Skip to main content
Glama
lib.rs10.8 kB
//! A concurrent type map for used for caching and protocol extensions. // Based on `Extensions` from the `http` create, released under the Apache v2 and MIT licenses // // Source: // https://github.com/hyperium/http/blob/63102bcd29fcd4a094cac6a4afb0af370ef1fcbe/src/extensions.rs use std::{ any::{ Any, TypeId, }, fmt, hash::{ BuildHasherDefault, Hasher, }, }; use dashmap::{ DashMap, mapref::one::{ MappedRef, MappedRefMut, }, }; type Key = TypeId; type Value = Box<dyn AnyClone + Send + Sync>; type AnyMap = DashMap<Key, Value, BuildHasherDefault<IdHasher>>; // With TypeIds as keys, there's no need to hash them. They are already hashes themselves, coming // from the compiler. The IdHasher just holds the u64 of the TypeId, and then returns it, instead // of doing any bit fiddling. #[derive(Default)] struct IdHasher(u64); impl Hasher for IdHasher { fn write(&mut self, _: &[u8]) { unreachable!("TypeId calls write_u64"); } #[inline] fn write_u64(&mut self, id: u64) { self.0 = id; } #[inline] fn finish(&self) -> u64 { self.0 } } /// A concurrent type map used for caching and protocol extensions. #[derive(Clone, Default)] pub struct ConcurrentExtensions { map: Box<AnyMap>, } impl ConcurrentExtensions { /// Creates an empty `ConcurrentExtensions`. #[inline] pub fn new() -> ConcurrentExtensions { ConcurrentExtensions { map: Box::default(), } } /// Inserts a type into the map. /// /// If a extension of this type already existed, it will be returned. /// /// # Example /// /// ``` /// # use concurrent_extensions::ConcurrentExtensions; /// let mut ext = ConcurrentExtensions::new(); /// assert!(ext.insert(5i32).is_none()); /// assert!(ext.insert(4u8).is_none()); /// assert_eq!(ext.insert(9i32), Some(5i32)); /// ``` pub fn insert<T: Clone + Send + Sync + 'static>(&self, val: T) -> Option<T> { self.map .insert(TypeId::of::<T>(), Box::new(val)) .and_then(|boxed| boxed.into_any().downcast().ok().map(|boxed| *boxed)) } /// Gets a reference to a type previously inserted in the map. /// /// # Example /// /// ``` /// # use concurrent_extensions::ConcurrentExtensions; /// let mut ext = ConcurrentExtensions::new(); /// assert!(ext.get::<i32>().is_none()); /// ext.insert(5i32); /// /// assert_eq!(ext.get::<i32>().as_deref(), Some(&5i32)); /// ``` pub fn get<T: Send + Sync + 'static>(&self) -> Option<MappedRef<'_, Key, Value, T>> { self.map.get(&TypeId::of::<T>()).map(|dm_ref| { dm_ref.map(|boxed| (**boxed).as_any().downcast_ref().expect("type should be T")) }) } /// Gets a mutable reference to a type previously inserted in the map. /// /// # Example /// /// ``` /// # use concurrent_extensions::ConcurrentExtensions; /// let mut ext = ConcurrentExtensions::new(); /// ext.insert(String::from("Hello")); /// ext.get_mut::<String>().unwrap().push_str(" World"); /// /// assert_eq!(ext.get::<String>().as_deref().unwrap(), "Hello World"); /// ``` pub fn get_mut<T: Send + Sync + 'static>(&self) -> Option<MappedRefMut<'_, Key, Value, T>> { self.map.get_mut(&TypeId::of::<T>()).map(|dm_ref_mut| { dm_ref_mut.map(|boxed| { (**boxed) .as_any_mut() .downcast_mut() .expect("value type should be T") }) }) } /// Gets a mutable reference to a type, inserting `value` if not already present. /// /// # Example /// /// ``` /// # use concurrent_extensions::ConcurrentExtensions; /// let mut ext = ConcurrentExtensions::new(); /// *ext.get_or_insert(1i32) += 2; /// /// assert_eq!(*ext.get::<i32>().unwrap(), 3); /// ``` pub fn get_or_insert<T: Clone + Send + Sync + 'static>( &self, value: T, ) -> MappedRefMut<'_, Key, Value, T> { self.get_or_insert_with(|| value) } /// Gets a mutable reference to a type, inserting the value created by `f` if not already /// present. /// /// # Example /// /// ``` /// # use concurrent_extensions::ConcurrentExtensions; /// let mut ext = ConcurrentExtensions::new(); /// *ext.get_or_insert_with(|| 1i32) += 2; /// /// assert_eq!(*ext.get::<i32>().unwrap(), 3); /// ``` pub fn get_or_insert_with<T: Clone + Send + Sync + 'static, F: FnOnce() -> T>( &self, f: F, ) -> MappedRefMut<'_, Key, Value, T> { self.map .entry(TypeId::of::<T>()) .or_insert_with(|| Box::new(f())) .map(|boxed| { (**boxed) .as_any_mut() .downcast_mut() .expect("value type should be T") }) } /// Gets a mutable reference to a type, inserting the type's default value if not already /// present. /// /// # Example /// /// ``` /// # use concurrent_extensions::ConcurrentExtensions; /// let mut ext = ConcurrentExtensions::new(); /// *ext.get_or_insert_default::<i32>() += 2; /// /// assert_eq!(*ext.get::<i32>().unwrap(), 2); /// ``` pub fn get_or_insert_default<T: Default + Clone + Send + Sync + 'static>( &self, ) -> MappedRefMut<'_, Key, Value, T> { self.get_or_insert_with(T::default) } /// Removes a type from the map. /// /// If a extension of this type existed, it will be returned. /// /// # Example /// /// ``` /// # use concurrent_extensions::ConcurrentExtensions; /// let mut ext = ConcurrentExtensions::new(); /// ext.insert(5i32); /// assert_eq!(ext.remove::<i32>(), Some(5i32)); /// assert!(ext.get::<i32>().is_none()); /// ``` pub fn remove<T: Send + Sync + 'static>(&self) -> Option<T> { self.map .remove(&TypeId::of::<T>()) .and_then(|boxed| boxed.1.into_any().downcast().ok().map(|boxed| *boxed)) } /// Clears the map of all inserted extensions. /// /// # Example /// /// ``` /// # use concurrent_extensions::ConcurrentExtensions; /// let mut ext = ConcurrentExtensions::new(); /// ext.insert(5i32); /// ext.clear(); /// /// assert!(ext.get::<i32>().is_none()); /// ``` #[inline] pub fn clear(&self) { self.map.clear(); } /// Checks whether the map is empty or not. /// /// # Example /// /// ``` /// # use concurrent_extensions::ConcurrentExtensions; /// let mut ext = ConcurrentExtensions::new(); /// assert!(ext.is_empty()); /// ext.insert(5i32); /// assert!(!ext.is_empty()); /// ``` #[inline] pub fn is_empty(&self) -> bool { self.map.is_empty() } /// Gets the numer of types available in the map. /// /// # Example /// /// ``` /// # use concurrent_extensions::ConcurrentExtensions; /// let mut ext = ConcurrentExtensions::new(); /// assert_eq!(ext.len(), 0); /// ext.insert(5i32); /// assert_eq!(ext.len(), 1); /// ``` #[inline] pub fn len(&self) -> usize { self.map.len() } } impl fmt::Debug for ConcurrentExtensions { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("ConcurrentExtensions").finish() } } pub trait AnyClone: Any { fn clone_box(&self) -> Box<dyn AnyClone + Send + Sync>; fn as_any(&self) -> &dyn Any; fn as_any_mut(&mut self) -> &mut dyn Any; fn into_any(self: Box<Self>) -> Box<dyn Any>; } impl<T: Clone + Send + Sync + 'static> AnyClone for T { fn clone_box(&self) -> Box<dyn AnyClone + Send + Sync> { Box::new(self.clone()) } fn as_any(&self) -> &dyn Any { self } fn as_any_mut(&mut self) -> &mut dyn Any { self } fn into_any(self: Box<Self>) -> Box<dyn Any> { self } } impl Clone for Box<dyn AnyClone + Send + Sync> { fn clone(&self) -> Self { (**self).clone_box() } } #[cfg(test)] mod tests { use std::ops::DerefMut; use super::*; #[test] fn concurrent_extensions() { #[derive(Clone, Debug, PartialEq)] struct MyType(i32); #[derive(Clone, Debug, PartialEq)] struct MyMemoizedType(i32); #[derive(Clone, Debug, PartialEq)] struct MyMemoizedTypeWith(i32); #[derive(Clone, Debug, PartialEq)] struct MyMemoizedTypeDefault(i32); impl Default for MyMemoizedTypeDefault { fn default() -> Self { Self(7) } } let extensions = ConcurrentExtensions::new(); extensions.insert(5i32); extensions.insert(MyType(10)); assert_eq!(extensions.get().as_deref(), Some(&5i32)); assert_eq!(extensions.get_mut().as_deref_mut(), Some(&mut 5i32)); assert_eq!(extensions.get::<MyMemoizedType>().as_deref(), None); assert_eq!( extensions.get_or_insert(MyMemoizedType(10)).deref_mut(), &mut MyMemoizedType(10) ); assert_eq!(extensions.get().as_deref(), Some(&MyMemoizedType(10))); assert_eq!(extensions.get::<MyMemoizedTypeWith>().as_deref(), None); assert_eq!( extensions .get_or_insert_with(|| MyMemoizedTypeWith(12)) .deref_mut(), &mut MyMemoizedTypeWith(12) ); assert_eq!(extensions.get().as_deref(), Some(&MyMemoizedTypeWith(12))); assert_eq!(extensions.get::<MyMemoizedTypeDefault>().as_deref(), None); assert_eq!( extensions .get_or_insert_default::<MyMemoizedTypeDefault>() .deref_mut(), &mut MyMemoizedTypeDefault(7) ); assert_eq!(extensions.get().as_deref(), Some(&MyMemoizedTypeDefault(7))); let ext2 = extensions.clone(); assert_eq!(extensions.remove::<i32>(), Some(5i32)); assert!(extensions.get::<i32>().is_none()); // clone still has it assert_eq!(ext2.get().as_deref(), Some(&5i32)); assert_eq!(ext2.get().as_deref(), Some(&MyType(10))); assert_eq!(extensions.get::<bool>().as_deref(), None); assert_eq!(extensions.get().as_deref(), Some(&MyType(10))); assert!(!extensions.is_empty()); extensions.clear(); assert!(extensions.is_empty()); assert_eq!(extensions.get::<MyType>().as_deref(), None); // clone still has it assert_eq!(ext2.get().as_deref(), Some(&MyType(10))); } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/systeminit/si'

If you have feedback or need assistance with the MCP directory API, please join our Discord server