use serde::{Deserialize, Deserializer, Serialize, Serializer}; use std::error::Error; use std::fmt::Debug; use std::sync::LazyLock; use serde_flexitos::ser::require_erased_serialize_impl; use serde_flexitos::{serialize_trait_object, MapRegistry, Registry}; // Example traits pub trait Example1Obj: erased_serde::Serialize + Debug { fn id(&self) -> &'static str; } pub trait Example2Obj: erased_serde::Serialize + Debug { fn id(&self) -> &'static str; } // Example trait implementations #[derive(Clone, Serialize, Deserialize, Debug)] struct Foo(String); impl Foo { const ID: &'static str = "Foo"; } impl Example1Obj for Foo { fn id(&self) -> &'static str { Self::ID } } impl Example2Obj for Foo { fn id(&self) -> &'static str { Self::ID } } #[derive(Clone, Serialize, Deserialize, Debug)] struct Bar(usize); impl Bar { const ID: &'static str = "Bar"; } impl Example1Obj for Bar { fn id(&self) -> &'static str { Self::ID } } impl Example2Obj for Bar { fn id(&self) -> &'static str { Self::ID } } // Registries static EXAMPLE_1_OBJ_REGISTRY: LazyLock> = LazyLock::new(|| { let mut registry = MapRegistry::::new("Example1Obj"); registry.register(Foo::ID, |d| Ok(Box::new(erased_serde::deserialize::(d)?))); registry.register(Bar::ID, |d| Ok(Box::new(erased_serde::deserialize::(d)?))); registry }); static EXAMPLE_2_OBJ_REGISTRY: LazyLock> = LazyLock::new(|| { let mut registry = MapRegistry::::new("Example2Obj"); registry.register(Foo::ID, |d| Ok(Box::new(erased_serde::deserialize::(d)?))); registry.register(Bar::ID, |d| Ok(Box::new(erased_serde::deserialize::(d)?))); registry }); // (De)serialize implementations impl<'a> Serialize for dyn Example1Obj + 'a { fn serialize(&self, serializer: S) -> Result { const fn __check_erased_serialize_supertrait() { require_erased_serialize_impl::(); } serialize_trait_object(serializer, self.id(), self) } } impl<'de> Deserialize<'de> for Box { fn deserialize>(deserializer: D) -> Result { EXAMPLE_1_OBJ_REGISTRY.deserialize_trait_object(deserializer) } } impl<'a> Serialize for dyn Example2Obj + 'a { fn serialize(&self, serializer: S) -> Result { const fn __check_erased_serialize_supertrait() { require_erased_serialize_impl::(); } serialize_trait_object(serializer, self.id(), self) } } impl<'de> Deserialize<'de> for Box { fn deserialize>(deserializer: D) -> Result { EXAMPLE_2_OBJ_REGISTRY.deserialize_trait_object(deserializer) } } // Struct with boxed trait objects, with derived `Serialize` and `Deserialize` implementations. #[derive(Debug, Serialize, Deserialize)] struct Combined { example_1_obj: Box, example_2_obj: Box, } impl Combined { pub fn new(example_1_obj: impl Example1Obj + 'static, example_2_obj: impl Example2Obj + 'static) -> Self { Self { example_1_obj: Box::new(example_1_obj), example_2_obj: Box::new(example_2_obj) } } } // Run serialization roundtrips fn main() -> Result<(), Box> { { let json = serde_json::to_string(&Combined::new(Foo("A".to_string()), Bar(0)))?; println!("`Combined` serialized: {}", json); let roundtrip: Combined = serde_json::from_str(&json)?; println!("`Combined` deserialized: {:?}", roundtrip); } { let json = serde_json::to_string(&Combined::new(Bar(1337), Foo("asd".to_string())))?; println!("`Combined` serialized: {}", json); let roundtrip: Combined = serde_json::from_str(&json)?; println!("`Combined` deserialized: {:?}", roundtrip); } Ok(()) }