diff --git a/Cargo.toml b/Cargo.toml index bfd3f166..f1d65128 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,8 @@ convert-bytemuck = [ "bytemuck" ] serde-serialize-no-std = [ "serde", "num-complex/serde" ] serde-serialize = [ "serde-serialize-no-std", "serde/std" ] abomonation-serialize = [ "abomonation" ] +rkyv-serialize-no-std = [ "rkyv" ] +rkyv-serialize = [ "rkyv-serialize-no-std", "rkyv/std" ] # Randomness ## To use rand in a #[no-std] environment, enable the @@ -74,6 +76,7 @@ rand_distr = { version = "0.4", default-features = false, optional = true } matrixmultiply = { version = "0.3", optional = true } serde = { version = "1.0", default-features = false, features = [ "derive" ], optional = true } abomonation = { version = "0.7", optional = true } +rkyv = { version = "~0.6.4", default-features = false, features = ["const_generics"], optional = true } mint = { version = "0.5", optional = true } glam = { version = "0.13", optional = true } quickcheck = { version = "1", optional = true } @@ -81,7 +84,7 @@ pest = { version = "2", optional = true } pest_derive = { version = "2", optional = true } bytemuck = { version = "1.5", optional = true } matrixcompare-core = { version = "0.1", optional = true } -proptest = { version = "1", optional = true, default-features = false, features = ["std"] } +proptest = { version = "1", optional = true, default-features = false, features = ["std"] } [dev-dependencies] serde_json = "1.0" diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index 68da4c51..6d681ed5 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -299,3 +299,45 @@ where self.as_slice().iter().fold(0, |acc, e| acc + e.extent()) } } + +#[cfg(feature = "rkyv-serialize-no-std")] +mod rkyv_impl { + use super::ArrayStorage; + use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; + + impl Archive for ArrayStorage { + type Archived = ArrayStorage; + type Resolver = <[[T; R]; C] as Archive>::Resolver; + + fn resolve( + &self, + pos: usize, + resolver: Self::Resolver, + out: &mut core::mem::MaybeUninit, + ) { + self.0.resolve( + pos + offset_of!(Self::Archived, 0), + resolver, + project_struct!(out: Self::Archived => 0), + ); + } + } + + impl, S: Fallible + ?Sized, const R: usize, const C: usize> Serialize + for ArrayStorage + { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(self.0.serialize(serializer)?) + } + } + + impl + Deserialize, D> for ArrayStorage + where + T::Archived: Deserialize, + { + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(ArrayStorage(self.0.deserialize(deserializer)?)) + } + } +} diff --git a/src/base/dimension.rs b/src/base/dimension.rs index dd87647d..2b5ccec3 100644 --- a/src/base/dimension.rs +++ b/src/base/dimension.rs @@ -231,6 +231,37 @@ impl<'de, const D: usize> Deserialize<'de> for Const { } } +#[cfg(feature = "rkyv-serialize-no-std")] +mod rkyv_impl { + use super::Const; + use rkyv::{Archive, Deserialize, Fallible, Serialize}; + + impl Archive for Const { + type Archived = Self; + type Resolver = (); + + fn resolve( + &self, + _: usize, + _: Self::Resolver, + _: &mut core::mem::MaybeUninit, + ) { + } + } + + impl Serialize for Const { + fn serialize(&self, _: &mut S) -> Result { + Ok(()) + } + } + + impl Deserialize for Const { + fn deserialize(&self, _: &mut D) -> Result { + Ok(Const) + } + } +} + pub trait ToConst { type Const: DimName; } diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 3cde8a4f..bc9942be 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -308,6 +308,53 @@ where { } +#[cfg(feature = "rkyv-serialize-no-std")] +mod rkyv_impl { + use super::Matrix; + use core::marker::PhantomData; + use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; + + impl Archive for Matrix { + type Archived = Matrix; + type Resolver = S::Resolver; + + fn resolve( + &self, + pos: usize, + resolver: Self::Resolver, + out: &mut core::mem::MaybeUninit, + ) { + self.data.resolve( + pos + offset_of!(Self::Archived, data), + resolver, + project_struct!(out: Self::Archived => data), + ); + } + } + + impl, _S: Fallible + ?Sized> Serialize<_S> + for Matrix + { + fn serialize(&self, serializer: &mut _S) -> Result { + Ok(self.data.serialize(serializer)?) + } + } + + impl + Deserialize, D> + for Matrix + where + S::Archived: Deserialize, + { + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(Matrix { + data: self.data.deserialize(deserializer)?, + _phantoms: PhantomData, + }) + } + } +} + impl Matrix { /// Creates a new matrix with the given data without statically checking that the matrix /// dimension matches the storage dimension. diff --git a/src/base/unit.rs b/src/base/unit.rs index c2e60da3..b5a4096f 100644 --- a/src/base/unit.rs +++ b/src/base/unit.rs @@ -71,6 +71,47 @@ impl Abomonation for Unit { } } +#[cfg(feature = "rkyv-serialize-no-std")] +mod rkyv_impl { + use super::Unit; + use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; + + impl Archive for Unit { + type Archived = Unit; + type Resolver = T::Resolver; + + fn resolve( + &self, + pos: usize, + resolver: Self::Resolver, + out: &mut ::core::mem::MaybeUninit, + ) { + self.value.resolve( + pos + offset_of!(Self::Archived, value), + resolver, + project_struct!(out: Self::Archived => value), + ); + } + } + + impl, S: Fallible + ?Sized> Serialize for Unit { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(self.value.serialize(serializer)?) + } + } + + impl Deserialize, D> for Unit + where + T::Archived: Deserialize, + { + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(Unit { + value: self.value.deserialize(deserializer)?, + }) + } + } +} + impl PartialEq for Unit> where T: Scalar + PartialEq, diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index c5fd844c..d307c393 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -98,6 +98,66 @@ where } } +#[cfg(feature = "rkyv-serialize-no-std")] +mod rkyv_impl { + use super::Isometry; + use crate::{base::Scalar, geometry::Translation}; + use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; + + impl Archive for Isometry + where + T::Archived: Scalar, + { + type Archived = Isometry; + type Resolver = (R::Resolver, as Archive>::Resolver); + + fn resolve( + &self, + pos: usize, + resolver: Self::Resolver, + out: &mut core::mem::MaybeUninit, + ) { + self.rotation.resolve( + pos + offset_of!(Self::Archived, rotation), + resolver.0, + project_struct!(out: Self::Archived => rotation), + ); + self.translation.resolve( + pos + offset_of!(Self::Archived, translation), + resolver.1, + project_struct!(out: Self::Archived => translation), + ); + } + } + + impl, R: Serialize, S: Fallible + ?Sized, const D: usize> + Serialize for Isometry + where + T::Archived: Scalar, + { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(( + self.rotation.serialize(serializer)?, + self.translation.serialize(serializer)?, + )) + } + } + + impl + Deserialize, _D> for Isometry + where + T::Archived: Scalar + Deserialize, + R::Archived: Scalar + Deserialize, + { + fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { + Ok(Isometry { + rotation: self.rotation.deserialize(deserializer)?, + translation: self.translation.deserialize(deserializer)?, + }) + } + } +} + impl hash::Hash for Isometry where Owned>: hash::Hash, diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 365095b8..6852335b 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -113,6 +113,48 @@ where } } +#[cfg(feature = "rkyv-serialize-no-std")] +mod rkyv_impl { + use super::Quaternion; + use crate::base::Vector4; + use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; + + impl Archive for Quaternion { + type Archived = Quaternion; + type Resolver = as Archive>::Resolver; + + fn resolve( + &self, + pos: usize, + resolver: Self::Resolver, + out: &mut core::mem::MaybeUninit, + ) { + self.coords.resolve( + pos + offset_of!(Self::Archived, coords), + resolver, + project_struct!(out: Self::Archived => coords), + ); + } + } + + impl, S: Fallible + ?Sized> Serialize for Quaternion { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(self.coords.serialize(serializer)?) + } + } + + impl Deserialize, D> for Quaternion + where + T::Archived: Deserialize, + { + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(Quaternion { + coords: self.coords.deserialize(deserializer)?, + }) + } + } +} + impl Quaternion where T::Element: SimdRealField, diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs index 1a8f4b04..dcb7b603 100755 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -97,6 +97,49 @@ where } } +#[cfg(feature = "rkyv-serialize-no-std")] +mod rkyv_impl { + use super::Translation; + use crate::base::SVector; + use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; + + impl Archive for Translation { + type Archived = Translation; + type Resolver = as Archive>::Resolver; + + fn resolve( + &self, + pos: usize, + resolver: Self::Resolver, + out: &mut core::mem::MaybeUninit, + ) { + self.vector.resolve( + pos + offset_of!(Self::Archived, vector), + resolver, + project_struct!(out: Self::Archived => vector), + ); + } + } + + impl, S: Fallible + ?Sized, const D: usize> Serialize for Translation { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(self.vector.serialize(serializer)?) + } + } + + impl Deserialize, _D> + for Translation + where + T::Archived: Deserialize, + { + fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { + Ok(Translation { + vector: self.vector.deserialize(deserializer)?, + }) + } + } +} + impl Translation { /// Creates a new translation from the given vector. #[inline]