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
129macro_rules! impl_serializable_for_numeric {
131 ($($type:ty),* $(,)?) => {
132 $(
133 impl Serializable for $type {
134 fn serialize(&self) -> Option<String> {
135 self.to_string().into()
136 }
137 }
138 )*
139 };
140}
141
142impl_serializable_for_numeric!(
144 i8, i16, i32, i64, i128, isize, u8, u16, u32, u64, u128, usize, f32, f64,
145);
146
147impl Serializable for () {
148 fn serialize(&self) -> Option<String> {
149 "null".to_string().into()
150 }
151}
152
153impl<T: Serializable> Serializable for Vec<T> {
154 fn serialize(&self) -> Option<String> {
155 let serialized_elements: Vec<String> = self.iter().filter_map(|e| e.serialize()).collect();
156 format!("[{}]", serialized_elements.join(",")).into()
157 }
158}
159
160impl<T: Serializable> Serializable for Option<T> {
161 fn serialize(&self) -> Option<String> {
162 self.as_ref().and_then(|value| value.serialize())
163 }
164}
165
166impl<T: Serializable> Serializable for HashMap<String, T> {
167 fn serialize(&self) -> Option<String> {
168 self.iter()
169 .fold(Serializer::builder(), |mut builder, (key, value)| {
170 builder.set(key, value);
171 builder
172 })
173 .build()
174 .into()
175 }
176}
177
178impl<T: Serializable> Serializable for indexmap::IndexMap<String, T> {
179 fn serialize(&self) -> Option<String> {
180 self.iter()
181 .fold(Serializer::builder(), |mut builder, (key, value)| {
182 builder.set(key, value);
183 builder
184 })
185 .build()
186 .into()
187 }
188}
189
190impl<T: Serializable> Serializable for Box<T> {
191 fn serialize(&self) -> Option<String> {
192 self.as_ref().serialize()
193 }
194
195 fn set_metadata(&mut self, metadata: MetadataSchema) {
196 self.as_mut().set_metadata(metadata)
197 }
198
199 fn set_nullable(&mut self, nullable: bool) {
200 self.as_mut().set_nullable(nullable)
201 }
202
203 fn set_rename(&mut self, new_name: &str) {
204 self.as_mut().set_rename(new_name)
205 }
206}
207
208impl Serializable for Box<dyn Serializable> {
209 fn serialize(&self) -> Option<String> {
210 self.as_ref().serialize()
211 }
212
213 fn set_metadata(&mut self, metadata: MetadataSchema) {
214 self.as_mut().set_metadata(metadata)
215 }
216
217 fn set_nullable(&mut self, nullable: bool) {
218 self.as_mut().set_nullable(nullable)
219 }
220
221 fn set_rename(&mut self, new_name: &str) {
222 self.as_mut().set_rename(new_name)
223 }
224}
225
226#[cfg(feature = "chrono")]
227impl Serializable for chrono::DateTime<chrono::FixedOffset> {
228 fn serialize(&self) -> Option<String> {
229 self.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)
230 .serialize()
231 }
232}
233
234#[cfg(feature = "chrono")]
235impl Serializable for chrono::DateTime<chrono::Utc> {
236 fn serialize(&self) -> Option<String> {
237 self.to_rfc3339_opts(chrono::SecondsFormat::Millis, true)
238 .serialize()
239 }
240}
241
242#[cfg(test)]
245mod tests {
246 use super::*;
247
248 #[derive(Clone)]
249 struct MockSerializable {
250 value: String,
251 }
252
253 impl Serializable for MockSerializable {
254 fn serialize(&self) -> Option<String> {
255 self.value.serialize()
256 }
257 }
258
259 #[test]
260 fn test_serialize() {
261 let mock = MockSerializable {
262 value: "test_value".to_string(),
263 };
264 assert_eq!(mock.serialize(), Some("\"test_value\"".to_string()));
265 }
266
267 #[test]
268 fn test_debug_trait() {
269 let mock = MockSerializable {
270 value: "debug_value".to_string(),
271 };
272 assert_eq!(
273 format!("{:?}", &mock as &dyn Serializable),
274 "\"debug_value\""
275 );
276 }
277
278 #[test]
279 fn test_partial_eq_trait() {
280 let mock1 = MockSerializable {
281 value: "value".to_string(),
282 };
283 let mock2 = MockSerializable {
284 value: "value".to_string(),
285 };
286 assert_eq!(&mock1 as &dyn Serializable, &mock2 as &dyn Serializable);
287 }
288
289 #[test]
290 fn test_serialize_str() {
291 let value = "Hello, world!";
292 assert_eq!(value.serialize(), Some("\"Hello, world!\"".to_string()));
293 }
294
295 #[test]
296 fn test_serialize_string() {
297 let value = "Hello, world!".to_string();
298 assert_eq!(value.serialize(), Some("\"Hello, world!\"".to_string()));
299 }
300
301 #[test]
302 fn test_serialize_vec() {
303 let vec = vec![
304 MockSerializable {
305 value: "value1".to_string(),
306 },
307 MockSerializable {
308 value: "value2".to_string(),
309 },
310 ];
311 let serialized: serde_json::Value =
312 serde_json::from_str(&vec.serialize().unwrap()).unwrap();
313
314 assert_eq!(serialized, serde_json::json!(["value1", "value2"]));
315 }
316
317 #[test]
318 fn test_serialize_option() {
319 let value = Some(MockSerializable {
320 value: "optional_value".to_string(),
321 });
322
323 let none_value: Option<MockSerializable> = None;
324
325 assert_eq!(value.serialize(), Some("\"optional_value\"".to_string()));
326 assert_eq!(none_value.serialize(), None);
327 }
328
329 #[test]
330 fn test_recursive_serialize_vec() {
331 let vec = vec![
332 MockSerializable {
333 value: "value1".to_string(),
334 },
335 MockSerializable {
336 value: "value2".to_string(),
337 },
338 ];
339
340 let serialized: serde_json::Value =
341 serde_json::from_str(&vec.serialize().unwrap()).unwrap();
342
343 assert_eq!(serialized, serde_json::json!(["value1", "value2"]));
344 }
345
346 #[test]
347 fn test_serialize_hashmap_basic() {
348 let mut hashmap: HashMap<String, String> = HashMap::new();
349 hashmap.insert("key1".to_string(), "value1".to_string());
350 hashmap.insert("key2".to_string(), "value2".to_string());
351
352 let serialized: serde_json::Value =
353 serde_json::from_str(&hashmap.serialize().unwrap()).unwrap();
354
355 assert_eq!(
356 serialized,
357 serde_json::json!({
358 "key1": "value1",
359 "key2": "value2"
360 })
361 );
362 }
363
364 #[test]
365 fn test_serialize_hashmap_partial_recursion() {
366 let hashmap = HashMap::from([
367 (
368 "value1".to_string(),
369 MockSerializable {
370 value: "nested_value1".to_string(),
371 },
372 ),
373 (
374 "value2".to_string(),
375 MockSerializable {
376 value: "nested_value2".to_string(),
377 },
378 ),
379 ]);
380
381 let serialized: serde_json::Value =
382 serde_json::from_str(&hashmap.serialize().unwrap()).unwrap();
383
384 assert_eq!(
385 serialized,
386 serde_json::json!({
387 "value1": "nested_value1",
388 "value2": "nested_value2"
389 })
390 );
391 }
392
393 #[test]
394 fn test_serialize_hashmap_recursion() {
395 let mut hashmap: HashMap<String, HashMap<String, MockSerializable>> = HashMap::new();
396 hashmap.insert(
397 "key1".to_string(),
398 HashMap::from([(
399 "value1".to_string(),
400 MockSerializable {
401 value: "nested_value1".to_string(),
402 },
403 )]),
404 );
405 hashmap.insert(
406 "key2".to_string(),
407 HashMap::from([(
408 "value2".to_string(),
409 MockSerializable {
410 value: "nested_value2".to_string(),
411 },
412 )]),
413 );
414
415 let serialized: serde_json::Value =
416 serde_json::from_str(&hashmap.serialize().unwrap()).unwrap();
417
418 assert_eq!(
419 serialized,
420 serde_json::json!({
421 "key1": {
422 "value1": "nested_value1"
423 },
424 "key2": {
425 "value2": "nested_value2"
426 }
427 })
428 );
429 }
430
431 #[test]
432 fn test_serialize_box() {
433 let boxed_value = Box::new(MockSerializable {
434 value: "boxed_value".to_string(),
435 });
436 assert_eq!(boxed_value.serialize(), Some("\"boxed_value\"".to_string()));
437 }
438
439 #[test]
440 fn test_serialize_box_dyn() {
441 let boxed_value: Box<dyn Serializable> = Box::new(MockSerializable {
442 value: "boxed_dyn_value".to_string(),
443 });
444 assert_eq!(
445 boxed_value.serialize(),
446 Some("\"boxed_dyn_value\"".to_string())
447 );
448 }
449
450 #[cfg(feature = "chrono")]
451 #[test]
452 fn test_serialize_chrono_fixed_offset() {
453 use chrono::{DateTime, FixedOffset};
454
455 let datetime =
456 DateTime::<FixedOffset>::parse_from_rfc3339("1985-04-12T23:20:50.520Z").unwrap();
457
458 assert_eq!(
459 datetime.serialize(),
460 Some("\"1985-04-12T23:20:50.520Z\"".to_string())
461 );
462 }
463
464 #[cfg(feature = "chrono")]
465 #[test]
466 fn test_serialize_chrono_utc() {
467 use chrono::{DateTime, FixedOffset, Utc};
468 let datetime =
469 DateTime::<FixedOffset>::parse_from_rfc3339("1985-04-12T23:20:50.520Z").unwrap();
470 let datetime_utc = datetime.with_timezone(&Utc);
471
472 assert_eq!(
473 datetime_utc.serialize(),
474 Some("\"1985-04-12T23:20:50.520Z\"".to_string())
475 );
476 }
477}