diff --git a/.github/workflows/nalgebra-ci-build.yml b/.github/workflows/nalgebra-ci-build.yml index 8b96d264..9e500084 100644 --- a/.github/workflows/nalgebra-ci-build.yml +++ b/.github/workflows/nalgebra-ci-build.yml @@ -50,7 +50,7 @@ jobs: runs-on: ubuntu-latest steps: # Needed because the --all-features build which enables cuda support. - - uses: Jimver/cuda-toolkit@v0.2.4 + - uses: Jimver/cuda-toolkit@v0.2.8 - uses: actions/checkout@v2 - run: cargo build --all-features; - run: cargo build -p nalgebra-glm --all-features; @@ -123,9 +123,9 @@ jobs: build-cuda: runs-on: ubuntu-latest steps: - - uses: Jimver/cuda-toolkit@v0.2.4 + - uses: Jimver/cuda-toolkit@v0.2.8 with: - cuda: '11.2.2' + cuda: '11.5.0' - name: Install nightly-2021-12-04 uses: actions-rs/toolchain@v1 with: diff --git a/Cargo.toml b/Cargo.toml index 985a8918..9d0b1a7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,8 +54,8 @@ convert-glam022 = [ "glam022" ] ## `serde-serialize`. serde-serialize-no-std = [ "serde", "num-complex/serde" ] serde-serialize = [ "serde-serialize-no-std", "serde/std" ] -rkyv-serialize-no-std = [ "rkyv" ] -rkyv-serialize = [ "rkyv-serialize-no-std", "rkyv/std", "bytecheck" ] +rkyv-serialize-no-std = [ "rkyv/size_32" ] +rkyv-serialize = [ "rkyv-serialize-no-std", "rkyv/std", "rkyv/validation", "bytecheck" ] # Randomness ## To use rand in a #[no-std] environment, enable the @@ -82,7 +82,7 @@ alga = { version = "0.9", default-features = false, optional = true } 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 } -rkyv = { version = "~0.7.1", optional = true } +rkyv = { version = "0.7", default-features = false, optional = true } bytecheck = { version = "~0.6.1", optional = true } mint = { version = "0.5", optional = true } quickcheck = { version = "1", optional = true } @@ -137,4 +137,3 @@ lto = true [package.metadata.docs.rs] # Enable all the features when building the docs on docs.rs all-features = true - diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index d155cba7..5c165399 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -29,12 +29,16 @@ use std::mem; #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "ArrayStorage", + bound(archive = " + T: rkyv::Archive, + [[T; R]; C]: rkyv::Archive + ") + ) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] pub struct ArrayStorage(pub [[T; R]; C]); diff --git a/src/base/dimension.rs b/src/base/dimension.rs index 06697618..3d1de1ff 100644 --- a/src/base/dimension.rs +++ b/src/base/dimension.rs @@ -208,12 +208,10 @@ dim_ops!( #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive(as = "Self") )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] pub struct Const; diff --git a/src/base/matrix.rs b/src/base/matrix.rs index a263d761..700e2f02 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -11,6 +11,11 @@ use std::mem; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "rkyv-serialize-no-std")] +use super::rkyv_wrappers::CustomPhantom; +#[cfg(feature = "rkyv-serialize-no-std")] +use rkyv::{with::With, Archive, Archived}; + use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub, Field, SupersetOf}; use simba::simd::SimdPartialOrd; @@ -152,12 +157,17 @@ pub type MatrixCross = #[derive(Clone, Copy)] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Matrix", + bound(archive = " + T: Archive, + S: Archive, + With, CustomPhantom<(Archived, R, C)>>: Archive, R, C)>> + ") + ) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] pub struct Matrix { /// The data storage that contains all the matrix components. Disappointed? @@ -195,6 +205,7 @@ pub struct Matrix { // of the `RawStorage` trait. However, because we don't have // specialization, this is not possible because these `T, R, C` // allows us to desambiguate a lot of configurations. + #[cfg_attr(feature = "rkyv-serialize-no-std", with(CustomPhantom<(T::Archived, R, C)>))] _phantoms: PhantomData<(T, R, C)>, } diff --git a/src/base/mod.rs b/src/base/mod.rs index dfe7cc8d..4cbcff93 100644 --- a/src/base/mod.rs +++ b/src/base/mod.rs @@ -42,6 +42,9 @@ mod min_max; /// Mechanisms for working with values that may not be initialized. pub mod uninit; +#[cfg(feature = "rkyv-serialize-no-std")] +mod rkyv_wrappers; + pub use self::matrix::*; pub use self::norm::*; pub use self::scalar::*; diff --git a/src/base/rkyv_wrappers.rs b/src/base/rkyv_wrappers.rs new file mode 100644 index 00000000..ce178674 --- /dev/null +++ b/src/base/rkyv_wrappers.rs @@ -0,0 +1,46 @@ +//! Wrapper that allows changing the generic type of a PhantomData +//! +//! Copied from https://github.com/rkyv/rkyv_contrib (MIT-Apache2 licences) which isn’t published yet. + +use rkyv::{ + with::{ArchiveWith, DeserializeWith, SerializeWith}, + Fallible, +}; +use std::marker::PhantomData; + +/// A wrapper that allows for changing the generic type of a PhantomData. +pub struct CustomPhantom { + _data: PhantomData<*const NT>, +} + +impl ArchiveWith> for CustomPhantom { + type Archived = PhantomData; + type Resolver = (); + + #[inline] + unsafe fn resolve_with( + _: &PhantomData, + _: usize, + _: Self::Resolver, + _: *mut Self::Archived, + ) { + } +} + +impl SerializeWith, S> + for CustomPhantom +{ + #[inline] + fn serialize_with(_: &PhantomData, _: &mut S) -> Result { + Ok(()) + } +} + +impl + DeserializeWith, PhantomData, D> for CustomPhantom +{ + #[inline] + fn deserialize_with(_: &PhantomData, _: &mut D) -> Result, D::Error> { + Ok(PhantomData) + } +} diff --git a/src/base/unit.rs b/src/base/unit.rs index 1596b71a..2fc51107 100644 --- a/src/base/unit.rs +++ b/src/base/unit.rs @@ -23,12 +23,15 @@ use crate::{Dim, Matrix, OMatrix, RealField, Scalar, SimdComplexField, SimdRealF #[derive(Clone, Hash, Copy)] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Unit", + bound(archive = " + T: rkyv::Archive, + ") + ) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] // #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] pub struct Unit { pub(crate) value: T, diff --git a/src/geometry/dual_quaternion.rs b/src/geometry/dual_quaternion.rs index 3b283629..bae04f46 100644 --- a/src/geometry/dual_quaternion.rs +++ b/src/geometry/dual_quaternion.rs @@ -42,12 +42,16 @@ use simba::scalar::{ClosedNeg, RealField}; #[derive(Debug, Copy, Clone)] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "DualQuaternion", + bound(archive = " + T: rkyv::Archive, + Quaternion: rkyv::Archive> + ") + ) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] pub struct DualQuaternion { /// The real component of the quaternion diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index ff7c7502..e3f44075 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -21,7 +21,7 @@ use crate::geometry::{AbstractRotation, Point, Translation}; /// A 2D isometry is composed of: /// - A translation part of type [`Translation2`](crate::Translation2) /// - A rotation part which can either be a [`UnitComplex`](crate::UnitComplex) or a [`Rotation2`](crate::Rotation2). -/// +/// /// A 3D isometry is composed of: /// - A translation part of type [`Translation3`](crate::Translation3) /// - A rotation part which can either be a [`UnitQuaternion`](crate::UnitQuaternion) or a [`Rotation3`](crate::Rotation3). @@ -67,13 +67,18 @@ use crate::geometry::{AbstractRotation, Point, Translation}; Owned>: Deserialize<'de>, T: Scalar")) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Isometry", + bound(archive = " + T: rkyv::Archive, + R: rkyv::Archive, + Translation: rkyv::Archive> + ") + ) )] pub struct Isometry { /// The pure rotational part of this isometry. diff --git a/src/geometry/orthographic.rs b/src/geometry/orthographic.rs index ede7f587..06d0b471 100644 --- a/src/geometry/orthographic.rs +++ b/src/geometry/orthographic.rs @@ -21,12 +21,16 @@ use crate::geometry::{Point3, Projective3}; #[repr(C)] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Orthographic3", + bound(archive = " + T: rkyv::Archive, + Matrix4: rkyv::Archive> + ") + ) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(Copy, Clone)] pub struct Orthographic3 { diff --git a/src/geometry/perspective.rs b/src/geometry/perspective.rs index de29747f..a5fc19a8 100644 --- a/src/geometry/perspective.rs +++ b/src/geometry/perspective.rs @@ -22,12 +22,16 @@ use crate::geometry::{Point3, Projective3}; #[repr(C)] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Perspective3", + bound(archive = " + T: rkyv::Archive, + Matrix4: rkyv::Archive> + ") + ) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(Copy, Clone)] pub struct Perspective3 { diff --git a/src/geometry/point.rs b/src/geometry/point.rs index 3dd54b98..71ace3a9 100644 --- a/src/geometry/point.rs +++ b/src/geometry/point.rs @@ -36,13 +36,19 @@ use std::mem::MaybeUninit; /// of said transformations for details. #[repr(C)] #[derive(Clone)] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "OPoint", + bound(archive = " + T: rkyv::Archive, + T::Archived: Scalar, + OVector: rkyv::Archive>, + DefaultAllocator: Allocator, + ") + ) )] pub struct OPoint where diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 34eda897..1b251b29 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -25,12 +25,16 @@ use crate::geometry::{Point3, Rotation}; #[derive(Copy, Clone)] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Quaternion", + bound(archive = " + T: rkyv::Archive, + Vector4: rkyv::Archive> + ") + ) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] pub struct Quaternion { /// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order. diff --git a/src/geometry/rotation.rs b/src/geometry/rotation.rs index 79f14eda..5eceec21 100755 --- a/src/geometry/rotation.rs +++ b/src/geometry/rotation.rs @@ -51,12 +51,16 @@ use crate::geometry::Point; #[repr(C)] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Rotation", + bound(archive = " + T: rkyv::Archive, + SMatrix: rkyv::Archive> + ") + ) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(Copy, Clone)] pub struct Rotation { diff --git a/src/geometry/scale.rs b/src/geometry/scale.rs index e6c46e47..36a68066 100755 --- a/src/geometry/scale.rs +++ b/src/geometry/scale.rs @@ -19,12 +19,16 @@ use crate::geometry::Point; #[repr(C)] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Scale", + bound(archive = " + T: rkyv::Archive, + SVector: rkyv::Archive> + ") + ) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(Copy, Clone)] pub struct Scale { diff --git a/src/geometry/similarity.rs b/src/geometry/similarity.rs index 763f1db9..989b721b 100755 --- a/src/geometry/similarity.rs +++ b/src/geometry/similarity.rs @@ -34,13 +34,18 @@ use crate::geometry::{AbstractRotation, Isometry, Point, Translation}; DefaultAllocator: Allocator>, Owned>: Deserialize<'de>")) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Similarity", + bound(archive = " + T: rkyv::Archive, + R: rkyv::Archive, + Isometry: rkyv::Archive> + ") + ) )] pub struct Similarity { /// The part of this similarity that does not include the scaling factor. diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs index 482d45ed..39fae3b6 100755 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -19,12 +19,16 @@ use crate::geometry::Point; #[repr(C)] #[cfg_attr( feature = "rkyv-serialize-no-std", - derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize) -)] -#[cfg_attr( - feature = "rkyv-serialize", - archive_attr(derive(bytecheck::CheckBytes)) + derive(rkyv::Archive, rkyv::Serialize, rkyv::Deserialize), + archive( + as = "Translation", + bound(archive = " + T: rkyv::Archive, + SVector: rkyv::Archive> + ") + ) )] +#[cfg_attr(feature = "rkyv-serialize", derive(bytecheck::CheckBytes))] #[cfg_attr(feature = "cuda", derive(cust_core::DeviceCopy))] #[derive(Copy, Clone)] pub struct Translation { diff --git a/src/lib.rs b/src/lib.rs index e3e6b66b..93f05ff5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -83,14 +83,12 @@ an optimized set of tools for computer graphics and physics. Those features incl unused_variables, unused_mut, unused_parens, - unused_qualifications, rust_2018_idioms, rust_2018_compatibility, future_incompatible, missing_copy_implementations )] -#![cfg_attr(feature = "rkyv-serialize-no-std", warn(unused_results))] // TODO: deny this once bytecheck stops generating warnings. -#![cfg_attr(not(feature = "rkyv-serialize-no-std"), deny(unused_results))] +#![cfg_attr(not(feature = "rkyv-serialize-no-std"), deny(unused_results))] // TODO: deny this globally once bytecheck stops generating unused results. #![doc( html_favicon_url = "https://nalgebra.org/img/favicon.ico", html_root_url = "https://docs.rs/nalgebra/0.25.0" diff --git a/tests/core/rkyv.rs b/tests/core/rkyv.rs index b89f5211..ffe9ed30 100644 --- a/tests/core/rkyv.rs +++ b/tests/core/rkyv.rs @@ -1,44 +1,62 @@ +#![cfg(feature = "rkyv-serialize")] + use na::{ Isometry3, IsometryMatrix2, IsometryMatrix3, Matrix3x4, Point2, Point3, Quaternion, Rotation2, Rotation3, Similarity3, SimilarityMatrix2, SimilarityMatrix3, Translation2, Translation3, }; -use rkyv::ser::{serializers::AllocSerializer, Serializer}; +use rand; +use rkyv::{Deserialize, Infallible}; -macro_rules! test_rkyv( +macro_rules! test_rkyv_same_type( ($($test: ident, $ty: ident);* $(;)*) => {$( #[test] fn $test() { - let v: $ty = rand::random(); - // serialize - let mut serializer = AllocSerializer::<0>::default(); - serializer.serialize_value(&v).unwrap(); - let serialized = serializer.into_serializer().into_inner(); + let value: $ty = rand::random(); + let bytes = rkyv::to_bytes::<_, 256>(&value).unwrap(); - let deserialized: $ty = unsafe { rkyv::from_bytes_unchecked(&serialized).unwrap() }; - assert_eq!(v, deserialized); + let archived = rkyv::check_archived_root::<$ty>(&bytes[..]).unwrap(); + // Compare archived and non-archived + assert_eq!(archived, &value); - #[cfg(feature = "rkyv-safe-deser")] - { - let deserialized: $ty = rkyv::from_bytes(&serialized).unwrap(); - assert_eq!(v, deserialized); - } + // Make sure Debug implementations are the same for Archived and non-Archived versions. + assert_eq!(format!("{:?}", value), format!("{:?}", archived)); + } + )*} +); +macro_rules! test_rkyv_diff_type( + ($($test: ident, $ty: ident);* $(;)*) => {$( + #[test] + fn $test() { + let value: $ty = Default::default(); + let bytes = rkyv::to_bytes::<_, 256>(&value).unwrap(); + + let archived = rkyv::check_archived_root::<$ty>(&bytes[..]).unwrap(); + let deserialized: $ty = archived.deserialize(&mut Infallible).unwrap(); + assert_eq!(deserialized, value); } )*} ); -test_rkyv!( - rkyv_matrix3x4, Matrix3x4; - rkyv_point3, Point3; - rkyv_translation3, Translation3; - rkyv_rotation3, Rotation3; - rkyv_isometry3, Isometry3; - rkyv_isometry_matrix3, IsometryMatrix3; - rkyv_similarity3, Similarity3; - rkyv_similarity_matrix3, SimilarityMatrix3; - rkyv_quaternion, Quaternion; - rkyv_point2, Point2; - rkyv_translation2, Translation2; - rkyv_rotation2, Rotation2; - rkyv_isometry_matrix2, IsometryMatrix2; - rkyv_similarity_matrix2, SimilarityMatrix2; +// Tests to make sure +test_rkyv_same_type!( + rkyv_same_type_matrix3x4, Matrix3x4; + rkyv_same_type_point3, Point3; + rkyv_same_type_translation3, Translation3; + rkyv_same_type_rotation3, Rotation3; + rkyv_same_type_isometry3, Isometry3; + rkyv_same_type_isometry_matrix3, IsometryMatrix3; + rkyv_same_type_similarity3, Similarity3; + rkyv_same_type_similarity_matrix3, SimilarityMatrix3; + rkyv_same_type_quaternion, Quaternion; + rkyv_same_type_point2, Point2; + rkyv_same_type_translation2, Translation2; + rkyv_same_type_rotation2, Rotation2; + // rkyv_same_type_isometry2, Isometry2; + rkyv_same_type_isometry_matrix2, IsometryMatrix2; + // rkyv_same_type_similarity2, Similarity2; + rkyv_same_type_similarity_matrix2, SimilarityMatrix2; ); + +test_rkyv_diff_type! { + rkyv_diff_type_matrix3x4, Matrix3x4; +}