Skip to content

Commit

Permalink
Add support for the glam crate (#13)
Browse files Browse the repository at this point in the history
Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
  • Loading branch information
h3r2tic and emilk committed Jan 18, 2022
1 parent 07638a7 commit cd50cc6
Show file tree
Hide file tree
Showing 3 changed files with 291 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -15,6 +15,7 @@ edition = "2018"
[dependencies]
speedy-derive = { version = "= 0.8.0", path = "speedy-derive", optional = true }
chrono = { version = "0.4", optional = true }
glam = { version = ">= 0.15, <= 0.20", optional = true }
smallvec = { version = "1", optional = true }
regex = { version = "1", optional = true, default-features = false }

Expand Down
287 changes: 287 additions & 0 deletions src/ext_glam.rs
@@ -0,0 +1,287 @@
use {
crate::{Context, Readable, Reader, Writable, Writer},
glam::{
Affine2, Affine3A, BVec2, BVec3, BVec4, DAffine2, DAffine3, DMat2, DMat3, DMat4, DQuat,
DVec2, DVec3, DVec4, IVec2, IVec3, IVec4, Mat2, Mat3, Mat3A, Mat4, Quat, UVec2, UVec3,
UVec4, Vec2, Vec3, Vec3A, Vec4,
},
};

macro_rules! impl_for_vec {
($T:ty, $ctor:ident, $comp_ty:ty, $comp_read_fn:ident, $comp_write_fn:ident, $($comp:ident),+) => {
impl<'a, C> Readable<'a, C> for $T
where
C: Context,
{
#[inline]
fn read_from<R: Reader<'a, C>>(reader: &mut R) -> Result<Self, C::Error> {
$(
let $comp = reader.$comp_read_fn()?;
)+

Ok(<$T>::$ctor($($comp),+))
}

#[inline]
fn minimum_bytes_needed() -> usize {
let mut size = 0;
$(
let $comp = <$comp_ty as Readable::<'a, C>>::minimum_bytes_needed();
size += $comp;
)+
size
}
}

impl<C> Writable<C> for $T
where
C: Context,
{
#[inline]
fn write_to<T: ?Sized + Writer<C>>(&self, writer: &mut T) -> Result<(), C::Error> {
$(
writer.$comp_write_fn(self.$comp)?;
)+

Ok(())
}

#[inline]
fn bytes_needed(&self) -> Result<usize, C::Error> {
let mut size = 0;
$(
size += Writable::<C>::bytes_needed(&self.$comp)?;
)+
Ok( size )
}
}
};
}

impl_for_vec! {Vec2, new, f32, read_f32, write_f32, x, y}
impl_for_vec! {Vec3, new, f32, read_f32, write_f32, x, y, z}
impl_for_vec! {Vec3A, new, f32, read_f32, write_f32, x, y, z}
impl_for_vec! {Vec4, new, f32, read_f32, write_f32, x, y, z, w}

impl_for_vec! {DVec2, new, f64, read_f64, write_f64, x, y}
impl_for_vec! {DVec3, new, f64, read_f64, write_f64, x, y, z}
impl_for_vec! {DVec4, new, f64, read_f64, write_f64, x, y, z, w}

impl_for_vec! {IVec2, new, i32, read_i32, write_i32, x, y}
impl_for_vec! {IVec3, new, i32, read_i32, write_i32, x, y, z}
impl_for_vec! {IVec4, new, i32, read_i32, write_i32, x, y, z, w}

impl_for_vec! {UVec2, new, u32, read_u32, write_u32, x, y}
impl_for_vec! {UVec3, new, u32, read_u32, write_u32, x, y, z}
impl_for_vec! {UVec4, new, u32, read_u32, write_u32, x, y, z, w}

impl_for_vec! {Quat, from_xyzw, f32, read_f32, write_f32, x, y, z, w}
impl_for_vec! {DQuat, from_xyzw, f64, read_f64, write_f64, x, y, z, w}

macro_rules! impl_for_bvec {
($T:ty, $($comp:ident),+) => {
impl<'a, C> Readable<'a, C> for $T
where
C: Context,
{
#[inline]
#[allow(unused_assignments)]
fn read_from<R: Reader<'a, C>>(reader: &mut R) -> Result<Self, C::Error> {
let mask = reader.read_u8()?;
let mut shift = 0;

$(
let $comp = (mask & (1 << shift)) != 0;
shift += 1;
)+

Ok(<$T>::new($($comp),+))
}

#[inline]
fn minimum_bytes_needed() -> usize {
<u8 as Readable::<'a, C>>::minimum_bytes_needed()
}
}

impl<C> Writable<C> for $T
where
C: Context,
{
#[inline]
fn write_to<T: ?Sized + Writer<C>>(&self, writer: &mut T) -> Result<(), C::Error> {
writer.write_u8(self.bitmask() as u8)
}

#[inline]
fn bytes_needed(&self) -> Result<usize, C::Error> {
Writable::<C>::bytes_needed(&0u8)
}
}
};
}

impl_for_bvec! {BVec2, x, y}
impl_for_bvec! {BVec3, x, y, z}
impl_for_bvec! {BVec4, x, y, z, w}

