1pub use bytes::Bytes;
7
8pub mod serde_helpers {
10 use bytes::Bytes;
11 use serde::{Deserialize, Deserializer, Serializer};
12
13 pub mod uuid_string {
15 use super::*;
16 use serde::Serialize;
17
18 pub fn serialize<S>(bytes: &Bytes, serializer: S) -> Result<S::Ok, S::Error>
19 where
20 S: Serializer,
21 {
22 if bytes.len() == 16 {
23 let mut uuid_bytes = [0u8; 16];
24 uuid_bytes.copy_from_slice(&bytes[..]);
25
26 let uuid_str = format!(
28 "{:02x}{:02x}{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}-{:02x}{:02x}{:02x}{:02x}{:02x}{:02x}",
29 uuid_bytes[0],
30 uuid_bytes[1],
31 uuid_bytes[2],
32 uuid_bytes[3],
33 uuid_bytes[4],
34 uuid_bytes[5],
35 uuid_bytes[6],
36 uuid_bytes[7],
37 uuid_bytes[8],
38 uuid_bytes[9],
39 uuid_bytes[10],
40 uuid_bytes[11],
41 uuid_bytes[12],
42 uuid_bytes[13],
43 uuid_bytes[14],
44 uuid_bytes[15]
45 );
46 uuid_str.serialize(serializer)
47 } else {
48 base64::Engine::encode(&base64::engine::general_purpose::STANDARD, bytes)
50 .serialize(serializer)
51 }
52 }
53
54 pub fn deserialize<'de, D>(deserializer: D) -> Result<Bytes, D::Error>
55 where
56 D: Deserializer<'de>,
57 {
58 use serde::de::Error;
59 let s = String::deserialize(deserializer)?;
60
61 let cleaned = s.replace("-", "");
63 if cleaned.len() == 32 {
64 let mut bytes = Vec::with_capacity(16);
66 for i in 0..16 {
67 let byte_str = &cleaned[i * 2..i * 2 + 2];
68 if let Ok(byte) = u8::from_str_radix(byte_str, 16) {
69 bytes.push(byte);
70 } else {
71 return Err(D::Error::custom("Invalid UUID hex"));
72 }
73 }
74 Ok(Bytes::from(bytes))
75 } else {
76 base64::Engine::decode(&base64::engine::general_purpose::STANDARD, s.as_bytes())
78 .map(Bytes::from)
79 .map_err(D::Error::custom)
80 }
81 }
82 }
83
84 pub mod payload_flexible {
86 use super::*;
87 use serde::Serialize;
88
89 pub fn serialize<S>(bytes: &Bytes, serializer: S) -> Result<S::Ok, S::Error>
90 where
91 S: Serializer,
92 {
93 if let Ok(s) = std::str::from_utf8(bytes) {
95 s.serialize(serializer)
97 } else {
98 base64::Engine::encode(&base64::engine::general_purpose::STANDARD, bytes)
100 .serialize(serializer)
101 }
102 }
103
104 pub fn deserialize<'de, D>(deserializer: D) -> Result<Bytes, D::Error>
105 where
106 D: Deserializer<'de>,
107 {
108 let s = String::deserialize(deserializer)?;
109
110 if let Ok(decoded) =
112 base64::Engine::decode(&base64::engine::general_purpose::STANDARD, s.as_bytes())
113 {
114 if decoded != s.as_bytes() {
116 return Ok(Bytes::from(decoded));
117 }
118 }
119
120 Ok(Bytes::from(s.into_bytes()))
122 }
123 }
124
125 pub mod bytes_base64 {
127 use super::*;
128
129 pub fn serialize<S>(bytes: &Bytes, serializer: S) -> Result<S::Ok, S::Error>
130 where
131 S: Serializer,
132 {
133 use serde::Serialize;
134 base64::Engine::encode(&base64::engine::general_purpose::STANDARD, bytes)
135 .serialize(serializer)
136 }
137
138 pub fn deserialize<'de, D>(deserializer: D) -> Result<Bytes, D::Error>
139 where
140 D: Deserializer<'de>,
141 {
142 use serde::de::Error;
143 let s = String::deserialize(deserializer)?;
144 base64::Engine::decode(&base64::engine::general_purpose::STANDARD, s.as_bytes())
145 .map(Bytes::from)
146 .map_err(D::Error::custom)
147 }
148 }
149}
150
151include!(concat!(env!("OUT_DIR"), "/synapse.rs"));
153
154#[cfg(test)]
155mod tests {
156 use super::serde_helpers::*;
157 use bytes::Bytes;
158
159 #[derive(serde::Serialize, serde::Deserialize, Debug)]
161 struct UuidWrapper {
162 #[serde(with = "uuid_string")]
163 id: Bytes,
164 }
165
166 #[derive(serde::Serialize, serde::Deserialize, Debug)]
167 struct PayloadWrapper {
168 #[serde(with = "payload_flexible")]
169 data: Bytes,
170 }
171
172 #[derive(serde::Serialize, serde::Deserialize, Debug)]
173 struct Base64Wrapper {
174 #[serde(with = "bytes_base64")]
175 data: Bytes,
176 }
177
178 #[test]
181 fn test_uuid_serialize_16_bytes() {
182 let bytes = Bytes::from(vec![
183 0x55, 0x0e, 0x84, 0x00, 0xe2, 0x9b, 0x41, 0xd4, 0xa7, 0x16, 0x44, 0x66, 0x55, 0x44,
184 0x00, 0x00,
185 ]);
186 let wrapper = UuidWrapper { id: bytes };
187 let json = serde_json::to_string(&wrapper).unwrap();
188 assert!(json.contains("550e8400-e29b-41d4-a716-446655440000"));
189 }
190
191 #[test]
192 fn test_uuid_roundtrip() {
193 let original = Bytes::from(vec![
194 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
195 0x0f, 0x10,
196 ]);
197 let wrapper = UuidWrapper {
198 id: original.clone(),
199 };
200 let json = serde_json::to_string(&wrapper).unwrap();
201 let decoded: UuidWrapper = serde_json::from_str(&json).unwrap();
202 assert_eq!(original, decoded.id);
203 }
204
205 #[test]
206 fn test_uuid_non_16_bytes_falls_back_to_base64() {
207 let bytes = Bytes::from(vec![0x01, 0x02, 0x03]); let wrapper = UuidWrapper { id: bytes };
209 let json = serde_json::to_string(&wrapper).unwrap();
210 assert!(!json.contains('-'));
212 }
213
214 #[test]
215 fn test_uuid_deserialize_with_hyphens() {
216 let json = r#"{"id":"550e8400-e29b-41d4-a716-446655440000"}"#;
217 let wrapper: UuidWrapper = serde_json::from_str(json).unwrap();
218 assert_eq!(wrapper.id.len(), 16);
219 assert_eq!(wrapper.id[0], 0x55);
220 assert_eq!(wrapper.id[15], 0x00);
221 }
222
223 #[test]
224 fn test_uuid_deserialize_without_hyphens() {
225 let json = r#"{"id":"550e8400e29b41d4a716446655440000"}"#;
226 let wrapper: UuidWrapper = serde_json::from_str(json).unwrap();
227 assert_eq!(wrapper.id.len(), 16);
228 assert_eq!(wrapper.id[0], 0x55);
229 }
230
231 #[test]
234 fn test_payload_utf8_serializes_as_string() {
235 let wrapper = PayloadWrapper {
236 data: Bytes::from("hello world"),
237 };
238 let json = serde_json::to_string(&wrapper).unwrap();
239 assert!(json.contains("hello world"));
240 }
241
242 #[test]
243 fn test_payload_binary_serializes_as_base64() {
244 let wrapper = PayloadWrapper {
245 data: Bytes::from(vec![0xFF, 0xFE, 0x00, 0x01]),
246 };
247 let json = serde_json::to_string(&wrapper).unwrap();
248 assert!(!json.contains('\u{ffff}'));
250 }
251
252 #[test]
253 fn test_payload_plain_text_roundtrip() {
254 let wrapper = PayloadWrapper {
256 data: Bytes::from("{\"key\":\"value\"}"),
257 };
258 let json = serde_json::to_string(&wrapper).unwrap();
259 let decoded: PayloadWrapper = serde_json::from_str(&json).unwrap();
260 assert_eq!(decoded.data, Bytes::from("{\"key\":\"value\"}"));
261 }
262
263 #[test]
266 fn test_base64_roundtrip() {
267 let original = Bytes::from(vec![0x00, 0xFF, 0x42, 0x13, 0x37]);
268 let wrapper = Base64Wrapper {
269 data: original.clone(),
270 };
271 let json = serde_json::to_string(&wrapper).unwrap();
272 let decoded: Base64Wrapper = serde_json::from_str(&json).unwrap();
273 assert_eq!(original, decoded.data);
274 }
275
276 #[test]
277 fn test_base64_invalid_input() {
278 let json = r#"{"data":"not valid base64!!@@"}"#;
279 let result: Result<Base64Wrapper, _> = serde_json::from_str(json);
280 assert!(result.is_err());
281 }
282}