use crate::util::AnyValueId; use crate::util::FlatMap; #[derive(Default, Clone, Debug)] pub(crate) struct Extensions { extensions: FlatMap, } impl Extensions { #[allow(dead_code)] pub(crate) fn get(&self) -> Option<&T> { let id = AnyValueId::of::(); self.extensions.get(&id).map(|e| e.as_ref::()) } #[allow(dead_code)] pub(crate) fn get_mut(&mut self) -> Option<&mut T> { let id = AnyValueId::of::(); self.extensions.get_mut(&id).map(|e| e.as_mut::()) } #[allow(dead_code)] pub(crate) fn get_or_insert_default(&mut self) -> &mut T { let id = AnyValueId::of::(); self.extensions .entry(id) .or_insert_with(|| BoxedExtension::new(T::default())) .as_mut::() } #[allow(dead_code)] pub(crate) fn set>(&mut self, tagged: T) -> bool { let BoxedEntry { id, value } = tagged.into(); self.extensions.insert(id, value).is_some() } #[allow(dead_code)] pub(crate) fn remove(&mut self) -> Option> { let id = AnyValueId::of::(); self.extensions.remove(&id).map(BoxedExtension::into_inner) } pub(crate) fn update(&mut self, other: &Self) { for (key, value) in other.extensions.iter() { self.extensions.insert(*key, value.clone()); } } } /// Supports conversion to `Any`. Traits to be extended by `impl_downcast!` must extend `Extension`. pub(crate) trait Extension: std::fmt::Debug + Send + Sync + 'static { /// Convert `Box` (where `Trait: Extension`) to `Box`. /// /// `Box` can /// then be further `downcast` into /// `Box` where `ConcreteType` implements `Trait`. fn into_any(self: Box) -> Box; /// Clone `&Box` (where `Trait: Extension`) to `Box`. /// /// `Box` can /// then be further `downcast` into // `Box` where `ConcreteType` implements `Trait`. fn clone_extension(&self) -> Box; /// Convert `&Trait` (where `Trait: Extension`) to `&Any`. /// /// This is needed since Rust cannot /// generate `&Any`'s vtable from /// `&Trait`'s. fn as_any(&self) -> &dyn std::any::Any; /// Convert `&mut Trait` (where `Trait: Extension`) to `&Any`. /// /// This is needed since Rust cannot /// generate `&mut Any`'s vtable from /// `&mut Trait`'s. fn as_any_mut(&mut self) -> &mut dyn std::any::Any; } impl Extension for T where T: Clone + std::fmt::Debug + Send + Sync + 'static, { fn into_any(self: Box) -> Box { self } fn clone_extension(&self) -> Box { Box::new(self.clone()) } fn as_any(&self) -> &dyn std::any::Any { self } fn as_any_mut(&mut self) -> &mut dyn std::any::Any { self } } impl Clone for Box { fn clone(&self) -> Self { self.as_ref().clone_extension() } } #[derive(Clone)] #[repr(transparent)] struct BoxedExtension(Box); impl BoxedExtension { fn new(inner: T) -> Self { Self(Box::new(inner)) } fn into_inner(self) -> Box { self.0 } fn as_ref(&self) -> &T { self.0.as_ref().as_any().downcast_ref::().unwrap() } fn as_mut(&mut self) -> &mut T { self.0.as_mut().as_any_mut().downcast_mut::().unwrap() } } impl std::fmt::Debug for BoxedExtension { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { self.0.fmt(f) } } #[derive(Clone)] pub(crate) struct BoxedEntry { id: AnyValueId, value: BoxedExtension, } impl BoxedEntry { pub(crate) fn new(r: impl Extension) -> Self { let id = AnyValueId::from(&r); let value = BoxedExtension::new(r); BoxedEntry { id, value } } } impl From for BoxedEntry { fn from(inner: R) -> Self { BoxedEntry::new(inner) } } #[cfg(test)] mod test { use super::*; #[derive(Default, Copy, Clone, Debug, PartialEq, Eq)] struct Number(usize); #[test] fn get() { let mut ext = Extensions::default(); ext.set(Number(10)); assert_eq!(ext.get::(), Some(&Number(10))); } #[test] fn get_mut() { let mut ext = Extensions::default(); ext.set(Number(10)); *ext.get_mut::().unwrap() = Number(20); assert_eq!(ext.get::(), Some(&Number(20))); } #[test] fn get_or_insert_default_empty() { let mut ext = Extensions::default(); assert_eq!(ext.get_or_insert_default::(), &Number(0)); } #[test] fn get_or_insert_default_full() { let mut ext = Extensions::default(); ext.set(Number(10)); assert_eq!(ext.get_or_insert_default::(), &Number(10)); } #[test] fn set() { let mut ext = Extensions::default(); assert!(!ext.set(Number(10))); assert_eq!(ext.get::(), Some(&Number(10))); assert!(ext.set(Number(20))); assert_eq!(ext.get::(), Some(&Number(20))); } #[test] fn reset() { let mut ext = Extensions::default(); assert_eq!(ext.get::(), None); assert!(ext.remove::().is_none()); assert_eq!(ext.get::(), None); assert!(!ext.set(Number(10))); assert_eq!(ext.get::(), Some(&Number(10))); assert!(ext.remove::().is_some()); assert_eq!(ext.get::(), None); } #[test] fn update() { let mut ext = Extensions::default(); assert_eq!(ext.get::(), None); let mut new = Extensions::default(); assert!(!new.set(Number(10))); ext.update(&new); assert_eq!(ext.get::(), Some(&Number(10))); } }