use std::collections::HashMap; use std::error::Error; use std::fmt::Debug; use std::sync::LazyLock; use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde::de::DeserializeOwned; use serde_flexitos::{MapRegistry, Registry, serialize_trait_object}; use serde_flexitos::ser::require_erased_serialize_impl; // Example traits /// Just an example trait, which can be (de)serialized, identified, and debug formatted. pub trait Example: Serialize + DeserializeOwned + Debug { /// The unique and stable identifier of this type. const ID: &'static str; } /// Object safe proxy of [`Example`], because [`Serialize`], [`DeserializeOwned`], and [`Example::ID`] are not /// object safe. If your trait is already object safe, you don't need a separate object safe proxy. pub trait ExampleObj: erased_serde::Serialize + Debug { /// Gets the unique and stable identifier for the concrete type of this value. This is a method instead of a function /// because this trait must be object-safe; traits with associated functions are not object-safe. fn id(&self) -> &'static str; } /// Implement [`ExampleObj`] for all types that implement [`Example`]. impl ExampleObj for T { fn id(&self) -> &'static str { T::ID } } // Example trait implementations #[derive(Clone, Serialize, Deserialize, Debug)] struct Foo(String); impl Example for Foo { const ID: &'static str = "Foo"; } #[derive(Clone, Serialize, Deserialize, Debug)] struct Bar(usize); impl Example for Bar { const ID: &'static str = "Bar"; } // Registry static EXAMPLE_OBJ_REGISTRY: LazyLock> = LazyLock::new(|| { let mut registry = MapRegistry::::new("ExampleObj"); 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 ExampleObj + 'a { fn serialize(&self, serializer: S) -> Result where S: Serializer { // Check that `ExampleObj` has `erased_serde::Serialize` as a supertrait, preventing infinite recursion at runtime. 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 where D: Deserializer<'de> { EXAMPLE_OBJ_REGISTRY.deserialize_trait_object(deserializer) } } // Run serialization roundtrips fn main() -> Result<(), Box> { let foo = Foo("A".to_string()); let bar = Bar(0); { // Normal serialization roundtrip let json = serde_json::to_string(&foo)?; println!("`Foo` serialized: {}", json); let roundtrip: Foo = serde_json::from_str(&json)?; println!("`Foo` deserialized: {:?}", roundtrip); } { // `Box` serialization roundtrip let example: Box = Box::new(foo.clone()); let json = serde_json::to_string(&example)?; println!("`Box` serialized: {}", json); let roundtrip: Box = serde_json::from_str(&json)?; println!("`Box` deserialized: {:?}", roundtrip); } { // `Vec>` serialization roundtrip let examples: Vec> = vec![Box::new(foo.clone()), Box::new(bar.clone())]; let json = serde_json::to_string(&examples)?; println!("`Vec>` serialized: {}", json); let roundtrip: Vec> = serde_json::from_str(&json)?; println!("`Vec>` deserialized: {:?}", roundtrip); } { // `HashMap>` serialization roundtrip let mut examples = HashMap::>::new(); examples.insert("foo".to_string(), Box::new(foo.clone())); examples.insert("bar".to_string(), Box::new(bar.clone())); let json = serde_json::to_string(&examples)?; println!("`HashMap>` serialized: {}", json); let roundtrip: HashMap::> = serde_json::from_str(&json)?; println!("`HashMap>` deserialized: {:?}", roundtrip); } Ok(()) }