1use std::{any::type_name, collections::HashMap, fmt::Debug};
3
4use downcast_rs::{Downcast, impl_downcast};
5
6use crate::{MetadataSchema, serializer::Serializer};
7
8fn do_panic<T>(message: impl std::fmt::Display, serialized: impl Debug, value: impl Debug) -> !
22where
23 T: ?Sized,
24{
25 panic!(
26 "{}!\n\
27 This is a bug, please report it @ <https://github.com/Arthurdw/ronky/issues>\n\
28 Type: {:?}\n\
29 Serialized: {:?}\n\
30 Value: {:?}",
31 message,
32 type_name::<T>(),
33 serialized,
34 value
35 );
36}
37
38pub trait Serializable: Downcast {
43 fn serialize(&self) -> Option<String>;
48
49 fn set_metadata(&mut self, metadata: MetadataSchema) {
57 do_panic::<Self>(
58 "set_metadata is not implemented for this type",
59 self.serialize(),
60 metadata,
61 );
62 }
63
64 fn set_nullable(&mut self, nullable: bool) {
72 do_panic::<Self>(
73 "set_nullable is not implemented for this type",
74 self.serialize(),
75 nullable,
76 );
77 }
78
79 fn set_rename(&mut self, new_name: &str) {
87 do_panic::<Self>(
88 "set_rename is not implemented for this type",
89 self.serialize(),
90 new_name,
91 );
92 }
93}
94
95impl_downcast!(Serializable);
96
97impl Debug for dyn Serializable {
98 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99 write!(f, "{}", self.serialize().unwrap_or("undefined".to_string()))
100 }
101}
102
103impl PartialEq for dyn Serializable {
104 fn eq(&self, other: &Self) -> bool {
105 self.serialize() == other.serialize()
106 }
107}
108
109impl Eq for dyn Serializable {}
110
111impl Serializable for &'static str {
112 fn serialize(&self) -> Option<String> {
113 format!("\"{}\"", self).into()
114 }
115}
116
117impl Serializable for String {
118 fn serialize(&self) -> Option<String> {
119 format!("\"{}\"", self).into()
120 }
121}
122
123impl Serializable for bool {
124 fn serialize(&self) -> Option<String> {
125 self.to_string().into()
126 }
127}
128
129impl Serializable for () {
130 fn serialize(&self) -> Option<String> {
131 "null".to_string().into()
132 }
133}
134
135impl<T: Serializable> Serializable for Vec<T> {
136 fn serialize(&self) -> Option<String> {
137 let serialized_elements: Vec<String> = self.iter().filter_map(|e| e.serialize()).collect();
138 format!("[{}]", serialized_elements.join(",")).into()
139 }
140}
141
142impl<T: Serializable> Serializable for Option<T> {
143 fn serialize(&self) -> Option<String> {
144 self.as_ref().and_then(|value| value.serialize())
145 }
146}
147
148impl<T: Serializable> Serializable for HashMap<String, T> {
149 fn serialize(&self) -> Option<String> {
150 self.iter()
151 .fold(Serializer::builder(), |mut builder, (key, value)| {
152 builder.set(key, value);
153 builder
154 })
155 .build()
156 .into()
157 }
158}
159
160impl<T: Serializable> Serializable for Box<T> {
161 fn serialize(&self) -> Option<String> {
162 self.as_ref().serialize()
163 }
164
165 fn set_metadata(&mut self, metadata: MetadataSchema) {
166 self.as_mut().set_metadata(metadata)
167 }
168
169 fn set_nullable(&mut self, nullable: bool) {
170 self.as_mut().set_nullable(nullable)
171 }
172
173 fn set_rename(&mut self, new_name: &str) {
174 self.as_mut().set_rename(new_name)
175 }
176}
177
178impl Serializable for Box<dyn Serializable> {
179 fn serialize(&self) -> Option<String> {
180 self.as_ref().serialize()
181 }
182
183 fn set_metadata(&mut self, metadata: MetadataSchema) {
184 self.as_mut().set_metadata(metadata)
185 }
186
187 fn set_nullable(&mut self, nullable: bool) {
188 self.as_mut().set_nullable(nullable)
189 }
190
191 fn set_rename(&mut self, new_name: &str) {
192 self.as_mut().set_rename(new_name)
193 }
194}
195
196#[cfg(feature = "chrono")]
197impl Serializable for chrono::DateTime<chrono::FixedOffset> {
198 fn serialize(&self) -> Option<String> {
199 self.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)
200 .serialize()
201 }
202}
203
204#[cfg(feature = "chrono")]
205impl Serializable for chrono::DateTime<chrono::Utc> {
206 fn serialize(&self) -> Option<String> {
207 self.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)
208 .serialize()
209 }
210}
211
212#[cfg(test)]
215mod tests {
216 use super::*;
217
218 #[derive(Clone)]
219 struct MockSerializable {
220 value: String,
221 }
222
223 impl Serializable for MockSerializable {
224 fn serialize(&self) -> Option<String> {
225 self.value.serialize()
226 }
227 }
228
229 #[test]
230 fn test_serialize() {
231 let mock = MockSerializable {
232 value: "test_value".to_string(),
233 };
234 assert_eq!(mock.serialize(), Some("\"test_value\"".to_string()));
235 }
236
237 #[test]
238 fn test_debug_trait() {
239 let mock = MockSerializable {
240 value: "debug_value".to_string(),
241 };
242 assert_eq!(
243 format!("{:?}", &mock as &dyn Serializable),
244 "\"debug_value\""
245 );
246 }
247
248 #[test]
249 fn test_partial_eq_trait() {
250 let mock1 = MockSerializable {
251 value: "value".to_string(),
252 };
253 let mock2 = MockSerializable {
254 value: "value".to_string(),
255 };
256 assert_eq!(&mock1 as &dyn Serializable, &mock2 as &dyn Serializable);
257 }
258
259 #[test]
260 fn test_serialize_str() {
261 let value = "Hello, world!";
262 assert_eq!(value.serialize(), Some("\"Hello, world!\"".to_string()));
263 }
264
265 #[test]
266 fn test_serialize_string() {
267 let value = "Hello, world!".to_string();
268 assert_eq!(value.serialize(), Some("\"Hello, world!\"".to_string()));
269 }
270
271 #[test]
272 fn test_serialize_vec() {
273 let vec = vec![
274 MockSerializable {
275 value: "value1".to_string(),
276 },
277 MockSerializable {
278 value: "value2".to_string(),
279 },
280 ];
281 let serialized: serde_json::Value =
282 serde_json::from_str(&vec.serialize().unwrap()).unwrap();
283
284 assert_eq!(serialized, serde_json::json!(["value1", "value2"]));
285 }
286
287 #[test]
288 fn test_serialize_option() {
289 let value = Some(MockSerializable {
290 value: "optional_value".to_string(),
291 });
292
293 let none_value: Option<MockSerializable> = None;
294
295 assert_eq!(value.serialize(), Some("\"optional_value\"".to_string()));
296 assert_eq!(none_value.serialize(), None);
297 }
298
299 #[test]
300 fn test_recursive_serialize_vec() {
301 let vec = vec![
302 MockSerializable {
303 value: "value1".to_string(),
304 },
305 MockSerializable {
306 value: "value2".to_string(),
307 },
308 ];
309
310 let serialized: serde_json::Value =
311 serde_json::from_str(&vec.serialize().unwrap()).unwrap();
312
313 assert_eq!(serialized, serde_json::json!(["value1", "value2"]));
314 }
315
316 #[test]
317 fn test_serialize_hashmap_basic() {
318 let mut hashmap: HashMap<String, String> = HashMap::new();
319 hashmap.insert("key1".to_string(), "value1".to_string());
320 hashmap.insert("key2".to_string(), "value2".to_string());
321
322 let serialized: serde_json::Value =
323 serde_json::from_str(&hashmap.serialize().unwrap()).unwrap();
324
325 assert_eq!(
326 serialized,
327 serde_json::json!({
328 "key1": "value1",
329 "key2": "value2"
330 })
331 );
332 }
333
334 #[test]
335 fn test_serialize_hashmap_partial_recursion() {
336 let hashmap = HashMap::from([
337 (
338 "value1".to_string(),
339 MockSerializable {
340 value: "nested_value1".to_string(),
341 },
342 ),
343 (
344 "value2".to_string(),
345 MockSerializable {
346 value: "nested_value2".to_string(),
347 },
348 ),
349 ]);
350
351 let serialized: serde_json::Value =
352 serde_json::from_str(&hashmap.serialize().unwrap()).unwrap();
353
354 assert_eq!(
355 serialized,
356 serde_json::json!({
357 "value1": "nested_value1",
358 "value2": "nested_value2"
359 })
360 );
361 }
362
363 #[test]
364 fn test_serialize_hashmap_recursion() {
365 let mut hashmap: HashMap<String, HashMap<String, MockSerializable>> = HashMap::new();
366 hashmap.insert(
367 "key1".to_string(),
368 HashMap::from([(
369 "value1".to_string(),
370 MockSerializable {
371 value: "nested_value1".to_string(),
372 },
373 )]),
374 );
375 hashmap.insert(
376 "key2".to_string(),
377 HashMap::from([(
378 "value2".to_string(),
379 MockSerializable {
380 value: "nested_value2".to_string(),
381 },
382 )]),
383 );
384
385 let serialized: serde_json::Value =
386 serde_json::from_str(&hashmap.serialize().unwrap()).unwrap();
387
388 assert_eq!(
389 serialized,
390 serde_json::json!({
391 "key1": {
392 "value1": "nested_value1"
393 },
394 "key2": {
395 "value2": "nested_value2"
396 }
397 })
398 );
399 }
400
401 #[test]
402 fn test_serialize_box() {
403 let boxed_value = Box::new(MockSerializable {
404 value: "boxed_value".to_string(),
405 });
406 assert_eq!(boxed_value.serialize(), Some("\"boxed_value\"".to_string()));
407 }
408
409 #[test]
410 fn test_serialize_box_dyn() {
411 let boxed_value: Box<dyn Serializable> = Box::new(MockSerializable {
412 value: "boxed_dyn_value".to_string(),
413 });
414 assert_eq!(
415 boxed_value.serialize(),
416 Some("\"boxed_dyn_value\"".to_string())
417 );
418 }
419
420 #[cfg(feature = "chrono")]
421 #[test]
422 fn test_serialize_chrono_fixed_offset() {
423 use chrono::{DateTime, FixedOffset};
424
425 let datetime =
426 DateTime::<FixedOffset>::parse_from_rfc3339("1985-04-12T23:20:50.520Z").unwrap();
427
428 assert_eq!(
429 datetime.serialize(),
430 Some("\"1985-04-12T23:20:50.520Z\"".to_string())
431 );
432 }
433
434 #[cfg(feature = "chrono")]
435 #[test]
436 fn test_serialize_chrono_utc() {
437 use chrono::{DateTime, FixedOffset, Utc};
438 let datetime =
439 DateTime::<FixedOffset>::parse_from_rfc3339("1985-04-12T23:20:50.520Z").unwrap();
440 let datetime_utc = datetime.with_timezone(&Utc);
441
442 assert_eq!(
443 datetime_utc.serialize(),
444 Some("\"1985-04-12T23:20:50.520Z\"".to_string())
445 );
446 }
447}