nautilus_core/
serialization.rs1use bytes::Bytes;
19use serde::{
20 Deserializer,
21 de::{Unexpected, Visitor},
22};
23
24struct BoolVisitor;
25use serde::{Deserialize, Serialize};
26
27pub trait Serializable: Serialize + for<'de> Deserialize<'de> {
29 fn from_json_bytes(data: &[u8]) -> Result<Self, serde_json::Error> {
35 serde_json::from_slice(data)
36 }
37
38 fn from_msgpack_bytes(data: &[u8]) -> Result<Self, rmp_serde::decode::Error> {
44 rmp_serde::from_slice(data)
45 }
46
47 fn to_json_bytes(&self) -> Result<Bytes, serde_json::Error> {
53 serde_json::to_vec(self).map(Bytes::from)
54 }
55
56 fn to_msgpack_bytes(&self) -> Result<Bytes, rmp_serde::encode::Error> {
62 rmp_serde::to_vec_named(self).map(Bytes::from)
63 }
64}
65
66impl Visitor<'_> for BoolVisitor {
67 type Value = u8;
68
69 fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 formatter.write_str("a boolean as u8")
71 }
72
73 fn visit_bool<E>(self, value: bool) -> Result<Self::Value, E>
74 where
75 E: serde::de::Error,
76 {
77 Ok(u8::from(value))
78 }
79
80 #[allow(clippy::cast_possible_truncation)]
81 fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
82 where
83 E: serde::de::Error,
84 {
85 if value > 1 {
90 Err(E::invalid_value(Unexpected::Unsigned(value), &self))
91 } else {
92 Ok(value as u8)
93 }
94 }
95}
96
97pub fn from_bool_as_u8<'de, D>(deserializer: D) -> Result<u8, D::Error>
103where
104 D: Deserializer<'de>,
105{
106 deserializer.deserialize_any(BoolVisitor)
107}
108
109#[cfg(test)]
113mod tests {
114 use rstest::*;
115 use serde::{Deserialize, Serialize};
116
117 use super::{Serializable, from_bool_as_u8};
118
119 #[derive(Deserialize)]
120 pub struct TestStruct {
121 #[serde(deserialize_with = "from_bool_as_u8")]
122 pub value: u8,
123 }
124
125 #[rstest]
126 #[case(r#"{"value": true}"#, 1)]
127 #[case(r#"{"value": false}"#, 0)]
128 fn test_deserialize_bool_as_u8_with_boolean(#[case] json_str: &str, #[case] expected: u8) {
129 let test_struct: TestStruct = serde_json::from_str(json_str).unwrap();
130 assert_eq!(test_struct.value, expected);
131 }
132
133 #[rstest]
134 #[case(r#"{"value": 1}"#, 1)]
135 #[case(r#"{"value": 0}"#, 0)]
136 fn test_deserialize_bool_as_u8_with_u64(#[case] json_str: &str, #[case] expected: u8) {
137 let test_struct: TestStruct = serde_json::from_str(json_str).unwrap();
138 assert_eq!(test_struct.value, expected);
139 }
140
141 #[rstest]
142 fn test_deserialize_bool_as_u8_with_invalid_integer() {
143 let json = r#"{"value": 2}"#;
145 let result: Result<TestStruct, _> = serde_json::from_str(json);
146 assert!(result.is_err());
147 }
148
149 #[derive(Serialize, Deserialize, PartialEq, Debug)]
150 struct SerializableTestStruct {
151 id: u32,
152 name: String,
153 value: f64,
154 }
155
156 impl Serializable for SerializableTestStruct {}
157
158 #[rstest]
159 fn test_serializable_json_roundtrip() {
160 let original = SerializableTestStruct {
161 id: 42,
162 name: "test".to_string(),
163 value: std::f64::consts::PI,
164 };
165
166 let json_bytes = original.to_json_bytes().unwrap();
167 let deserialized = SerializableTestStruct::from_json_bytes(&json_bytes).unwrap();
168
169 assert_eq!(original, deserialized);
170 }
171
172 #[rstest]
173 fn test_serializable_msgpack_roundtrip() {
174 let original = SerializableTestStruct {
175 id: 123,
176 name: "msgpack_test".to_string(),
177 value: std::f64::consts::E,
178 };
179
180 let msgpack_bytes = original.to_msgpack_bytes().unwrap();
181 let deserialized = SerializableTestStruct::from_msgpack_bytes(&msgpack_bytes).unwrap();
182
183 assert_eq!(original, deserialized);
184 }
185
186 #[rstest]
187 fn test_serializable_json_invalid_data() {
188 let invalid_json = b"invalid json data";
189 let result = SerializableTestStruct::from_json_bytes(invalid_json);
190 assert!(result.is_err());
191 }
192
193 #[rstest]
194 fn test_serializable_msgpack_invalid_data() {
195 let invalid_msgpack = b"invalid msgpack data";
196 let result = SerializableTestStruct::from_msgpack_bytes(invalid_msgpack);
197 assert!(result.is_err());
198 }
199
200 #[rstest]
201 fn test_serializable_json_empty_values() {
202 let test_struct = SerializableTestStruct {
203 id: 0,
204 name: String::new(),
205 value: 0.0,
206 };
207
208 let json_bytes = test_struct.to_json_bytes().unwrap();
209 let deserialized = SerializableTestStruct::from_json_bytes(&json_bytes).unwrap();
210
211 assert_eq!(test_struct, deserialized);
212 }
213
214 #[rstest]
215 fn test_serializable_msgpack_empty_values() {
216 let test_struct = SerializableTestStruct {
217 id: 0,
218 name: String::new(),
219 value: 0.0,
220 };
221
222 let msgpack_bytes = test_struct.to_msgpack_bytes().unwrap();
223 let deserialized = SerializableTestStruct::from_msgpack_bytes(&msgpack_bytes).unwrap();
224
225 assert_eq!(test_struct, deserialized);
226 }
227}