use std::collections::HashMap; use std::error::Error; use std::fmt::Debug; use serde::{Deserialize, Serialize}; use serde::de::DeserializeOwned; use serde_flexitos::id::{Id, IdObj}; // Macro #[macro_export] macro_rules! create_registry { ($trait_object:ident, $register_macro:ident) => { create_registry!($trait_object, $register_macro, serde_flexitos::id::Ident<'static>, serde_flexitos::type_to_ident); }; ($trait_object:ident, $register_macro:ident, $ident:ty, $($type_to_ident:ident)::*) => { paste::paste! { create_registry!($trait_object, $register_macro, $ident, $($type_to_ident)::*, [<$trait_object:snake:upper _DESERIALIZE_REGISTRY>], [<$trait_object:snake:upper _DESERIALIZE_REGISTRY_DISTRIBUTED_SLICE>]); } }; ($trait_object:ident, $register_macro:ident, $ident:ty, $($type_to_ident:ident)::*, $registry:ident, $distributed_slice:ident) => { #[linkme::distributed_slice] pub static $distributed_slice: [fn(&mut serde_flexitos::MapRegistry)] = [..]; static $registry: std::sync::LazyLock> = std::sync::LazyLock::new(|| { let mut registry = serde_flexitos::MapRegistry::::new(stringify!($trait_object)); for registry_fn in $distributed_slice { registry_fn(&mut registry); } registry }); impl<'a> serde::Serialize for dyn $trait_object + 'a { #[inline] fn serialize(&self, serializer: S) -> Result { const fn __check_erased_serialize_supertrait() { serde_flexitos::ser::require_erased_serialize_impl::(); } serde_flexitos::serialize_trait_object(serializer, >::id(self), self) } } impl<'a, 'de> serde::Deserialize<'de> for Box { #[inline] fn deserialize>(deserializer: D) -> Result { use serde_flexitos::Registry; $registry.deserialize_trait_object(deserializer) } } #[macro_export] macro_rules! $register_macro { ($generic:ident<$arg:ty>) => { impl serde_flexitos::id::Id<$ident> for $generic<$arg> { const ID: $ident = $($type_to_ident)::*!($generic<$arg>); } impl Into> for $generic<$arg> where { #[inline] fn into(self) -> Box { Box::new(self) } } paste::paste! { #[linkme::distributed_slice($distributed_slice)] #[inline] fn [< __register_ $generic:snake _ $arg:snake >](registry: &mut serde_flexitos::MapRegistry) { use serde_flexitos::Registry; registry.register_id_type::<$generic<$arg>>(); } } }; ($concrete:ty) => { impl serde_flexitos::id::Id<$ident> for $concrete { const ID: $ident = $($type_to_ident)::*!($concrete); } impl Into> for $concrete where { #[inline] fn into(self) -> Box { Box::new(self) } } paste::paste! { #[linkme::distributed_slice($distributed_slice)] #[inline] fn [< __register_ $concrete:snake >](registry: &mut serde_flexitos::MapRegistry) { use serde_flexitos::Registry; registry.register_id_type::<$concrete>(); } } }; } }; } // Example trait /// Just an example trait, which can be (de)serialized, identified, and debug formatted. pub trait Example: Serialize + DeserializeOwned + Id + Debug {} /// Object safe proxy of [`Example`], because [`Serialize`], [`DeserializeOwned`], and [`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 + IdObj + Debug {} /// Implement [`ExampleObj`] for all types that implement [`Example`]. impl ExampleObj for T {} // Create `ExampleObj` registry, implement (de)serialize for `dyn ExampleObj`, and create `register_example!` macro. create_registry!(ExampleObj, register_example); // Test implementations #[derive(Clone, Serialize, Deserialize, Debug)] struct Foo(String); impl Example for Foo {} register_example!(Foo); #[derive(Clone, Serialize, Deserialize, Debug)] struct Bar(T); impl Example for Bar {} impl Example for Bar {} register_example!(Bar); // It even works with generic instantiations with a single type argument. register_example!(Bar); // Run serialization roundtrips fn main() -> Result<(), Box> { let foo = Foo("A".to_string()); { // 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(42))]; 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 with f32".to_string(), Box::new(Bar(42.1337))); examples.insert("bar with usize".to_string(), Box::new(Bar(1337))); let json = serde_json::to_string(&examples)?; println!("`HashMap>` serialized: {}", json); let roundtrip: HashMap::> = serde_json::from_str(&json)?; println!("`HashMap>` deserialized: {:?}", roundtrip); } Ok(()) }