use serde::{Deserialize, Deserializer, Serialize, Serializer}; use serde_flexitos::ser::require_erased_serialize_impl; #[allow(unused_imports)] use serde_flexitos::MapRegistry; use serde_flexitos::{serialize_trait_object, DeserializeFn, GetError, Registry}; use std::collections::BTreeMap; use std::error::Error; use std::fmt::Debug; use std::sync::LazyLock; // Custom registry implementation /// [Registry] implementation mapping unique identifiers of type `I` to deserialize functions of trait object type `O`, /// using a [BTreeMap]. /// /// Multiple registrations for the same identifier are ignored. The first deserialize function registered for that /// identifier is returned instead. /// /// Only use this registry implementation when you are sure that you want to ignore multiple registrations for the same /// identifiers without errors, for example when you know that these registrations are pure duplicates: the exact same /// deserialize function is registered multiple times for the same identifier. /// /// Do *not* use this implementation with global static registration mechanisms such as [linkme] or [inventory], as /// there is no guarantee about the order in which registrations are performed. This could lead to subtle bugs where /// changing an unrelated part of the program changes the deserialization function! pub struct FirstMapRegistry { deserialize_fns: BTreeMap>, trait_object_name: &'static str, } impl FirstMapRegistry { /// Creates a new registry, using `trait_object_name` as the name of `O` for diagnostic purposes. #[inline] pub fn new(trait_object_name: &'static str) -> Self { Self { deserialize_fns: BTreeMap::new(), trait_object_name, } } } impl Registry for FirstMapRegistry { type Identifier = I; type TraitObject = O; #[inline] fn register(&mut self, id: Self::Identifier, deserialize_fn: DeserializeFn) { self.deserialize_fns.entry(id).or_insert(deserialize_fn); } #[inline] fn get_deserialize_fn(&self, id: Self::Identifier) -> Result<&DeserializeFn, GetError> { self.deserialize_fns.get(&id).ok_or_else(|| GetError::NotRegistered { id }) } #[inline] fn get_trait_object_name(&self) -> &'static str { self.trait_object_name } } // Example trait pub trait ExampleObj: erased_serde::Serialize + Debug { fn id(&self) -> &'static str; } // Example trait implementation #[derive(Clone, Serialize, Deserialize, Debug)] struct Foo(String); impl Foo { const ID: &'static str = "Foo"; } impl ExampleObj for Foo { fn id(&self) -> &'static str { Self::ID } } // Registry static EXAMPLE_OBJ_REGISTRY: LazyLock> = LazyLock::new(|| { // Use our custom `FirstMapRegistry` here. let mut registry = FirstMapRegistry::::new("ExampleObj"); registry.register(Foo::ID, |d| Ok(Box::new(erased_serde::deserialize::(d)?))); // Register `Foo` again, but this will be ignored by our `FirstMapRegistry` implementation. This is fine because we // registered `Foo` again with the same deserialize function. registry.register(Foo::ID, |d| Ok(Box::new(erased_serde::deserialize::(d)?))); registry }); // (De)serialize implementation impl<'a> Serialize for dyn ExampleObj + '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_OBJ_REGISTRY.deserialize_trait_object(deserializer) } } // Run serialization roundtrips fn main() -> Result<(), Box> { // `Box` serialization roundtrip let example: Box = Box::new(Foo("A".to_string())); let json = serde_json::to_string(&example)?; println!("`Box` serialized: {}", json); let roundtrip: Box = serde_json::from_str(&json)?; println!("`Box` deserialized: {:?}", roundtrip); // If you change `FirstMapRegistry` to `MapRegistry` above, deserialization fails "multiple registrations" error. Ok(()) }