From 9835808884689960283b2a2d6bcc74c4e6e8d1dd Mon Sep 17 00:00:00 2001 From: JieningYu Date: Tue, 13 Aug 2024 09:51:53 +0800 Subject: [PATCH 1/6] polish component changes type --- crates/core/component/rime-target.toml | 2 +- crates/core/component/src/changes.rs | 42 ++++++++++++++++++-------- crates/core/component/src/lib.rs | 6 ++++ crates/core/component/src/map.rs | 16 +++++++--- crates/core/world/Cargo.toml | 1 - 5 files changed, 48 insertions(+), 19 deletions(-) diff --git a/crates/core/component/rime-target.toml b/crates/core/component/rime-target.toml index e3a9858f..bf45d5d0 100644 --- a/crates/core/component/rime-target.toml +++ b/crates/core/component/rime-target.toml @@ -1,2 +1,2 @@ [java_edition] -version = "1.20.6" +version = "1.21.1" diff --git a/crates/core/component/src/changes.rs b/crates/core/component/src/changes.rs index 4f20bab4..04004de2 100644 --- a/crates/core/component/src/changes.rs +++ b/crates/core/component/src/changes.rs @@ -1,6 +1,6 @@ //! `ComponentChanges` implementation. -use std::{cell::UnsafeCell, fmt::Debug, marker::PhantomData, str::FromStr}; +use std::{cell::UnsafeCell, fmt::Debug, marker::PhantomData, str::FromStr, sync::OnceLock}; use ahash::AHashMap; use rimecraft_global_cx::ProvideIdTy; @@ -9,7 +9,8 @@ use rimecraft_registry::{ProvideRegistry, Reg}; use serde::{Deserialize, Serialize}; use crate::{ - map::CompTyCell, ErasedComponentType, Object, RawErasedComponentType, UnsafeDebugIter, + map::CompTyCell, ErasedComponentType, Object, RawErasedComponentType, SerdeCodec, + UnsafeDebugIter, }; /// Changes of components. @@ -17,7 +18,7 @@ pub struct ComponentChanges<'a, 'cow, Cx> where Cx: ProvideIdTy, { - pub(crate) changes: Maybe<'cow, AHashMap, Option>>>>, + pub(crate) changed: Maybe<'cow, AHashMap, Option>>>>, } const REMOVED_PREFIX: char = '!'; @@ -28,6 +29,8 @@ where { ty: ErasedComponentType<'a, Cx>, rm: bool, + + cached_ser: OnceLock, } impl Serialize for Type<'_, Cx> @@ -38,12 +41,14 @@ where where S: serde::Serializer, { - let id = Reg::id(self.ty); - serializer.serialize_str(&if self.rm { - format!("{}{}", REMOVED_PREFIX, id) - } else { - id.to_string() - }) + serializer.serialize_str(self.cached_ser.get_or_init(|| { + let id = Reg::id(self.ty); + if self.rm { + format!("{}{}", REMOVED_PREFIX, id) + } else { + id.to_string() + } + })) } } @@ -85,11 +90,22 @@ where E::custom(format!("unable to deserialize the identifier {}", any)) })?; + let ty = Cx::registry().get(&id).ok_or_else(|| { + E::custom(format!("unable to find the component type {}", id)) + })?; + + if !ty.is_serializable() { + return Err(E::custom(format!( + "the component type {} is not serializable", + id + ))); + } + Ok(Type { - ty: Cx::registry().get(&id).ok_or_else(|| { - E::custom(format!("unable to find the component type {}", id)) - })?, + ty, rm: stripped.is_some(), + + cached_ser: OnceLock::new(), }) } } @@ -106,6 +122,6 @@ where Cx::Id: Debug, { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - Debug::fmt(&UnsafeDebugIter(UnsafeCell::new(self.changes.keys())), f) + Debug::fmt(&UnsafeDebugIter(UnsafeCell::new(self.changed.keys())), f) } } diff --git a/crates/core/component/src/lib.rs b/crates/core/component/src/lib.rs index 29734663..37d45a6e 100644 --- a/crates/core/component/src/lib.rs +++ b/crates/core/component/src/lib.rs @@ -230,6 +230,12 @@ impl<'a, Cx> RawErasedComponentType<'a, Cx> { _marker: PhantomData, } } + + /// Returns whether the component is serializable. + #[inline] + pub fn is_serializable(&self) -> bool { + self.f.serde_codec.is_some() + } } impl<'a, T, Cx> From<&ComponentType<'a, T>> for RawErasedComponentType<'a, Cx> { diff --git a/crates/core/component/src/map.rs b/crates/core/component/src/map.rs index c7ae48a9..bcbf9ad2 100644 --- a/crates/core/component/src/map.rs +++ b/crates/core/component/src/map.rs @@ -128,7 +128,7 @@ where } /// Returns whether a component with given type exist. - pub fn contains(&self, ty: &ComponentType<'a, T>) -> bool { + pub fn contains(&self, ty: &ComponentType<'a, T>) -> bool { self.contains_raw(&RawErasedComponentType::from(ty)) } @@ -145,13 +145,21 @@ where } /// Gets the component with given type, with mutable access. - pub fn get_mut(&mut self, ty: &ComponentType<'a, T>) -> Option<&mut 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_mut(&mut self, ty: &ComponentType<'a, T>) -> Option<&mut T> { self.get_mut_raw(&RawErasedComponentType::from(ty)) .and_then(|val| unsafe { val.downcast_mut() }) } #[inline] - fn get_mut_raw(&mut self, ty: &RawErasedComponentType<'a, Cx>) -> Option<&mut Object<'a>> { + unsafe 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, .. } => { @@ -323,7 +331,7 @@ where pub fn changes(&self) -> Option> { if let MapInner::Patched { changes, .. } = &self.0 { Some(ComponentChanges { - changes: Maybe::Borrowed(changes), + changed: Maybe::Borrowed(changes), }) } else { None diff --git a/crates/core/world/Cargo.toml b/crates/core/world/Cargo.toml index 2c389325..c6ccc0c1 100644 --- a/crates/core/world/Cargo.toml +++ b/crates/core/world/Cargo.toml @@ -27,7 +27,6 @@ serde = { version = "1.0", features = ["derive"] } serde_repr = "0.1" edcode2 = { path = "../../util/edcode2", package = "rimecraft-edcode2", optional = true } parking_lot = "0.12" -fastnbt = "2.5" ahash = "0.8" [features] From 4f37b7a5b5e154659e88fcf8cc38c7cce2bd767b Mon Sep 17 00:00:00 2001 From: JieningYu Date: Tue, 13 Aug 2024 10:16:36 +0800 Subject: [PATCH 2/6] done builder --- crates/core/component/src/changes.rs | 83 +++++++++++++++++++++++++++- crates/core/component/src/map.rs | 2 +- crates/util/maybe/src/lib.rs | 1 + 3 files changed, 82 insertions(+), 4 deletions(-) diff --git a/crates/core/component/src/changes.rs b/crates/core/component/src/changes.rs index 04004de2..deae5c89 100644 --- a/crates/core/component/src/changes.rs +++ b/crates/core/component/src/changes.rs @@ -4,13 +4,12 @@ use std::{cell::UnsafeCell, fmt::Debug, marker::PhantomData, str::FromStr, sync: use ahash::AHashMap; use rimecraft_global_cx::ProvideIdTy; -use rimecraft_maybe::Maybe; +use rimecraft_maybe::{Maybe, SimpleOwned}; use rimecraft_registry::{ProvideRegistry, Reg}; use serde::{Deserialize, Serialize}; use crate::{ - map::CompTyCell, ErasedComponentType, Object, RawErasedComponentType, SerdeCodec, - UnsafeDebugIter, + map::CompTyCell, ErasedComponentType, Object, RawErasedComponentType, UnsafeDebugIter, }; /// Changes of components. @@ -21,6 +20,74 @@ where pub(crate) changed: Maybe<'cow, AHashMap, Option>>>>, } +impl<'a, Cx> ComponentChanges<'a, '_, Cx> +where + Cx: ProvideIdTy, +{ + /// Returns a builder for `ComponentChanges`. + pub fn builder() -> Builder<'a, Cx> { + Builder { + changes: AHashMap::new(), + } + } +} + +/// Builder for [`ComponentChanges`]. +pub struct Builder<'a, Cx> +where + Cx: ProvideIdTy, +{ + changes: AHashMap, Option>>>, +} + +impl<'a, Cx> Builder<'a, Cx> +where + Cx: ProvideIdTy, +{ + /// Inserts a component type with a valid value. + /// + /// # Panics + /// + /// Panics if the type of the value does not match the component type. + #[inline] + pub fn insert(&mut self, ty: ErasedComponentType<'a, Cx>, value: T) + where + T: Send + Sync + 'a, + { + assert_eq!( + ty.ty, + typeid::of::(), + "the type {} does not match the component type", + std::any::type_name::() + ); + self.changes.insert(CompTyCell(ty), Some(Box::new(value))); + } + + /// Inserts a component type with an empty value. + #[inline] + pub fn remove(&mut self, ty: ErasedComponentType<'a, Cx>) { + self.changes.insert(CompTyCell(ty), None); + } + + /// Builds the changes into a [`ComponentChanges`]. + #[inline] + pub fn build<'cow>(self) -> ComponentChanges<'a, 'cow, Cx> { + ComponentChanges { + changed: Maybe::Owned(SimpleOwned(self.changes)), + } + } +} + +impl<'a, Cx> From> for ComponentChanges<'a, '_, Cx> +where + Cx: ProvideIdTy, +{ + #[inline] + fn from(builder: Builder<'a, Cx>) -> Self { + builder.build() + } +} + const REMOVED_PREFIX: char = '!'; struct Type<'a, Cx> @@ -125,3 +192,13 @@ where Debug::fmt(&UnsafeDebugIter(UnsafeCell::new(self.changed.keys())), f) } } + +impl Debug for Builder<'_, Cx> +where + Cx: ProvideIdTy + Debug, + Cx::Id: Debug, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + Debug::fmt(&UnsafeDebugIter(UnsafeCell::new(self.changes.keys())), f) + } +} diff --git a/crates/core/component/src/map.rs b/crates/core/component/src/map.rs index bcbf9ad2..f50cb919 100644 --- a/crates/core/component/src/map.rs +++ b/crates/core/component/src/map.rs @@ -17,7 +17,7 @@ use crate::{ }; #[repr(transparent)] -pub(crate) struct CompTyCell<'a, Cx: ProvideIdTy>(ErasedComponentType<'a, Cx>); +pub(crate) struct CompTyCell<'a, Cx: ProvideIdTy>(pub(crate) ErasedComponentType<'a, Cx>); /// A map that stores components. pub struct ComponentMap<'a, Cx>(MapInner<'a, Cx>) diff --git a/crates/util/maybe/src/lib.rs b/crates/util/maybe/src/lib.rs index ce7f2866..887e1af4 100644 --- a/crates/util/maybe/src/lib.rs +++ b/crates/util/maybe/src/lib.rs @@ -65,6 +65,7 @@ where /// A cell that simply owns a value. #[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Hash)] +#[repr(transparent)] pub struct SimpleOwned(pub T); impl Deref for SimpleOwned { From f814f70597c0c6d364a4d9bf58b495f0bf19b4d9 Mon Sep 17 00:00:00 2001 From: JieningYu Date: Tue, 13 Aug 2024 17:00:16 +0800 Subject: [PATCH 3/6] changes serde --- crates/core/component/src/changes.rs | 169 ++++++++++++++++++++++++++- crates/core/component/src/map.rs | 4 + 2 files changed, 171 insertions(+), 2 deletions(-) diff --git a/crates/core/component/src/changes.rs b/crates/core/component/src/changes.rs index deae5c89..70e299a5 100644 --- a/crates/core/component/src/changes.rs +++ b/crates/core/component/src/changes.rs @@ -6,10 +6,11 @@ use ahash::AHashMap; use rimecraft_global_cx::ProvideIdTy; use rimecraft_maybe::{Maybe, SimpleOwned}; use rimecraft_registry::{ProvideRegistry, Reg}; -use serde::{Deserialize, Serialize}; +use serde::{de::DeserializeSeed, ser::SerializeMap, Deserialize, Serialize}; use crate::{ - map::CompTyCell, ErasedComponentType, Object, RawErasedComponentType, UnsafeDebugIter, + map::CompTyCell, ComponentType, ErasedComponentType, Object, RawErasedComponentType, + SerdeCodec, UnsafeDebugIter, }; /// Changes of components. @@ -18,6 +19,7 @@ where Cx: ProvideIdTy, { pub(crate) changed: Maybe<'cow, AHashMap, Option>>>>, + pub(crate) ser_count: usize, } impl<'a, Cx> ComponentChanges<'a, '_, Cx> @@ -28,8 +30,166 @@ where pub fn builder() -> Builder<'a, Cx> { Builder { changes: AHashMap::new(), + ser_count: 0, } } + + /// Gets the component with given type. + /// + /// # 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> { + let val = self.get_raw(&RawErasedComponentType::from(ty))?; + if let Some(val) = val { + let downcasted = val.downcast_ref::()?; + Some(Some(downcasted)) + } else { + Some(None) + } + } + + #[inline] + fn get_raw(&self, ty: &RawErasedComponentType<'a, Cx>) -> Option>> { + self.changed.get(ty).map(Option::as_deref) + } + + /// Returns number of changed components. + #[inline] + pub fn len(&self) -> usize { + self.changed.len() + } + + /// Returns `true` if there are no changed components. + #[inline] + pub fn is_empty(&self) -> bool { + self.changed.is_empty() + } +} + +impl Serialize for ComponentChanges<'_, '_, Cx> +where + Cx: ProvideIdTy, +{ + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + let mut map = serializer.serialize_map(Some(self.ser_count))?; + for (&CompTyCell(ty), obj) in self.changed.iter().filter(|(k, _)| k.0.is_serializable()) { + struct Ser<'a, 's> { + obj: &'s Object<'a>, + codec: &'a SerdeCodec<'a>, + } + + impl Serialize for Ser<'_, '_> { + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + (self.codec.ser)(self.obj).serialize(serializer) + } + } + + let ty = Type { + ty, + rm: obj.is_none(), + cached_ser: OnceLock::new(), + }; + + map.serialize_key(&ty)?; + if obj.is_none() { + // Dummy value. fastnbt does not support Unit values. + map.serialize_value(&0u32)?; + } else { + map.serialize_value(&Ser { + obj: obj.as_ref().unwrap(), + codec: ty.ty.f.serde_codec.expect("missing serde codec"), + })?; + } + } + map.end() + } +} + +impl<'a, 'de, Cx> Deserialize<'de> for ComponentChanges<'a, '_, Cx> +where + Cx: ProvideIdTy + ProvideRegistry<'a, Cx::Id, RawErasedComponentType<'a, Cx>>, +{ + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + struct Visitor<'a, Cx>(PhantomData<(Cx, &'a ())>); + + impl<'a, 'de, Cx> serde::de::Visitor<'de> for Visitor<'a, Cx> + where + Cx: ProvideIdTy + + ProvideRegistry<'a, Cx::Id, RawErasedComponentType<'a, Cx>>, + { + type Value = AHashMap, Option>>>; + + fn expecting(&self, formatter: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(formatter, "a map") + } + + fn visit_map(self, mut map: A) -> Result + where + A: serde::de::MapAccess<'de>, + { + let mut changes; + + if let Some(hint) = map.size_hint() { + changes = AHashMap::with_capacity(hint); + } else { + changes = AHashMap::new(); + } + + while let Some(ty) = map.next_key::>()? { + if ty.rm { + // Skips a dummy value. fastnbt does not support Unit values. + let _: () = map.next_value()?; + changes.insert(CompTyCell(ty.ty), None); + } else { + struct Seed<'a>(&'a SerdeCodec<'a>); + impl<'de, 'a> DeserializeSeed<'de> for Seed<'a> { + type Value = Box>; + + fn deserialize( + self, + deserializer: D, + ) -> Result + where + D: serde::Deserializer<'de>, + { + (self.0.de)(&mut >::erase( + deserializer, + )) + .map_err(serde::de::Error::custom) + } + } + changes.insert( + CompTyCell(ty.ty), + Some(map.next_value_seed(Seed( + ty.ty.f.serde_codec.expect("missing serde codec"), + ))?), + ); + } + } + + Ok(changes) + } + } + + deserializer + .deserialize_map(Visitor(PhantomData)) + .map(|changed| ComponentChanges { + ser_count: changed.len(), + changed: Maybe::Owned(SimpleOwned(changed)), + }) + } } /// Builder for [`ComponentChanges`]. @@ -38,6 +198,7 @@ where Cx: ProvideIdTy, { changes: AHashMap, Option>>>, + ser_count: usize, } impl<'a, Cx> Builder<'a, Cx> @@ -61,6 +222,9 @@ where std::any::type_name::() ); self.changes.insert(CompTyCell(ty), Some(Box::new(value))); + if ty.is_serializable() { + self.ser_count += 1; + } } /// Inserts a component type with an empty value. @@ -74,6 +238,7 @@ where pub fn build<'cow>(self) -> ComponentChanges<'a, 'cow, Cx> { ComponentChanges { changed: Maybe::Owned(SimpleOwned(self.changes)), + ser_count: self.ser_count, } } } diff --git a/crates/core/component/src/map.rs b/crates/core/component/src/map.rs index f50cb919..855b0e79 100644 --- a/crates/core/component/src/map.rs +++ b/crates/core/component/src/map.rs @@ -332,6 +332,10 @@ where if let MapInner::Patched { changes, .. } = &self.0 { Some(ComponentChanges { changed: Maybe::Borrowed(changes), + ser_count: changes + .iter() + .filter(|(cell, _)| cell.0.is_serializable()) + .count(), }) } else { None From ff29d8d8e7e041963e3909e96b185a4d47918df4 Mon Sep 17 00:00:00 2001 From: JieningYu Date: Tue, 13 Aug 2024 18:24:52 +0800 Subject: [PATCH 4/6] done serde --- crates/core/component/src/changes.rs | 64 ++++++++- crates/core/component/src/lib.rs | 188 ++++++++++++++++++--------- crates/core/component/src/map.rs | 4 +- 3 files changed, 190 insertions(+), 66 deletions(-) diff --git a/crates/core/component/src/changes.rs b/crates/core/component/src/changes.rs index 70e299a5..a0978264 100644 --- a/crates/core/component/src/changes.rs +++ b/crates/core/component/src/changes.rs @@ -3,6 +3,8 @@ use std::{cell::UnsafeCell, fmt::Debug, marker::PhantomData, str::FromStr, sync::OnceLock}; use ahash::AHashMap; +use bytes::{Buf, BufMut}; +use edcode2::{BufExt as _, BufMutExt as _, Decode, Encode}; use rimecraft_global_cx::ProvideIdTy; use rimecraft_maybe::{Maybe, SimpleOwned}; use rimecraft_registry::{ProvideRegistry, Reg}; @@ -10,7 +12,7 @@ use serde::{de::DeserializeSeed, ser::SerializeMap, Deserialize, Serialize}; use crate::{ map::CompTyCell, ComponentType, ErasedComponentType, Object, RawErasedComponentType, - SerdeCodec, UnsafeDebugIter, + UnsafeDebugIter, UnsafeSerdeCodec, }; /// Changes of components. @@ -80,7 +82,7 @@ where for (&CompTyCell(ty), obj) in self.changed.iter().filter(|(k, _)| k.0.is_serializable()) { struct Ser<'a, 's> { obj: &'s Object<'a>, - codec: &'a SerdeCodec<'a>, + codec: &'a UnsafeSerdeCodec<'a>, } impl Serialize for Ser<'_, '_> { @@ -153,7 +155,7 @@ where let _: () = map.next_value()?; changes.insert(CompTyCell(ty.ty), None); } else { - struct Seed<'a>(&'a SerdeCodec<'a>); + struct Seed<'a>(&'a UnsafeSerdeCodec<'a>); impl<'de, 'a> DeserializeSeed<'de> for Seed<'a> { type Value = Box>; @@ -192,6 +194,62 @@ where } } +impl Encode for ComponentChanges<'_, '_, Cx> +where + Cx: ProvideIdTy, + B: BufMut, +{ + fn encode(&self, mut buf: B) -> Result<(), edcode2::BoxedError<'static>> { + let present = self.changed.values().filter(|val| val.is_some()).count() as u32; + buf.put_variable(present); + buf.put_variable(self.changed.len() as u32 - present); + + for (&CompTyCell(ty), val) in self.changed.iter() { + if let Some(val) = val { + buf.put_variable(1); + ty.encode(&mut buf)?; + (ty.f.packet_codec.encode)(&**val, &mut buf)?; + } + } + for (&CompTyCell(ty), val) in self.changed.iter() { + if val.is_none() { + ty.encode(&mut buf)?; + } + } + + Ok(()) + } +} + +impl<'a: 'de, 'de, Cx, B> Decode<'de, B> for ComponentChanges<'a, '_, Cx> +where + Cx: ProvideIdTy Decode<'de, &'b mut B>> + + ProvideRegistry<'a, Cx::Id, RawErasedComponentType<'a, Cx>>, + B: Buf, +{ + fn decode(mut buf: B) -> Result> { + let present = buf.get_variable::(); + let absent = buf.get_variable::(); + let len = (present + absent) as usize; + + let mut changed = AHashMap::with_capacity(len); + for _ in 0..present { + let ty = ErasedComponentType::decode(&mut buf)?; + let obj = (ty.f.packet_codec.decode)(&mut buf)?; + changed.insert(CompTyCell(ty), Some(obj)); + } + for _ in 0..absent { + let ty = ErasedComponentType::decode(&mut buf)?; + changed.insert(CompTyCell(ty), None); + } + + Ok(ComponentChanges { + ser_count: changed.keys().filter(|k| k.0.is_serializable()).count(), + changed: Maybe::Owned(SimpleOwned(changed)), + }) + } +} + /// Builder for [`ComponentChanges`]. pub struct Builder<'a, Cx> where diff --git a/crates/core/component/src/lib.rs b/crates/core/component/src/lib.rs index 37d45a6e..1e4d9abf 100644 --- a/crates/core/component/src/lib.rs +++ b/crates/core/component/src/lib.rs @@ -4,7 +4,10 @@ use std::{any::TypeId, cell::UnsafeCell, fmt::Debug, hash::Hash, marker::Phantom use bytes::{Buf, BufMut}; use edcode2::{Decode, Encode}; -use rimecraft_global_cx::ProvideIdTy; +use rimecraft_global_cx::{ + nbt_edcode::{ReadNbt, UpdateNbt, WriteNbt}, + ProvideIdTy, +}; use rimecraft_registry::{ProvideRegistry, Reg}; use serde::{de::DeserializeOwned, Serialize}; @@ -50,75 +53,125 @@ where }; } -impl<'a, T> ComponentType<'a, T> +/// Creates a new [`PacketCodec`] by encoding and decoding through `edcode2`. +pub const fn packet_codec_edcode<'a, T>() -> PacketCodec<'a, T> where - T: for<'b> Encode<&'b dyn BufMut> + for<'b> Decode<'static, &'b dyn Buf> + Send + Sync + 'a, + T: for<'b> Encode<&'b mut dyn BufMut> + + for<'b> Decode<'static, &'b mut dyn Buf> + + Send + + Sync + + 'a, { - /// Codec for packet encoding and decoding. - 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, - "non-in-place decoding is not supported for this type", - ); - |buf| Ok(Box::new(T::decode(buf)?)) + PacketCodec { + codec: UnsafePacketCodec { + encode: |obj, buf| unsafe { &*(obj as *const Object<'_> as *const T) }.encode(buf), + decode: { + assert!( + >::SUPPORT_NON_IN_PLACE, + "non-in-place decoding is not supported for this type", + ); + |buf| Ok(Box::new(T::decode(buf)?)) + }, + upd: |obj, buf| { + unsafe { &mut *(obj as *mut Object<'_> as *mut T) }.decode_in_place(buf) + }, }, - upd: |obj, buf| unsafe { &mut *(obj as *mut Object<'_> as *mut T) }.decode_in_place(buf), - }; + _marker: PhantomData, + } } -impl<'a, T> ComponentType<'a, T> +/// Creates a new [`PacketCodec`] by NBT serialization. +pub const fn packet_codec_nbt<'a, T, Cx>() -> PacketCodec<'a, T> where - T: Clone + Eq + Send + Sync + 'a, + T: Send + Sync + 'a, + Cx: ReadNbt + for<'t> WriteNbt<&'t T>, { - /// Creates a new transient component type. - /// - /// Transient components are not serialized. - #[inline] - pub const fn transient(packet_codec: Option<&'a PacketCodec<'a>>) -> Self { - Self { - f: Funcs { - serde_codec: None, - packet_codec, - util: &Self::UTIL, + PacketCodec { + codec: UnsafePacketCodec { + encode: |obj, buf| { + Cx::write_nbt( + unsafe { &*(obj as *const Object<'_> as *const T) }, + buf.writer(), + ) + .map_err(Into::into) }, - _marker: PhantomData, - } + decode: |buf| Ok(Box::new(Cx::read_nbt(buf.reader())?)), + upd: |obj, buf| { + Cx::update_nbt( + unsafe { &mut *(obj as *mut Object<'_> as *mut T) }, + buf.reader(), + ) + .map_err(Into::into) + }, + }, + _marker: PhantomData, } } -impl<'a, T> ComponentType<'a, T> +/// Creates a new [`SerdeCodec`] by using `erased_serde`. +pub const fn serde_codec<'a, T>() -> SerdeCodec<'a, T> where - T: Clone + Eq + Serialize + DeserializeOwned + Send + Sync + 'a, + T: Serialize + DeserializeOwned + Send + Sync + 'a, { - 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); - v - }) - }, - upd: |obj, deserializer| { - *unsafe { &mut *(obj as *mut Object<'_> as *mut T) } = - erased_serde::deserialize::(deserializer)?; - Ok(()) + SerdeCodec { + codec: UnsafeSerdeCodec { + ser: |obj| unsafe { &*(obj as *const Object<'_> as *const T) }, + de: |deserializer| { + erased_serde::deserialize::(deserializer).map(|v| { + let v: Box> = Box::new(v); + v + }) + }, + upd: |obj, deserializer| { + *unsafe { &mut *(obj as *mut Object<'_> as *mut T) } = + erased_serde::deserialize::(deserializer)?; + Ok(()) + }, }, - }; + _marker: PhantomData, + } +} - /// Creates a new persistent component type. - /// - /// Persistent components are 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. - pub const fn persistent(packet_codec: Option<&'a PacketCodec<'a>>) -> Self { +/// Builder for creating a new [`ComponentType`]. +#[derive(Debug)] +pub struct TypeBuilder<'a, T, Cx> { + serde_codec: Option<&'a UnsafeSerdeCodec<'a>>, + packet_codec: Option<&'a UnsafePacketCodec<'a>>, + _marker: PhantomData<(T, Cx)>, +} + +impl<'a, T, Cx> TypeBuilder<'a, T, Cx> { + /// Applies the given serialization and deserialization codec. + pub const fn serde_codec(self, codec: &'a SerdeCodec<'a, T>) -> Self { + Self { + serde_codec: Some(&codec.codec), + ..self + } + } + + /// Applies the given packet encoding and decoding codec. + pub const fn packet_codec(self, codec: &'a PacketCodec<'a, T>) -> Self { Self { + packet_codec: Some(&codec.codec), + ..self + } + } +} + +impl<'a, T, Cx> TypeBuilder<'a, T, Cx> +where + T: Clone + Eq + Send + Sync + 'a, +{ + /// Builds a new [`ComponentType`] with the given codecs. + pub const fn build(self) -> ComponentType<'a, T> { + ComponentType { f: Funcs { - serde_codec: Some(&Self::SERDE_CODEC), - packet_codec, - util: &Self::UTIL, + serde_codec: self.serde_codec, + packet_codec: match self.packet_codec { + Some(codec) => codec, + None => panic!("packet codec is required"), + }, + util: &ComponentType::::UTIL, }, _marker: PhantomData, } @@ -145,7 +198,7 @@ where { #[inline] fn default() -> Self { - Self::transient(None) + todo!() } } @@ -168,21 +221,34 @@ pub struct RawErasedComponentType<'a, Cx> { _marker: PhantomData, } +/// Codec for serialization and deserialization. +#[derive(Debug, Clone, Copy)] +pub struct SerdeCodec<'a, T> { + codec: UnsafeSerdeCodec<'a>, + _marker: PhantomData, +} + #[derive(Debug, Clone, Copy)] #[allow(dead_code)] -struct SerdeCodec<'a> { +struct UnsafeSerdeCodec<'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)] +pub struct PacketCodec<'a, T> { + codec: UnsafePacketCodec<'a>, + _marker: PhantomData, +} + #[derive(Debug, Clone, Copy)] #[allow(dead_code)] -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>>, +struct UnsafePacketCodec<'a> { + encode: fn(&'_ Object<'a>, &'_ mut dyn BufMut) -> Result<(), edcode2::BoxedError<'static>>, + 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)] @@ -194,8 +260,8 @@ struct DynUtil<'a> { #[derive(Debug, Clone, Copy)] #[allow(dead_code)] struct Funcs<'a> { - serde_codec: Option<&'a SerdeCodec<'a>>, - packet_codec: Option<&'a PacketCodec<'a>>, + serde_codec: Option<&'a UnsafeSerdeCodec<'a>>, + packet_codec: &'a UnsafePacketCodec<'a>, util: &'a DynUtil<'a>, } diff --git a/crates/core/component/src/map.rs b/crates/core/component/src/map.rs index 855b0e79..10a8d6cc 100644 --- a/crates/core/component/src/map.rs +++ b/crates/core/component/src/map.rs @@ -13,7 +13,7 @@ use serde::{Deserialize, Serialize}; use crate::{ changes::ComponentChanges, dyn_any, ComponentType, ErasedComponentType, Object, - RawErasedComponentType, SerdeCodec, UnsafeDebugIter, + RawErasedComponentType, UnsafeSerdeCodec, UnsafeDebugIter, }; #[repr(transparent)] @@ -619,7 +619,7 @@ where } else { AHashMap::new() }; - struct DeSeed<'a, Cx>(&'a SerdeCodec<'a>, PhantomData); + struct DeSeed<'a, Cx>(&'a UnsafeSerdeCodec<'a>, PhantomData); impl<'a, 'de, Cx> serde::de::DeserializeSeed<'de> for DeSeed<'a, Cx> where From 5330da20f560ccc5637bafa9a349410f80810e69 Mon Sep 17 00:00:00 2001 From: JieningYu Date: Tue, 13 Aug 2024 18:28:33 +0800 Subject: [PATCH 5/6] fix --- crates/core/component/src/lib.rs | 18 ++---------------- crates/core/global-cx/src/lib.rs | 2 +- 2 files changed, 3 insertions(+), 17 deletions(-) diff --git a/crates/core/component/src/lib.rs b/crates/core/component/src/lib.rs index 1e4d9abf..4ed654dc 100644 --- a/crates/core/component/src/lib.rs +++ b/crates/core/component/src/lib.rs @@ -56,18 +56,14 @@ where /// Creates a new [`PacketCodec`] by encoding and decoding through `edcode2`. pub const fn packet_codec_edcode<'a, T>() -> PacketCodec<'a, T> where - T: for<'b> Encode<&'b mut dyn BufMut> - + for<'b> Decode<'static, &'b mut dyn Buf> - + Send - + Sync - + 'a, + T: for<'b> Encode<&'b mut dyn BufMut> + for<'b> Decode<'a, &'b mut dyn Buf> + Send + Sync + 'a, { PacketCodec { codec: UnsafePacketCodec { encode: |obj, buf| unsafe { &*(obj as *const Object<'_> as *const T) }.encode(buf), decode: { assert!( - >::SUPPORT_NON_IN_PLACE, + >::SUPPORT_NON_IN_PLACE, "non-in-place decoding is not supported for this type", ); |buf| Ok(Box::new(T::decode(buf)?)) @@ -192,16 +188,6 @@ impl PartialEq for ComponentType<'_, T> { } } -impl<'a, T> Default for ComponentType<'a, T> -where - T: Clone + Eq + Send + Sync + 'a, -{ - #[inline] - fn default() -> Self { - todo!() - } -} - impl Copy for ComponentType<'_, T> {} impl Clone for ComponentType<'_, T> { diff --git a/crates/core/global-cx/src/lib.rs b/crates/core/global-cx/src/lib.rs index 6e2059a0..65b0eed1 100644 --- a/crates/core/global-cx/src/lib.rs +++ b/crates/core/global-cx/src/lib.rs @@ -42,7 +42,7 @@ pub trait ProvideNbtTy: GlobalContext { /// [`i64`] array type. type LongArray: Into> + From>; - /// Function that converts a `Compound` to a [`Deserializer`]. + /// Function that converts a `Compound` to a `Deserializer`. fn compound_to_deserializer(compound: &Self::Compound) -> impl serde::Deserializer<'_>; } From 45d94a75bb9b6d038429e576914135bb538120d1 Mon Sep 17 00:00:00 2001 From: JieningYu Date: Tue, 13 Aug 2024 19:22:36 +0800 Subject: [PATCH 6/6] 0u32->0u8 --- crates/core/component/src/changes.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/core/component/src/changes.rs b/crates/core/component/src/changes.rs index a0978264..ff2b14f7 100644 --- a/crates/core/component/src/changes.rs +++ b/crates/core/component/src/changes.rs @@ -104,7 +104,7 @@ where map.serialize_key(&ty)?; if obj.is_none() { // Dummy value. fastnbt does not support Unit values. - map.serialize_value(&0u32)?; + map.serialize_value(&0u8)?; } else { map.serialize_value(&Ser { obj: obj.as_ref().unwrap(),