macro_rules! impl_for_mat {
($T:ty, $comp_count:literal, $comp_ty:ty) => {
impl<'a, C> Readable<'a, C> for $T
where
C: Context,
{
#[inline]
fn read_from<R: Reader<'a, C>>(reader: &mut R) -> Result<Self, C::Error> {
let mut values = [Default::default(); $comp_count];
for v in &mut values {
*v = reader.read_value()?;
}
Ok(<$T>::from_cols_array(&values))
}

#[inline]
fn minimum_bytes_needed() -> usize {
<$comp_ty as Readable<'a, C>>::minimum_bytes_needed() * $comp_count
}
}

impl<C> Writable<C> for $T
where
C: Context,
{
#[inline]
fn write_to<T: ?Sized + Writer<C>>(&self, writer: &mut T) -> Result<(), C::Error> {
for comp in self.to_cols_array().iter() {
writer.write_value(comp)?
}

Ok(())
}

#[inline]
fn bytes_needed(&self) -> Result<usize, C::Error> {
let mut size = 0;
for comp in self.to_cols_array().iter() {
size += Writable::<C>::bytes_needed(comp)?;
}
Ok(size)
}
}
};
}

impl_for_mat! { Mat2, 4, f32 }
impl_for_mat! { Mat3, 9, f32 }
impl_for_mat! { Mat3A, 9, f32 }
impl_for_mat! { Mat4, 16, f32 }

impl_for_mat! { DMat2, 4, f64 }
impl_for_mat! { DMat3, 9, f64 }
impl_for_mat! { DMat4, 16, f64 }

impl_for_mat! { Affine2, 6, f32 }
impl_for_mat! { Affine3A, 12, f32 }

impl_for_mat! { DAffine2, 6, f64 }
impl_for_mat! { DAffine3, 12, f64 }

#[test]
fn test_glam() {
use crate::endianness::Endianness;

macro_rules! test_vec {
($T:ty, $ctor:ident, $($values:literal),+) => {{
let original = <$T>::$ctor($($values as _),+);
let serialized = original.write_to_vec_with_ctx(Endianness::NATIVE).unwrap();
let deserialized = <$T>::read_from_buffer_with_ctx(Endianness::NATIVE, &serialized).unwrap();
assert_eq!(original, deserialized);
}}
}

test_vec!(Vec2, new, 1, 2);
test_vec!(Vec3, new, 1, 2, 3);
test_vec!(Vec3A, new, 1, 2, 3);
test_vec!(Vec4, new, 1, 2, 3, 4);

test_vec!(DVec2, new, 1, 2);
test_vec!(DVec3, new, 1, 2, 3);
test_vec!(DVec4, new, 1, 2, 3, 4);

test_vec!(IVec2, new, 1, 2);
test_vec!(IVec3, new, 1, 2, 3);
test_vec!(IVec4, new, 1, 2, 3, 4);

test_vec!(UVec2, new, 1, 2);
test_vec!(UVec3, new, 1, 2, 3);
test_vec!(UVec4, new, 1, 2, 3, 4);

test_vec!(Quat, from_xyzw, 1, 2, 3, 4);
test_vec!(DQuat, from_xyzw, 1, 2, 3, 4);

for a in [false, true] {
for b in [false, true] {
let original = BVec2::new(a, b);
let serialized = original.write_to_vec_with_ctx(Endianness::NATIVE).unwrap();
let deserialized =
BVec2::read_from_buffer_with_ctx(Endianness::NATIVE, &serialized).unwrap();
assert_eq!(original, deserialized);
}
}

for a in [false, true] {
for b in [false, true] {
for c in [false, true] {
let original = BVec3::new(a, b, c);
let serialized = original.write_to_vec_with_ctx(Endianness::NATIVE).unwrap();
let deserialized =
BVec3::read_from_buffer_with_ctx(Endianness::NATIVE, &serialized).unwrap();
assert_eq!(original, deserialized);
}
}
}

for a in [false, true] {
for b in [false, true] {
for c in [false, true] {
for d in [false, true] {
let original = BVec4::new(a, b, c, d);
let serialized = original.write_to_vec_with_ctx(Endianness::NATIVE).unwrap();
let deserialized =
BVec4::read_from_buffer_with_ctx(Endianness::NATIVE, &serialized).unwrap();
assert_eq!(original, deserialized);
}
}
}
}

macro_rules! test_mat {
($T:ty) => {{
let mut cols = <$T>::IDENTITY.to_cols_array();
for (i, c) in cols.iter_mut().enumerate() {
*c = (i + 1) as _;
}

let original = <$T>::from_cols_array(&cols);
let serialized = original.write_to_vec_with_ctx(Endianness::NATIVE).unwrap();
let deserialized =
<$T>::read_from_buffer_with_ctx(Endianness::NATIVE, &serialized).unwrap();
assert_eq!(original, deserialized);
}};
}

test_mat!(Mat2);
test_mat!(Mat3);
test_mat!(Mat3A);
test_mat!(Mat4);

test_mat!(DMat2);
test_mat!(DMat3);
test_mat!(DMat4);

test_mat!(Affine2);
test_mat!(Affine3A);

test_mat!(DAffine2);
test_mat!(DAffine3);
}
3 changes: 3 additions & 0 deletions src/lib.rs
Expand Up @@ -17,6 +17,9 @@ mod circular_buffer;
#[cfg(feature = "chrono")]
mod ext_chrono;

#[cfg(feature = "glam")]
mod ext_glam;

#[cfg(feature = "smallvec")]
mod ext_smallvec;

Expand Down

0 comments on commit cd50cc6

Please sign in to comment.