#[derive(Clone)] pub(crate) struct AnyValue { inner: std::sync::Arc, // While we can extract `TypeId` from `inner`, the debug repr is of a number, so let's track // the type_name in debug builds. id: AnyValueId, } impl AnyValue { pub(crate) fn new(inner: V) -> Self { let id = AnyValueId::of::(); let inner = std::sync::Arc::new(inner); Self { inner, id } } pub(crate) fn downcast_ref( &self, ) -> Option<&T> { self.inner.downcast_ref::() } pub(crate) fn downcast_into(self) -> Result { let id = self.id; let value = ok!(std::sync::Arc::downcast::(self.inner).map_err(|inner| Self { inner, id })); let value = std::sync::Arc::try_unwrap(value).unwrap_or_else(|arc| (*arc).clone()); Ok(value) } pub(crate) fn type_id(&self) -> AnyValueId { self.id } } impl std::fmt::Debug for AnyValue { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { f.debug_struct("AnyValue").field("inner", &self.id).finish() } } #[derive(Copy, Clone)] pub struct AnyValueId { type_id: std::any::TypeId, #[cfg(debug_assertions)] type_name: &'static str, } impl AnyValueId { pub(crate) fn of() -> Self { Self { type_id: std::any::TypeId::of::(), #[cfg(debug_assertions)] type_name: std::any::type_name::(), } } } impl PartialEq for AnyValueId { fn eq(&self, other: &Self) -> bool { self.type_id == other.type_id } } impl Eq for AnyValueId {} impl PartialOrd for AnyValueId { fn partial_cmp(&self, other: &Self) -> Option { self.type_id.partial_cmp(&other.type_id) } } impl PartialEq for AnyValueId { fn eq(&self, other: &std::any::TypeId) -> bool { self.type_id == *other } } impl Ord for AnyValueId { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.type_id.cmp(&other.type_id) } } impl std::hash::Hash for AnyValueId { fn hash(&self, state: &mut H) { self.type_id.hash(state); } } impl std::fmt::Debug for AnyValueId { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> Result<(), std::fmt::Error> { #[cfg(not(debug_assertions))] { self.type_id.fmt(f) } #[cfg(debug_assertions)] { f.debug_struct(self.type_name).finish() } } } impl<'a, A: ?Sized + 'static> From<&'a A> for AnyValueId { fn from(_: &'a A) -> Self { Self::of::() } } #[cfg(test)] mod test { #[test] #[cfg(debug_assertions)] fn debug_impl() { use super::*; assert_eq!(format!("{:?}", AnyValue::new(5)), "AnyValue { inner: i32 }"); } #[test] fn eq_to_type_id() { use super::*; let any_value_id = AnyValueId::of::(); let type_id = std::any::TypeId::of::(); assert_eq!(any_value_id, type_id); } }