diff --git a/crates/core/component/Cargo.toml b/crates/core/component/Cargo.toml index b730930a..9f106eba 100644 --- a/crates/core/component/Cargo.toml +++ b/crates/core/component/Cargo.toml @@ -20,6 +20,7 @@ edcode2 = { path = "../../util/edcode2", package = "rimecraft-edcode2" } rimecraft-registry = { path = "../registry", features = ["serde"] } rimecraft-global-cx = { path = "../global-cx", features = ["nbt", "std"] } rimecraft-maybe = { path = "../../util/maybe" } +typeid = "1.0" [features] diff --git a/crates/core/component/src/changes.rs b/crates/core/component/src/changes.rs index 299c5728..4f20bab4 100644 --- a/crates/core/component/src/changes.rs +++ b/crates/core/component/src/changes.rs @@ -1,6 +1,6 @@ //! `ComponentChanges` implementation. -use std::{fmt::Debug, marker::PhantomData, str::FromStr}; +use std::{cell::UnsafeCell, fmt::Debug, marker::PhantomData, str::FromStr}; use ahash::AHashMap; use rimecraft_global_cx::ProvideIdTy; @@ -8,14 +8,16 @@ use rimecraft_maybe::Maybe; use rimecraft_registry::{ProvideRegistry, Reg}; use serde::{Deserialize, Serialize}; -use crate::{map::CompTyCell, ErasedComponentType, Object, RawErasedComponentType}; +use crate::{ + map::CompTyCell, ErasedComponentType, Object, RawErasedComponentType, UnsafeDebugIter, +}; /// Changes of components. pub struct ComponentChanges<'a, 'cow, Cx> where Cx: ProvideIdTy, { - pub(crate) changes: Maybe<'cow, AHashMap, Option>>>, + pub(crate) changes: Maybe<'cow, AHashMap, Option>>>>, } const REMOVED_PREFIX: char = '!'; @@ -47,7 +49,7 @@ where impl<'a, 'de, Cx> Deserialize<'de> for Type<'a, Cx> where - Cx: ProvideIdTy + ProvideRegistry<'a, Cx::Id, RawErasedComponentType>, + Cx: ProvideIdTy + ProvideRegistry<'a, Cx::Id, RawErasedComponentType<'a, Cx>>, Cx::Id: FromStr, { fn deserialize(deserializer: D) -> Result @@ -63,7 +65,7 @@ where impl<'a, Cx> serde::de::Visitor<'_> for Visitor<'a, Cx> where - Cx: ProvideIdTy + ProvideRegistry<'a, Cx::Id, RawErasedComponentType>, + Cx: ProvideIdTy + ProvideRegistry<'a, Cx::Id, RawErasedComponentType<'a, Cx>>, Cx::Id: FromStr, { type Value = Type<'a, Cx>; @@ -104,6 +106,6 @@ where Cx::Id: Debug, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Debug::fmt(&self.changes, f) + Debug::fmt(&UnsafeDebugIter(UnsafeCell::new(self.changes.keys())), f) } } diff --git a/crates/core/component/src/dyn_any.rs b/crates/core/component/src/dyn_any.rs new file mode 100644 index 00000000..03329e72 --- /dev/null +++ b/crates/core/component/src/dyn_any.rs @@ -0,0 +1,38 @@ +use std::any::TypeId; + +pub trait Any { + #[inline(always)] + fn type_id(&self) -> TypeId { + typeid::of::() + } +} + +impl Any for T {} + +impl dyn Any + Send + Sync + '_ { + pub unsafe fn downcast_ref(&self) -> Option<&T> { + if (*self).type_id() == typeid::of::() { + unsafe { Some(&*(self as *const dyn Any as *const T)) } + } else { + None + } + } + + pub unsafe fn downcast_mut(&mut self) -> Option<&mut T> { + if (*self).type_id() == typeid::of::() { + unsafe { Some(&mut *(self as *mut dyn Any as *mut T)) } + } else { + None + } + } +} + +pub unsafe fn downcast<'a, T>( + any: Box, +) -> Result, Box> { + if (*any).type_id() == typeid::of::() { + unsafe { Ok(Box::from_raw(Box::into_raw(any) as *mut T)) } + } else { + Err(any) + } +} diff --git a/crates/core/component/src/lib.rs b/crates/core/component/src/lib.rs index 5a15273d..29734663 100644 --- a/crates/core/component/src/lib.rs +++ b/crates/core/component/src/lib.rs @@ -1,10 +1,6 @@ //! Minecraft Component implementation. -use std::{ - any::{Any, TypeId}, - hash::Hash, - marker::PhantomData, -}; +use std::{any::TypeId, cell::UnsafeCell, fmt::Debug, hash::Hash, marker::PhantomData}; use bytes::{Buf, BufMut}; use edcode2::{Decode, Encode}; @@ -12,11 +8,15 @@ use rimecraft_global_cx::ProvideIdTy; use rimecraft_registry::{ProvideRegistry, Reg}; use serde::{de::DeserializeOwned, Serialize}; -type Object = dyn Any + Send + Sync; +type Object<'a> = dyn Any + Send + Sync + 'a; pub mod changes; pub mod map; +mod dyn_any; + +use dyn_any::Any; + /// Type of a component data. /// /// The type `T` should be unique for each component, as it's used to identify the component. @@ -24,12 +24,12 @@ pub mod map; /// For the type-erased variant, see [`RawErasedComponentType`]. #[derive(Debug)] #[doc(alias = "DataComponentType")] -pub struct ComponentType { - f: Funcs, +pub struct ComponentType<'a, T> { + f: Funcs<'a>, _marker: PhantomData, } -impl ComponentType { +impl ComponentType<'_, T> { /// Returns whether the component is transient. #[inline] #[doc(alias = "should_skip_serialization")] @@ -38,31 +38,25 @@ impl ComponentType { } } -impl ComponentType +impl<'a, T> ComponentType<'a, T> where - T: Clone + Eq + Send + Sync + 'static, + T: Clone + Eq + Send + Sync + 'a, { - const UTIL: DynUtil = DynUtil { - clone: |obj| Box::new(obj.downcast_ref::().expect("mismatched type").clone()), - eq: |a, b| a.downcast_ref::() == b.downcast_ref::(), + const UTIL: DynUtil<'a> = DynUtil { + clone: |obj| Box::new(unsafe { &*(obj as *const Object<'_> as *const T) }.clone()), + eq: |a, b| unsafe { + *(a as *const Object<'_> as *const T) == *(b as *const Object<'_> as *const T) + }, }; } -impl ComponentType +impl<'a, T> ComponentType<'a, T> where - T: for<'a> Encode<&'a dyn BufMut> - + for<'a> Decode<'static, &'a dyn Buf> - + Send - + Sync - + 'static, + T: for<'b> Encode<&'b dyn BufMut> + for<'b> Decode<'static, &'b dyn Buf> + Send + Sync + 'a, { /// Codec for packet encoding and decoding. - pub const PACKET_CODEC: PacketCodec = PacketCodec { - encode: |obj, buf| { - obj.downcast_ref::() - .expect("mismatched type") - .encode(buf) - }, + pub const PACKET_CODEC: PacketCodec<'a> = PacketCodec { + encode: |obj, buf| unsafe { &*(obj as *const Object<'_> as *const T) }.encode(buf), decode: { assert!( >::SUPPORT_NON_IN_PLACE, @@ -70,26 +64,19 @@ where ); |buf| Ok(Box::new(T::decode(buf)?)) }, - upd: |obj, buf| { - obj.downcast_mut::() - .expect("mismatched type") - .decode_in_place(buf) - }, + upd: |obj, buf| unsafe { &mut *(obj as *mut Object<'_> as *mut T) }.decode_in_place(buf), }; } -impl ComponentType +impl<'a, T> ComponentType<'a, T> where - T: Clone + Eq + Send + Sync + 'static, + T: Clone + Eq + Send + Sync + 'a, { /// Creates a new transient component type. /// /// Transient components are not serialized. - /// - /// This function requires the type to be `'static`. If the type is not `'static`, transmutes - /// the type to `'static`, which is unsound but works. #[inline] - pub const fn transient(packet_codec: Option<&'static PacketCodec>) -> Self { + pub const fn transient(packet_codec: Option<&'a PacketCodec<'a>>) -> Self { Self { f: Funcs { serde_codec: None, @@ -101,24 +88,20 @@ where } } -impl ComponentType +impl<'a, T> ComponentType<'a, T> where - T: Clone + Eq + Serialize + DeserializeOwned + Send + Sync + 'static, + T: Clone + Eq + Serialize + DeserializeOwned + Send + Sync + 'a, { - const SERDE_CODEC: SerdeCodec = SerdeCodec { - ser: |obj| { - obj.downcast_ref::() - .expect("the erased type should matches the actual type") - }, + const SERDE_CODEC: SerdeCodec<'a> = SerdeCodec { + ser: |obj| unsafe { &*(obj as *const Object<'_> as *const T) }, de: |deserializer| { erased_serde::deserialize::(deserializer).map(|v| { - let v: Box = Box::new(v); + let v: Box> = Box::new(v); v }) }, upd: |obj, deserializer| { - *obj.downcast_mut::() - .expect("the erased type should matches the actual type") = + *unsafe { &mut *(obj as *mut Object<'_> as *mut T) } = erased_serde::deserialize::(deserializer)?; Ok(()) }, @@ -130,7 +113,7 @@ where /// /// This function requires the type to be `'static`. If the type is not `'static`, transmutes /// the type to `'static`, which is unsound but works. - pub const fn persistent(packet_codec: Option<&'static PacketCodec>) -> Self { + pub const fn persistent(packet_codec: Option<&'a PacketCodec<'a>>) -> Self { Self { f: Funcs { serde_codec: Some(&Self::SERDE_CODEC), @@ -142,23 +125,23 @@ where } } -impl Hash for ComponentType { +impl Hash for ComponentType<'_, T> { #[inline] fn hash(&self, state: &mut H) { - TypeId::of::().hash(state); + typeid::of::().hash(state); } } -impl PartialEq for ComponentType { +impl PartialEq for ComponentType<'_, T> { #[inline] fn eq(&self, _other: &Self) -> bool { true } } -impl Default for ComponentType +impl<'a, T> Default for ComponentType<'a, T> where - T: Clone + Eq + Send + Sync + 'static, + T: Clone + Eq + Send + Sync + 'a, { #[inline] fn default() -> Self { @@ -166,9 +149,9 @@ where } } -impl Copy for ComponentType {} +impl Copy for ComponentType<'_, T> {} -impl Clone for ComponentType { +impl Clone for ComponentType<'_, T> { #[inline] fn clone(&self) -> Self { *self @@ -179,82 +162,104 @@ impl Clone for ComponentType { /// /// This contains the type ID of the component and the codecs for serialization and packet encoding. #[derive(Debug)] -pub struct RawErasedComponentType { +pub struct RawErasedComponentType<'a, Cx> { ty: TypeId, - f: Funcs, + f: Funcs<'a>, _marker: PhantomData, } #[derive(Debug, Clone, Copy)] #[allow(dead_code)] -struct SerdeCodec { - ser: for<'a> fn(&'a Object) -> &'a dyn erased_serde::Serialize, - de: fn(&mut dyn erased_serde::Deserializer<'_>) -> erased_serde::Result>, - upd: fn(&mut Object, &mut dyn erased_serde::Deserializer<'_>) -> erased_serde::Result<()>, +struct SerdeCodec<'a> { + ser: for<'s> fn(&'s Object<'a>) -> &'s dyn erased_serde::Serialize, + de: fn(&mut dyn erased_serde::Deserializer<'_>) -> erased_serde::Result>>, + upd: fn(&mut Object<'a>, &mut dyn erased_serde::Deserializer<'a>) -> erased_serde::Result<()>, } /// Codec for packet encoding and decoding. #[derive(Debug, Clone, Copy)] #[allow(dead_code)] -pub struct PacketCodec { - encode: fn(&Object, &mut dyn BufMut) -> Result<(), edcode2::BoxedError<'static>>, - decode: fn(&mut dyn Buf) -> Result, edcode2::BoxedError<'static>>, - upd: fn(&mut Object, &mut dyn Buf) -> Result<(), edcode2::BoxedError<'static>>, +pub struct PacketCodec<'a> { + encode: fn(&Object<'a>, &mut dyn BufMut) -> Result<(), edcode2::BoxedError<'a>>, + decode: fn(&mut dyn Buf) -> Result>, edcode2::BoxedError<'a>>, + upd: fn(&mut Object<'a>, &mut dyn Buf) -> Result<(), edcode2::BoxedError<'a>>, } #[derive(Debug, Clone, Copy)] -struct DynUtil { - clone: fn(&Object) -> Box, - eq: fn(&Object, &Object) -> bool, +struct DynUtil<'a> { + clone: fn(&Object<'a>) -> Box>, + eq: fn(&Object<'a>, &Object<'a>) -> bool, } #[derive(Debug, Clone, Copy)] #[allow(dead_code)] -struct Funcs { - serde_codec: Option<&'static SerdeCodec>, - packet_codec: Option<&'static PacketCodec>, - util: &'static DynUtil, +struct Funcs<'a> { + serde_codec: Option<&'a SerdeCodec<'a>>, + packet_codec: Option<&'a PacketCodec<'a>>, + util: &'a DynUtil<'a>, } -impl RawErasedComponentType { +impl<'a, Cx> RawErasedComponentType<'a, Cx> { /// Downcasts this type-erased component type into a typed data component type. + /// + /// # Safety + /// + /// This function could not guarantee lifetime of type `T` is sound. + /// The type `T`'s lifetime parameters should not overlap lifetime `'a`. #[inline] - pub fn downcast(&self) -> Option> { - (TypeId::of::() == self.ty).then_some(ComponentType { + pub unsafe fn downcast(&self) -> Option> { + (typeid::of::() == self.ty).then_some(ComponentType { f: self.f, _marker: PhantomData, }) } + + /// Downcasts this type-erased component type into a typed data component type. + /// + /// # Safety + /// + /// This function could not guarantee lifetime of type `T` is sound. + /// The type `T`'s lifetime parameters should not overlap lifetime `'a`. + /// + /// This function does not validate equality of two types. + #[inline] + pub unsafe fn downcast_unchecked(&self) -> ComponentType<'a, T> { + debug_assert_eq!(typeid::of::(), self.ty); + ComponentType { + f: self.f, + _marker: PhantomData, + } + } } -impl From<&ComponentType> for RawErasedComponentType { +impl<'a, T, Cx> From<&ComponentType<'a, T>> for RawErasedComponentType<'a, Cx> { #[inline] - fn from(value: &ComponentType) -> Self { + fn from(value: &ComponentType<'a, T>) -> Self { Self { - ty: TypeId::of::(), + ty: typeid::of::(), f: value.f, _marker: PhantomData, } } } -impl Hash for RawErasedComponentType { +impl Hash for RawErasedComponentType<'_, Cx> { #[inline] fn hash(&self, state: &mut H) { self.ty.hash(state); } } -impl PartialEq for RawErasedComponentType { +impl PartialEq for RawErasedComponentType<'_, Cx> { #[inline] fn eq(&self, other: &Self) -> bool { self.ty == other.ty } } -impl Eq for RawErasedComponentType {} +impl Eq for RawErasedComponentType<'_, Cx> {} -impl<'r, K, Cx> ProvideRegistry<'r, K, Self> for RawErasedComponentType +impl<'r, K, Cx> ProvideRegistry<'r, K, Self> for RawErasedComponentType<'_, Cx> where Cx: ProvideRegistry<'r, K, Self>, { @@ -265,4 +270,19 @@ where } /// Registration wrapper of [`RawErasedComponentType`]. -pub type ErasedComponentType<'a, Cx> = Reg<'a, ::Id, RawErasedComponentType>; +pub type ErasedComponentType<'a, Cx> = + Reg<'a, ::Id, RawErasedComponentType<'a, Cx>>; + +struct UnsafeDebugIter(UnsafeCell); + +impl Debug for UnsafeDebugIter +where + I: Iterator, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + unsafe { + let it = &mut *self.0.get(); + f.debug_list().entries(it).finish() + } + } +} diff --git a/crates/core/component/src/map.rs b/crates/core/component/src/map.rs index 17b7b852..c7ae48a9 100644 --- a/crates/core/component/src/map.rs +++ b/crates/core/component/src/map.rs @@ -1,7 +1,8 @@ //! Component map implementation. use std::{ - any::TypeId, borrow::Borrow, collections::hash_map, fmt::Debug, hash::Hash, marker::PhantomData, + borrow::Borrow, cell::UnsafeCell, collections::hash_map, fmt::Debug, hash::Hash, + marker::PhantomData, }; use ahash::AHashMap; @@ -11,8 +12,8 @@ use rimecraft_registry::ProvideRegistry; use serde::{Deserialize, Serialize}; use crate::{ - changes::ComponentChanges, ComponentType, ErasedComponentType, Object, RawErasedComponentType, - SerdeCodec, + changes::ComponentChanges, dyn_any, ComponentType, ErasedComponentType, Object, + RawErasedComponentType, SerdeCodec, UnsafeDebugIter, }; #[repr(transparent)] @@ -30,10 +31,10 @@ where Empty, Patched { base: &'a ComponentMap<'a, Cx>, - changes: AHashMap, Option>>, + changes: AHashMap, Option>>>, changes_count: isize, }, - Simple(AHashMap, Box>), + Simple(AHashMap, Box>>), } impl Default for ComponentMap<'_, Cx> @@ -75,13 +76,18 @@ where } /// Gets the component with given type. - pub fn get(&self, ty: &ComponentType) -> Option<&T> { + /// + /// # Safety + /// + /// This function could not guarantee lifetime of type `T` is sound. + /// The type `T`'s lifetime parameters should not overlap lifetime `'a`. + pub unsafe fn get(&self, ty: &ComponentType<'a, T>) -> Option<&T> { self.get_raw(&RawErasedComponentType::from(ty)) - .and_then(Object::downcast_ref) + .and_then(|val| unsafe { val.downcast_ref() }) } #[inline] - fn get_raw(&self, ty: &RawErasedComponentType) -> Option<&Object> { + fn get_raw(&self, ty: &RawErasedComponentType<'a, Cx>) -> Option<&Object<'_>> { match &self.0 { MapInner::Empty => None, MapInner::Patched { base, changes, .. } => changes @@ -93,9 +99,14 @@ where } /// Gets the component and its type registration with given type. - pub fn get_key_value( + /// + /// # Safety + /// + /// This function could not guarantee lifetime of type `T` is sound. + /// The type `T`'s lifetime parameters should not overlap lifetime `'a`. + pub unsafe fn get_key_value( &self, - ty: &ComponentType, + ty: &ComponentType<'a, T>, ) -> Option<(ErasedComponentType<'a, Cx>, &T)> { self.get_key_value_raw(&RawErasedComponentType::from(ty)) .and_then(|(k, v)| v.downcast_ref().map(|v| (k, v))) @@ -104,8 +115,8 @@ where #[inline] fn get_key_value_raw( &self, - ty: &RawErasedComponentType, - ) -> Option<(ErasedComponentType<'a, Cx>, &Object)> { + ty: &RawErasedComponentType<'a, Cx>, + ) -> Option<(ErasedComponentType<'a, Cx>, &Object<'a>)> { match &self.0 { MapInner::Empty => None, MapInner::Patched { base, changes, .. } => changes @@ -117,12 +128,12 @@ where } /// Returns whether a component with given type exist. - pub fn contains(&self, ty: &ComponentType) -> bool { + pub fn contains(&self, ty: &ComponentType<'a, T>) -> bool { self.contains_raw(&RawErasedComponentType::from(ty)) } #[inline] - fn contains_raw(&self, ty: &RawErasedComponentType) -> bool { + fn contains_raw(&self, ty: &RawErasedComponentType<'a, Cx>) -> bool { match &self.0 { MapInner::Empty => false, MapInner::Patched { base, changes, .. } => changes @@ -134,13 +145,13 @@ where } /// Gets the component with given type, with mutable access. - pub fn get_mut(&mut self, ty: &ComponentType) -> Option<&mut T> { + pub fn get_mut(&mut self, ty: &ComponentType<'a, T>) -> Option<&mut T> { self.get_mut_raw(&RawErasedComponentType::from(ty)) - .and_then(Object::downcast_mut) + .and_then(|val| unsafe { val.downcast_mut() }) } #[inline] - fn get_mut_raw(&mut self, ty: &RawErasedComponentType) -> Option<&mut Object> { + fn get_mut_raw(&mut self, ty: &RawErasedComponentType<'a, Cx>) -> Option<&mut Object<'a>> { match &mut self.0 { MapInner::Empty => None, MapInner::Patched { base, changes, .. } => { @@ -164,11 +175,20 @@ where /// /// This function panics when the given component type's type information does not match with /// the given static type. - pub fn insert(&mut self, ty: ErasedComponentType<'a, Cx>, val: T) -> Option> + /// + /// # Safety + /// + /// This function could not guarantee lifetime of type `T` is sound. + /// The type `T`'s lifetime parameters should not overlap lifetime `'a`. + pub unsafe fn insert( + &mut self, + ty: ErasedComponentType<'a, Cx>, + val: T, + ) -> Option> where - T: Send + Sync + 'static, + T: Send + Sync + 'a, { - let value = self.insert_untracked(ty, val); + let value = unsafe { self.insert_untracked(ty, val) }; if value.is_none() { self.track_add() } @@ -176,19 +196,20 @@ where } #[inline] - fn insert_untracked( + unsafe fn insert_untracked( &mut self, ty: ErasedComponentType<'a, Cx>, val: T, ) -> Option> where - T: Send + Sync + 'static, + T: Send + Sync + 'a, { assert_eq! { ty.ty, - TypeId::of::(), + typeid::of::(), "the component type should matches the type of given value", }; + match &mut self.0 { MapInner::Empty => None, MapInner::Patched { base, changes, .. } => { @@ -199,20 +220,25 @@ where Some(v) } else { return old - .and_then(|old| old.downcast_ref::()) + .and_then(|old| unsafe { old.downcast_ref::() }) .map(Maybe::Borrowed); } .flatten() } MapInner::Simple(map) => map.insert(CompTyCell(ty), Box::new(val)), } - .and_then(|obj| obj.downcast().ok()) + .and_then(|obj| unsafe { dyn_any::downcast(obj).ok() }) .map(|boxed| Maybe::Owned(SimpleOwned(*boxed))) } /// Removes a component with given type, and returns it if valid. - pub fn remove(&mut self, ty: &ComponentType) -> Option> { - let value = self.remove_untracked(ty); + /// + /// # Safety + /// + /// This function could not guarantee lifetime of type `T` is sound. + /// The type `T`'s lifetime parameters should not overlap lifetime `'a`. + pub unsafe fn remove(&mut self, ty: &ComponentType<'a, T>) -> Option> { + let value = unsafe { self.remove_untracked(ty) }; if value.is_some() { self.track_rm() } @@ -220,7 +246,7 @@ where } #[inline] - fn remove_untracked(&mut self, ty: &ComponentType) -> Option> { + unsafe fn remove_untracked(&mut self, ty: &ComponentType<'a, T>) -> Option> { match &mut self.0 { MapInner::Empty => None, MapInner::Patched { base, changes, .. } => { @@ -234,18 +260,18 @@ where } (Some(_), Some(now)) => now .take() - .and_then(|obj| obj.downcast().ok()) + .and_then(|obj| unsafe { dyn_any::downcast(obj).ok() }) .map(|boxed| Maybe::Owned(SimpleOwned(*boxed))), (None, Some(_)) => changes .remove(era_ty)? - .and_then(|obj| obj.downcast().ok()) + .and_then(|obj| unsafe { dyn_any::downcast(obj).ok() }) .map(|boxed| Maybe::Owned(SimpleOwned(*boxed))), (None, None) => None, } } MapInner::Simple(map) => map .remove(&RawErasedComponentType::from(ty)) - .and_then(|obj| obj.downcast().ok()) + .and_then(|obj| unsafe { dyn_any::downcast(obj).ok() }) .map(|boxed| Maybe::Owned(SimpleOwned(*boxed))), } } @@ -289,7 +315,7 @@ where /// Returns an iterator over the components in this map. #[inline] - pub fn iter(&self) -> Iter<'_, Cx> { + pub fn iter<'s>(&'s self) -> Iter<'s, 'a, Cx> { self.into_iter() } @@ -305,13 +331,13 @@ where } } -impl<'a, Cx> IntoIterator for &'a ComponentMap<'a, Cx> +impl<'a, 's, Cx> IntoIterator for &'s ComponentMap<'a, Cx> where Cx: ProvideIdTy, { - type Item = as Iterator>::Item; + type Item = as Iterator>::Item; - type IntoIter = Iter<'a, Cx>; + type IntoIter = Iter<'s, 'a, Cx>; fn into_iter(self) -> Self::IntoIter { Iter( @@ -345,33 +371,33 @@ impl Hash for CompTyCell<'_, Cx> { } } -impl Borrow> for CompTyCell<'_, Cx> { +impl<'a, Cx: ProvideIdTy> Borrow> for CompTyCell<'a, Cx> { #[inline] - fn borrow(&self) -> &RawErasedComponentType { + fn borrow(&self) -> &RawErasedComponentType<'a, Cx> { &self.0 } } /// Iterates over the components in this map. -pub struct Iter<'a, Cx>(IterInner<'a, Cx>, &'a ComponentMap<'a, Cx>) +pub struct Iter<'s, 'a, Cx>(IterInner<'s, 'a, Cx>, &'s ComponentMap<'a, Cx>) where Cx: ProvideIdTy; -enum IterInner<'a, Cx: ProvideIdTy> { +enum IterInner<'s, 'a, Cx: ProvideIdTy> { Empty, Patched { - changes: &'a AHashMap, Option>>, - base_it: Box>, - changes_it: hash_map::Iter<'a, CompTyCell<'a, Cx>, Option>>, + changes: &'s AHashMap, Option>>>, + base_it: Box>, + changes_it: hash_map::Iter<'s, CompTyCell<'a, Cx>, Option>>>, }, - Simple(hash_map::Iter<'a, CompTyCell<'a, Cx>, Box>), + Simple(hash_map::Iter<'s, CompTyCell<'a, Cx>, Box>>), } -impl<'a, Cx> Iterator for Iter<'a, Cx> +impl<'s, 'a, Cx> Iterator for Iter<'s, 'a, Cx> where Cx: ProvideIdTy, { - type Item = (ErasedComponentType<'a, Cx>, &'a Object); + type Item = (ErasedComponentType<'a, Cx>, &'s Object<'a>); fn next(&mut self) -> Option { match &mut self.0 { @@ -415,7 +441,7 @@ pub struct Builder<'a, Cx> where Cx: ProvideIdTy, { - map: AHashMap, Box>, + map: AHashMap, Box>>, } impl<'a, Cx> Builder<'a, Cx> @@ -431,11 +457,11 @@ where #[inline] pub fn insert(mut self, ty: ErasedComponentType<'a, Cx>, val: T) -> Self where - T: Send + Sync + 'static, + T: Send + Sync + 'a, { assert_eq!( ty.ty, - TypeId::of::(), + typeid::of::(), "the component type should matches the type of given value" ); self.map.insert(CompTyCell(ty), Box::new(val)); @@ -488,15 +514,18 @@ where } => f .debug_struct("PatchedComponentMap") .field("base", base) - .field("changes", changes) + .field("changes", &UnsafeDebugIter(UnsafeCell::new(changes.keys()))) .field("changes_count", changes_count) .finish(), - MapInner::Simple(map) => f.debug_tuple("SimpleComponentMap").field(&map).finish(), + MapInner::Simple(map) => f + .debug_tuple("SimpleComponentMap") + .field(&UnsafeDebugIter(UnsafeCell::new(map.keys()))) + .finish(), } } } -impl Debug for Iter<'_, Cx> +impl Debug for Iter<'_, '_, Cx> where Cx: ProvideIdTy + Debug, Cx::Id: Debug, @@ -507,14 +536,13 @@ where IterInner::Patched { changes, base_it, - changes_it, + changes_it: _, } => f .debug_struct("PatchedComponentMapIter") - .field("changes", changes) + .field("changes", &UnsafeDebugIter(UnsafeCell::new(changes.keys()))) .field("base_it", base_it) - .field("changes_it", changes_it) .finish(), - IterInner::Simple(it) => f.debug_tuple("SimpleComponentMapIter").field(it).finish(), + IterInner::Simple(_it) => f.debug_tuple("SimpleComponentMapIter").finish(), } } } @@ -526,7 +554,7 @@ where { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("ComponentMapBuilder") - .field("map", &self.map) + .field("map", &UnsafeDebugIter(UnsafeCell::new(self.map.keys()))) .finish() } } @@ -542,8 +570,8 @@ where { use serde::ser::SerializeMap; let mut map = serializer.serialize_map(None)?; - for (ty, val) in self { - if let Some(codec) = &ty.f.serde_codec { + for (ty, val) in self.iter() { + if let Some(codec) = ty.f.serde_codec { map.serialize_entry(&ty, (codec.ser)(val))?; } } @@ -553,7 +581,7 @@ where impl<'a, 'de, Cx> Deserialize<'de> for ComponentMap<'a, Cx> where - Cx: ProvideIdTy + ProvideRegistry<'a, Cx::Id, RawErasedComponentType>, + Cx: ProvideIdTy + ProvideRegistry<'a, Cx::Id, RawErasedComponentType<'a, Cx>>, Cx::Id: Deserialize<'de> + Hash + Eq, { fn deserialize(deserializer: D) -> Result @@ -564,7 +592,7 @@ where impl<'a, 'de, Cx> serde::de::Visitor<'de> for Visitor<'a, Cx> where - Cx: ProvideIdTy + ProvideRegistry<'a, Cx::Id, RawErasedComponentType>, + Cx: ProvideIdTy + ProvideRegistry<'a, Cx::Id, RawErasedComponentType<'a, Cx>>, Cx::Id: Deserialize<'de> + Hash + Eq, { type Value = ComponentMap<'a, Cx>; @@ -579,14 +607,14 @@ where } else { AHashMap::new() }; - struct DeSeed<'a, Cx>(&'a SerdeCodec, PhantomData<&'a Cx>); + struct DeSeed<'a, Cx>(&'a SerdeCodec<'a>, PhantomData); impl<'a, 'de, Cx> serde::de::DeserializeSeed<'de> for DeSeed<'a, Cx> where - Cx: ProvideIdTy + ProvideRegistry<'a, Cx::Id, RawErasedComponentType>, + Cx: ProvideIdTy + ProvideRegistry<'a, Cx::Id, RawErasedComponentType<'a, Cx>>, Cx::Id: Deserialize<'de> + Hash + Eq, { - type Value = Box; + type Value = Box>; #[inline] fn deserialize(self, deserializer: D) -> Result @@ -608,7 +636,7 @@ where })?; m.insert( CompTyCell(k), - map.next_value_seed(DeSeed(codec, PhantomData::<&Cx>))?, + map.next_value_seed(DeSeed(codec, PhantomData::))?, ); } m.shrink_to_fit();