Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 5 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,18 +16,17 @@ resolver = "2"
[features]
default = ["rkyv", "serde"]
glam-ext = ["dep:glam-ext"]
serde = ["dep:serde", "glam/serde", "bimap/serde" ]
rkyv = ["dep:rkyv", "dep:bytecheck", "glam/rkyv", "glam/bytecheck"]
serde = ["dep:serde", "glam/serde", "glam-ext/serde", "bimap/serde" ]
rkyv = ["dep:rkyv", "glam/rkyv", "glam/bytecheck", "glam-ext/rkyv"]
wasm = []
nodejs = ["wasm", "dep:js-sys", "dep:wasm-bindgen"]

[dependencies]
bimap = { version = "0.6" }
bytecheck = { version = "0.6", optional = true, default-features = false }
glam = { version = "0.29", features = [ "core-simd", "libm" ] }
glam-ext = { version = "0.2", optional = true, features = [ "core-simd", "libm" ] }
glam = { version = "0.30", features = [ "core-simd", "libm" ] }
glam-ext = { version = "0.3", optional = true, features = [ "core-simd", "libm" ] }
js-sys = { version = "0.3", optional = true }
rkyv = { version = "0.7", optional = true, features = [ "validation" ] }
rkyv = { version = "0.8", optional = true }
serde = { version= "1.0", optional = true, features = [ "serde_derive" ] }
static_assertions = "1.1"
thiserror = "1.0"
Expand Down
42 changes: 42 additions & 0 deletions src/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ pub enum OzzError {
#[error("Invalid version")]
InvalidVersion,

/// Invalid repr.
#[error("Invalid repr")]
InvalidRepr,

/// Unexcepted error.
#[error("Unexcepted error")]
Unexcepted,
Expand Down Expand Up @@ -80,6 +84,10 @@ impl OzzError {
matches!(self, OzzError::InvalidVersion)
}

pub fn is_invalid_repr(&self) -> bool {
matches!(self, OzzError::InvalidRepr)
}

pub fn is_unexcepted(&self) -> bool {
matches!(self, OzzError::Unexcepted)
}
Expand Down Expand Up @@ -446,3 +454,37 @@ pub type OzzArcBuf<T> = Arc<RwLock<Vec<T>>>;
pub fn ozz_arc_buf<T>(v: Vec<T>) -> OzzArcBuf<T> {
Arc::new(RwLock::new(v))
}

#[cfg(feature = "rkyv")]
pub(crate) trait SliceRkyvExt<T, D>
where
T: rkyv::Archive,
T::Archived: rkyv::Deserialize<T, D>,
D: rkyv::rancor::Fallible + ?Sized,
{
fn copy_from_deserialize(
&mut self,
deserializer: &mut D,
avec: &rkyv::vec::ArchivedVec<T::Archived>,
) -> Result<(), D::Error>;
}

impl<T, D> SliceRkyvExt<T, D> for [T]
where
T: rkyv::Archive,
T::Archived: rkyv::Deserialize<T, D>,
D: rkyv::rancor::Fallible + ?Sized,
{
#[inline(always)]
fn copy_from_deserialize(
&mut self,
deserializer: &mut D,
avec: &rkyv::vec::ArchivedVec<T::Archived>,
) -> Result<(), D::Error> {
use rkyv::Deserialize;
for (i, item) in avec.iter().enumerate() {
self[i] = item.deserialize(deserializer)?;
}
Ok(())
}
}
110 changes: 64 additions & 46 deletions src/math.rs
Original file line number Diff line number Diff line change
Expand Up @@ -178,17 +178,21 @@ impl SoaVec3 {

#[cfg(feature = "rkyv")]
const _: () = {
use bytecheck::CheckBytes;
use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
use std::io::{Error, ErrorKind};
use rkyv::bytecheck::CheckBytes;
use rkyv::rancor::{fail, Fallible, Source};
use rkyv::traits::NoUndef;
use rkyv::{Archive, Deserialize, Place, Portable, Serialize};

unsafe impl NoUndef for SoaVec3 {}
unsafe impl Portable for SoaVec3 {}

impl Archive for SoaVec3 {
type Archived = SoaVec3;
type Resolver = ();

#[inline]
unsafe fn resolve(&self, _: usize, _: Self::Resolver, out: *mut Self::Archived) {
out.write(to_archived!(*self as Self));
fn resolve(&self, _: Self::Resolver, out: Place<Self::Archived>) {
out.write(*self)
}
}

Expand All @@ -202,19 +206,21 @@ const _: () = {
impl<D: Fallible + ?Sized> Deserialize<SoaVec3, D> for SoaVec3 {
#[inline]
fn deserialize(&self, _: &mut D) -> Result<SoaVec3, D::Error> {
Ok(from_archived!(*self))
Ok(*self)
}
}

impl<C: ?Sized> CheckBytes<C> for SoaVec3 {
type Error = Error;

unsafe impl<C> CheckBytes<C> for SoaVec3
where
C: Fallible + ?Sized,
C::Error: Source,
{
#[inline]
unsafe fn check_bytes<'a>(value: *const Self, _: &mut C) -> Result<&'a Self, Self::Error> {
unsafe fn check_bytes(value: *const Self, _: &mut C) -> Result<(), C::Error> {
if value as usize % mem::align_of::<SoaVec3>() != 0 {
return Err(Error::new(ErrorKind::InvalidData, "must be aligned to 16 bytes"));
fail!(OzzError::InvalidRepr)
}
Ok(&*value)
Ok(())
}
}
};
Expand Down Expand Up @@ -417,17 +423,21 @@ impl SoaQuat {

#[cfg(feature = "rkyv")]
const _: () = {
use bytecheck::CheckBytes;
use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
use std::io::{Error, ErrorKind};
use rkyv::bytecheck::CheckBytes;
use rkyv::rancor::{fail, Fallible, Source};
use rkyv::traits::NoUndef;
use rkyv::{Archive, Deserialize, Place, Portable, Serialize};

unsafe impl NoUndef for SoaQuat {}
unsafe impl Portable for SoaQuat {}

impl Archive for SoaQuat {
type Archived = SoaQuat;
type Resolver = ();

#[inline]
unsafe fn resolve(&self, _: usize, _: Self::Resolver, out: *mut Self::Archived) {
out.write(to_archived!(*self as Self));
fn resolve(&self, _: Self::Resolver, out: Place<Self::Archived>) {
out.write(*self)
}
}

Expand All @@ -441,19 +451,21 @@ const _: () = {
impl<D: Fallible + ?Sized> Deserialize<SoaQuat, D> for SoaQuat {
#[inline]
fn deserialize(&self, _: &mut D) -> Result<SoaQuat, D::Error> {
Ok(from_archived!(*self))
Ok(*self)
}
}

impl<C: ?Sized> CheckBytes<C> for SoaQuat {
type Error = Error;

unsafe impl<C> CheckBytes<C> for SoaQuat
where
C: Fallible + ?Sized,
C::Error: Source,
{
#[inline]
unsafe fn check_bytes<'a>(value: *const Self, _: &mut C) -> Result<&'a Self, Self::Error> {
unsafe fn check_bytes(value: *const Self, _: &mut C) -> Result<(), C::Error> {
if value as usize % mem::align_of::<SoaQuat>() != 0 {
return Err(Error::new(ErrorKind::InvalidData, "must be aligned to 16 bytes"));
fail!(OzzError::InvalidRepr)
}
Ok(&*value)
Ok(())
}
}
};
Expand Down Expand Up @@ -555,17 +567,21 @@ impl SoaTransform {

#[cfg(feature = "rkyv")]
const _: () = {
use bytecheck::CheckBytes;
use rkyv::{from_archived, to_archived, Archive, Deserialize, Fallible, Serialize};
use std::io::{Error, ErrorKind};
use rkyv::bytecheck::CheckBytes;
use rkyv::rancor::{fail, Fallible, Source};
use rkyv::traits::NoUndef;
use rkyv::{Archive, Deserialize, Place, Portable, Serialize};

unsafe impl NoUndef for SoaTransform {}
unsafe impl Portable for SoaTransform {}

impl Archive for SoaTransform {
type Archived = SoaTransform;
type Resolver = ();

#[inline]
unsafe fn resolve(&self, _: usize, _: Self::Resolver, out: *mut Self::Archived) {
out.write(to_archived!(*self as Self));
fn resolve(&self, _: Self::Resolver, out: Place<Self::Archived>) {
out.write(*self)
}
}

Expand All @@ -579,19 +595,21 @@ const _: () = {
impl<D: Fallible + ?Sized> Deserialize<SoaTransform, D> for SoaTransform {
#[inline]
fn deserialize(&self, _: &mut D) -> Result<SoaTransform, D::Error> {
Ok(from_archived!(*self))
Ok(*self)
}
}

impl<C: ?Sized> CheckBytes<C> for SoaTransform {
type Error = Error;

unsafe impl<C> CheckBytes<C> for SoaTransform
where
C: Fallible + ?Sized,
C::Error: Source,
{
#[inline]
unsafe fn check_bytes<'a>(value: *const Self, _: &mut C) -> Result<&'a Self, Self::Error> {
unsafe fn check_bytes(value: *const Self, _: &mut C) -> Result<(), C::Error> {
if value as usize % mem::align_of::<SoaTransform>() != 0 {
return Err(Error::new(ErrorKind::InvalidData, "must be aligned to 16 bytes"));
fail!(OzzError::InvalidRepr)
}
Ok(&*value)
Ok(())
}
}
};
Expand Down Expand Up @@ -1542,31 +1560,31 @@ mod tests {
#[test]
#[wasm_bindgen_test]
fn test_rkyv() {
use rkyv::Deserialize;
use rkyv::rancor::{Error, Panic};

let vec3 = SoaVec3::splat_vec3(Vec3::new(2.0, 3.0, 4.0));
let bytes = rkyv::to_bytes::<_, 256>(&vec3).unwrap();
let archived = rkyv::check_archived_root::<SoaVec3>(&bytes[..]).unwrap();
let bytes = rkyv::to_bytes::<Error>(&vec3).unwrap();
let archived = rkyv::access::<SoaVec3, Error>(&bytes[..]).unwrap();
assert_eq!(archived, &vec3);
let vec3_de: SoaVec3 = archived.deserialize(&mut rkyv::Infallible).unwrap();
let vec3_de: SoaVec3 = rkyv::deserialize::<_, Panic>(archived).unwrap();
assert_eq!(vec3_de, vec3);

let quat = SoaQuat::splat_quat(Quat::from_xyzw(2.0, 3.0, 4.0, 5.0));
let bytes = rkyv::to_bytes::<_, 256>(&quat).unwrap();
let archived = rkyv::check_archived_root::<SoaQuat>(&bytes[..]).unwrap();
let bytes = rkyv::to_bytes::<Error>(&quat).unwrap();
let archived = rkyv::access::<SoaQuat, Error>(&bytes[..]).unwrap();
assert_eq!(archived, &quat);
let quat_de: SoaQuat = archived.deserialize(&mut rkyv::Infallible).unwrap();
let quat_de: SoaQuat = rkyv::deserialize::<_, Panic>(archived).unwrap();
assert_eq!(quat_de, quat);

let transform = SoaTransform::new(
SoaVec3::splat_vec3(Vec3::new(9.0, 8.0, 7.0)),
SoaQuat::splat_quat(Quat::from_xyzw(6.0, 5.0, 4.0, 3.0)),
SoaVec3::splat_vec3(Vec3::new(-1.0, -2.0, -3.0)),
);
let bytes = rkyv::to_bytes::<_, 256>(&transform).unwrap();
let archived = rkyv::check_archived_root::<SoaTransform>(&bytes[..]).unwrap();
let bytes = rkyv::to_bytes::<Error>(&transform).unwrap();
let archived = rkyv::access::<SoaTransform, Error>(&bytes[..]).unwrap();
assert_eq!(archived, &transform);
let transform_de: SoaTransform = archived.deserialize(&mut rkyv::Infallible).unwrap();
let transform_de: SoaTransform = rkyv::deserialize::<_, Panic>(archived).unwrap();
assert_eq!(transform_de, transform);
}

Expand Down
Loading