Merge branch 'aepsil0n-abomonation'

This commit is contained in:
Sébastien Crozet 2017-08-15 19:37:25 +02:00
commit 613abfc1b4
20 changed files with 300 additions and 10 deletions

View File

@ -23,9 +23,10 @@ script:
- cargo build --verbose - cargo build --verbose
- cargo build --verbose --features arbitrary - cargo build --verbose --features arbitrary
- cargo build --verbose --features serde-serialize - cargo build --verbose --features serde-serialize
- cargo test --verbose --features "arbitrary debug serde-serialize" - cargo build --verbose --features abomonation-serialize
- cargo test --verbose --features "arbitrary serde-serialize abomonation-serialize"
- cd nalgebra-lapack; cargo test --verbose - cd nalgebra-lapack; cargo test --verbose
env: env:
matrix: matrix:
- CARGO_FEATURE_SYSTEM_NETLIB=1 CARGO_FEATURE_EXCLUDE_LAPACKE=1 CARGO_FEATURE_EXCLUDE_CBLAS=1 - CARGO_FEATURE_SYSTEM_NETLIB=1 CARGO_FEATURE_EXCLUDE_LAPACKE=1 CARGO_FEATURE_EXCLUDE_CBLAS=1

View File

@ -18,6 +18,7 @@ path = "src/lib.rs"
[features] [features]
arbitrary = [ "quickcheck" ] arbitrary = [ "quickcheck" ]
serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ] serde-serialize = [ "serde", "serde_derive", "num-complex/serde" ]
abomonation-serialize = [ "abomonation" ]
debug = [ ] debug = [ ]
[dependencies] [dependencies]
@ -31,6 +32,7 @@ alga = "0.5"
matrixmultiply = "0.1" matrixmultiply = "0.1"
serde = { version = "1.0", optional = true } serde = { version = "1.0", optional = true }
serde_derive = { version = "1.0", optional = true } serde_derive = { version = "1.0", optional = true }
abomonation = { version = "0.4", optional = true }
[dependencies.quickcheck] [dependencies.quickcheck]
optional = true optional = true

View File

@ -2,10 +2,10 @@ all:
cargo check --features "debug arbitrary serde-serialize" cargo check --features "debug arbitrary serde-serialize"
doc: doc:
cargo doc --no-deps --features "debug arbitrary serde-serialize" cargo doc --no-deps --features "debug arbitrary serde-serialize abomonation"
bench: bench:
cargo bench cargo bench
test: test:
cargo test --features "debug arbitrary serde-serialize" cargo test --features "debug arbitrary serde-serialize abomonation-serialize"

View File

@ -11,6 +11,9 @@ use approx::ApproxEq;
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
use serde::{Serialize, Serializer, Deserialize, Deserializer}; use serde::{Serialize, Serializer, Deserialize, Deserializer};
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
use alga::general::{Ring, Real}; use alga::general::{Ring, Real};
use core::{Scalar, DefaultAllocator, Unit, VectorN, MatrixMN}; use core::{Scalar, DefaultAllocator, Unit, VectorN, MatrixMN};
@ -99,6 +102,21 @@ impl<'de, N, R, C, S> Deserialize<'de> for Matrix<N, R, C, S>
} }
} }
#[cfg(feature = "abomonation-serialize")]
impl<N: Scalar, R: Dim, C: Dim, S: Abomonation> Abomonation for Matrix<N, R, C, S> {
unsafe fn entomb(&self, writer: &mut Vec<u8>) {
self.data.entomb(writer)
}
unsafe fn embalm(&mut self) {
self.data.embalm()
}
unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
self.data.exhume(bytes)
}
}
impl<N: Scalar, R: Dim, C: Dim, S> Matrix<N, R, C, S> { impl<N: Scalar, R: Dim, C: Dim, S> Matrix<N, R, C, S> {
/// Creates a new matrix with the given data without statically checking that the matrix /// Creates a new matrix with the given data without statically checking that the matrix
/// dimension matches the storage dimension. /// dimension matches the storage dimension.

View File

@ -13,6 +13,9 @@ use std::mem;
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
use std::marker::PhantomData; use std::marker::PhantomData;
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
use typenum::Prod; use typenum::Prod;
use generic_array::{ArrayLength, GenericArray}; use generic_array::{ArrayLength, GenericArray};
@ -319,3 +322,36 @@ where N: Scalar + Deserialize<'a>,
} }
} }
} }
#[cfg(feature = "abomonation-serialize")]
impl<N, R, C> Abomonation for MatrixArray<N, R, C>
where R: DimName,
C: DimName,
R::Value: Mul<C::Value>,
Prod<R::Value, C::Value>: ArrayLength<N>,
N: Abomonation
{
unsafe fn entomb(&self, writer: &mut Vec<u8>) {
for element in self.data.as_slice() {
element.entomb(writer);
}
}
unsafe fn embalm(&mut self) {
for element in self.data.as_mut_slice() {
element.embalm();
}
}
unsafe fn exhume<'a, 'b>(&'a mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
for element in self.data.as_mut_slice() {
let temp = bytes;
bytes = if let Some(remainder) = element.exhume(temp) {
remainder
} else {
return None;
}
}
Some(bytes)
}
}

View File

@ -6,6 +6,9 @@ use core::storage::{Storage, StorageMut, Owned, ContiguousStorage, ContiguousSto
use core::allocator::Allocator; use core::allocator::Allocator;
use core::default_allocator::DefaultAllocator; use core::default_allocator::DefaultAllocator;
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
/* /*
* *
* Storage. * Storage.
@ -213,6 +216,21 @@ unsafe impl<N: Scalar, R: DimName> StorageMut<N, R, Dynamic> for MatrixVec<N, R,
} }
} }
#[cfg(feature = "abomonation-serialize")]
impl<N: Abomonation, R: Dim, C: Dim> Abomonation for MatrixVec<N, R, C> {
unsafe fn entomb(&self, writer: &mut Vec<u8>) {
self.data.entomb(writer)
}
unsafe fn embalm(&mut self) {
self.data.embalm()
}
unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
self.data.exhume(bytes)
}
}
unsafe impl<N: Scalar, R: DimName> ContiguousStorage<N, R, Dynamic> for MatrixVec<N, R, Dynamic> unsafe impl<N: Scalar, R: DimName> ContiguousStorage<N, R, Dynamic> for MatrixVec<N, R, Dynamic>
where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self> { where DefaultAllocator: Allocator<N, R, Dynamic, Buffer = Self> {
} }

View File

@ -5,6 +5,9 @@ use approx::ApproxEq;
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
use serde::{Serialize, Serializer, Deserialize, Deserializer}; use serde::{Serialize, Serializer, Deserialize, Deserializer};
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
use alga::general::SubsetOf; use alga::general::SubsetOf;
use alga::linear::NormedSpace; use alga::linear::NormedSpace;
@ -36,6 +39,21 @@ impl<'de, T: Deserialize<'de>> Deserialize<'de> for Unit<T> {
} }
} }
#[cfg(feature = "abomonation-serialize")]
impl<T: Abomonation> Abomonation for Unit<T> {
unsafe fn entomb(&self, writer: &mut Vec<u8>) {
self.value.entomb(writer);
}
unsafe fn embalm(&mut self) {
self.value.embalm();
}
unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
self.value.exhume(bytes)
}
}
impl<T: NormedSpace> Unit<T> { impl<T: NormedSpace> Unit<T> {
/// Normalize the given value and return it wrapped on a `Unit` structure. /// Normalize the given value and return it wrapped on a `Unit` structure.
#[inline] #[inline]

View File

@ -6,6 +6,9 @@ use approx::ApproxEq;
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
use serde; use serde;
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
use alga::general::{Real, SubsetOf}; use alga::general::{Real, SubsetOf};
use alga::linear::Rotation; use alga::linear::Rotation;
@ -42,6 +45,30 @@ pub struct Isometry<N: Real, D: DimName, R>
_noconstruct: PhantomData<N> _noconstruct: PhantomData<N>
} }
#[cfg(feature = "abomonation-serialize")]
impl<N, D, R> Abomonation for Isometry<N, D, R>
where N: Real,
D: DimName,
R: Abomonation,
Translation<N, D>: Abomonation,
DefaultAllocator: Allocator<N, D>
{
unsafe fn entomb(&self, writer: &mut Vec<u8>) {
self.rotation.entomb(writer);
self.translation.entomb(writer);
}
unsafe fn embalm(&mut self) {
self.rotation.embalm();
self.translation.embalm();
}
unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
self.rotation.exhume(bytes)
.and_then(|bytes| self.translation.exhume(bytes))
}
}
impl<N: Real + hash::Hash, D: DimName + hash::Hash, R: hash::Hash> hash::Hash for Isometry<N, D, R> impl<N: Real + hash::Hash, D: DimName + hash::Hash, R: hash::Hash> hash::Hash for Isometry<N, D, R>
where DefaultAllocator: Allocator<N, D>, where DefaultAllocator: Allocator<N, D>,
Owned<N, D>: hash::Hash { Owned<N, D>: hash::Hash {
@ -66,6 +93,7 @@ impl<N: Real, D: DimName, R: Rotation<Point<N, D>> + Clone> Clone for Isometry<N
impl<N: Real, D: DimName, R: Rotation<Point<N, D>>> Isometry<N, D, R> impl<N: Real, D: DimName, R: Rotation<Point<N, D>>> Isometry<N, D, R>
where DefaultAllocator: Allocator<N, D> { where DefaultAllocator: Allocator<N, D> {
/// Creates a new isometry from its rotational and translational parts. /// Creates a new isometry from its rotational and translational parts.
#[inline] #[inline]
pub fn from_parts(translation: Translation<N, D>, rotation: R) -> Isometry<N, D, R> { pub fn from_parts(translation: Translation<N, D>, rotation: R) -> Isometry<N, D, R> {

View File

@ -7,6 +7,9 @@ use approx::ApproxEq;
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
use serde; use serde;
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
use core::{DefaultAllocator, Scalar, VectorN}; use core::{DefaultAllocator, Scalar, VectorN};
use core::iter::{MatrixIter, MatrixIterMut}; use core::iter::{MatrixIter, MatrixIterMut};
use core::dimension::{DimName, DimNameSum, DimNameAdd, U1}; use core::dimension::{DimName, DimNameSum, DimNameAdd, U1};
@ -66,6 +69,27 @@ where DefaultAllocator: Allocator<N, D>,
} }
} }
#[cfg(feature = "abomonation-serialize")]
impl<N, D> Abomonation for Point<N, D>
where N: Scalar,
D: DimName,
VectorN<N, D>: Abomonation,
DefaultAllocator: Allocator<N, D>
{
unsafe fn entomb(&self, writer: &mut Vec<u8>) {
self.coords.entomb(writer)
}
unsafe fn embalm(&mut self) {
self.coords.embalm()
}
unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
self.coords.exhume(bytes)
}
}
impl<N: Scalar, D: DimName> Point<N, D> impl<N: Scalar, D: DimName> Point<N, D>
where DefaultAllocator: Allocator<N, D> { where DefaultAllocator: Allocator<N, D> {

View File

@ -8,6 +8,9 @@ use serde;
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
use core::storage::Owned; use core::storage::Owned;
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
use alga::general::Real; use alga::general::Real;
use core::{Unit, Vector3, Vector4, MatrixSlice, MatrixSliceMut, SquareMatrix, MatrixN}; use core::{Unit, Vector3, Vector4, MatrixSlice, MatrixSliceMut, SquareMatrix, MatrixN};
@ -25,9 +28,25 @@ pub struct Quaternion<N: Real> {
pub coords: Vector4<N> pub coords: Vector4<N>
} }
impl<N: Real + Eq> Eq for Quaternion<N> { #[cfg(feature = "abomonation-serialize")]
impl<N: Real> Abomonation for Quaternion<N>
where Vector4<N>: Abomonation
{
unsafe fn entomb(&self, writer: &mut Vec<u8>) {
self.coords.entomb(writer)
}
unsafe fn embalm(&mut self) {
self.coords.embalm()
}
unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
self.coords.exhume(bytes)
}
} }
impl<N: Real + Eq> Eq for Quaternion<N> { }
impl<N: Real> PartialEq for Quaternion<N> { impl<N: Real> PartialEq for Quaternion<N> {
fn eq(&self, rhs: &Self) -> bool { fn eq(&self, rhs: &Self) -> bool {
self.coords == rhs.coords || self.coords == rhs.coords ||

View File

@ -9,6 +9,9 @@ use serde;
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
use core::storage::Owned; use core::storage::Owned;
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
use alga::general::Real; use alga::general::Real;
use core::{DefaultAllocator, Scalar, MatrixN}; use core::{DefaultAllocator, Scalar, MatrixN};
@ -45,6 +48,26 @@ impl<N: Scalar, D: DimName> Clone for Rotation<N, D>
} }
} }
#[cfg(feature = "abomonation-serialize")]
impl<N, D> Abomonation for Rotation<N, D>
where N: Scalar,
D: DimName,
MatrixN<N, D>: Abomonation,
DefaultAllocator: Allocator<N, D, D>
{
unsafe fn entomb(&self, writer: &mut Vec<u8>) {
self.matrix.entomb(writer)
}
unsafe fn embalm(&mut self) {
self.matrix.embalm()
}
unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
self.matrix.exhume(bytes)
}
}
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
impl<N: Scalar, D: DimName> serde::Serialize for Rotation<N, D> impl<N: Scalar, D: DimName> serde::Serialize for Rotation<N, D>
where DefaultAllocator: Allocator<N, D, D>, where DefaultAllocator: Allocator<N, D, D>,

View File

@ -5,6 +5,9 @@ use approx::ApproxEq;
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
use serde; use serde;
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
use alga::general::{Real, SubsetOf}; use alga::general::{Real, SubsetOf};
use alga::linear::Rotation; use alga::linear::Rotation;
@ -15,6 +18,7 @@ use core::allocator::Allocator;
use geometry::{Point, Translation, Isometry}; use geometry::{Point, Translation, Isometry};
/// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation. /// A similarity, i.e., an uniform scaling, followed by a rotation, followed by a translation.
#[repr(C)] #[repr(C)]
#[derive(Debug)] #[derive(Debug)]
@ -38,6 +42,24 @@ pub struct Similarity<N: Real, D: DimName, R>
scaling: N scaling: N
} }
#[cfg(feature = "abomonation-serialize")]
impl<N: Real, D: DimName, R> Abomonation for Similarity<N, D, R>
where Isometry<N, D, R>: Abomonation,
DefaultAllocator: Allocator<N, D>
{
unsafe fn entomb(&self, writer: &mut Vec<u8>) {
self.isometry.entomb(writer)
}
unsafe fn embalm(&mut self) {
self.isometry.embalm()
}
unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
self.isometry.exhume(bytes)
}
}
impl<N: Real + hash::Hash, D: DimName + hash::Hash, R: hash::Hash> hash::Hash for Similarity<N, D, R> impl<N: Real + hash::Hash, D: DimName + hash::Hash, R: hash::Hash> hash::Hash for Similarity<N, D, R>
where DefaultAllocator: Allocator<N, D>, where DefaultAllocator: Allocator<N, D>,
Owned<N, D>: hash::Hash { Owned<N, D>: hash::Hash {

View File

@ -6,6 +6,9 @@ use approx::ApproxEq;
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
use serde; use serde;
#[cfg(feature = "abomonation-serialize")]
use abomonation::Abomonation;
use alga::general::{Real, ClosedNeg}; use alga::general::{Real, ClosedNeg};
use core::{DefaultAllocator, Scalar, MatrixN, VectorN}; use core::{DefaultAllocator, Scalar, MatrixN, VectorN};
@ -44,6 +47,26 @@ impl<N: Scalar, D: DimName> Clone for Translation<N, D>
} }
} }
#[cfg(feature = "abomonation-serialize")]
impl<N, D> Abomonation for Translation<N, D>
where N: Scalar,
D: DimName,
VectorN<N, D>: Abomonation,
DefaultAllocator: Allocator<N, D>
{
unsafe fn entomb(&self, writer: &mut Vec<u8>) {
self.vector.entomb(writer)
}
unsafe fn embalm(&mut self) {
self.vector.embalm()
}
unsafe fn exhume<'a, 'b>(&'a mut self, bytes: &'b mut [u8]) -> Option<&'b mut [u8]> {
self.vector.exhume(bytes)
}
}
#[cfg(feature = "serde-serialize")] #[cfg(feature = "serde-serialize")]
impl<N: Scalar, D: DimName> serde::Serialize for Translation<N, D> impl<N: Scalar, D: DimName> serde::Serialize for Translation<N, D>
where DefaultAllocator: Allocator<N, D>, where DefaultAllocator: Allocator<N, D>,

View File

@ -90,11 +90,16 @@ an optimized set of tools for computer graphics and physics. Those features incl
#[cfg(feature = "arbitrary")] #[cfg(feature = "arbitrary")]
extern crate quickcheck; extern crate quickcheck;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
extern crate serde; extern crate serde;
#[cfg(feature = "serde")] #[cfg(feature = "serde")]
#[macro_use] #[macro_use]
extern crate serde_derive; extern crate serde_derive;
#[cfg(feature = "abomonation")]
extern crate abomonation;
extern crate num_traits as num; extern crate num_traits as num;
extern crate num_complex; extern crate num_complex;
extern crate rand; extern crate rand;

51
tests/core/abomonation.rs Normal file
View File

@ -0,0 +1,51 @@
use rand::random;
use abomonation::{Abomonation, encode, decode};
use na::{
DMatrix, Matrix3x4, Point3, Translation3, Rotation3, Isometry3, Quaternion,
IsometryMatrix3, Similarity3, SimilarityMatrix3
};
#[test]
fn abomonate_dmatrix() {
assert_encode_and_decode(DMatrix::<f32>::new_random(3, 5));
}
macro_rules! test_abomonation(
($($test: ident, $ty: ty);* $(;)*) => {$(
#[test]
fn $test() {
assert_encode_and_decode(random::<$ty>());
}
)*}
);
test_abomonation! {
abomonate_matrix3x4, Matrix3x4<f32>;
abomonate_point3, Point3<f32>;
abomonate_translation3, Translation3<f64>;
abomonate_rotation3, Rotation3<f64>;
abomonate_isometry3, Isometry3<f32>;
abomonate_isometry_matrix3, IsometryMatrix3<f64>;
abomonate_similarity3, Similarity3<f32>;
abomonate_similarity_matrix3, SimilarityMatrix3<f32>;
abomonate_quaternion, Quaternion<f32>;
}
fn assert_encode_and_decode<T: Abomonation + PartialEq + Clone>(original_data: T) {
use std::mem::drop;
// Hold on to a clone for later comparison
let data = original_data.clone();
// Encode
let mut bytes = Vec::new();
unsafe { encode(&original_data, &mut bytes); }
// Drop the original, so that dangling pointers are revealed by the test
drop(original_data);
if let Some((result, rest)) = unsafe { decode::<T>(&mut bytes) } {
assert!(result == &data);
assert!(rest.len() == 0, "binary data was not decoded completely");
}
}

View File

@ -4,3 +4,4 @@ mod matrix;
mod matrix_slice; mod matrix_slice;
mod blas; mod blas;
mod serde; mod serde;
mod abomonation;

View File

@ -83,7 +83,7 @@ quickcheck!(
/* /*
* *
* Quaterion * Vector == RotationBase * Vector * Quaterion * Vector == Rotation * Vector
* *
*/ */
fn unit_quaternion_mul_vector(q: UnitQuaternion<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool { fn unit_quaternion_mul_vector(q: UnitQuaternion<f64>, v: Vector3<f64>, p: Point3<f64>) -> bool {

View File

@ -79,7 +79,7 @@ quickcheck!(
/* /*
* *
* RotationBase matrix between vectors. * Rotation matrix between vectors.
* *
*/ */
fn rotation_between_is_anticommutative_2(a: Vector2<f64>, b: Vector2<f64>) -> bool { fn rotation_between_is_anticommutative_2(a: Vector2<f64>, b: Vector2<f64>) -> bool {
@ -132,7 +132,7 @@ quickcheck!(
/* /*
* *
* RotationBase construction. * Rotation construction.
* *
*/ */
fn new_rotation_2(angle: f64) -> bool { fn new_rotation_2(angle: f64) -> bool {
@ -159,7 +159,7 @@ quickcheck!(
/* /*
* *
* RotationBase pow. * Rotation pow.
* *
*/ */
fn powf_rotation_2(angle: f64, pow: f64) -> bool { fn powf_rotation_2(angle: f64, pow: f64) -> bool {

View File

@ -60,7 +60,7 @@ quickcheck!(
/* /*
* *
* Quaterion * Vector == RotationBase * Vector * Quaterion * Vector == Rotation * Vector
* *
*/ */
fn unit_complex_mul_vector(c: UnitComplex<f64>, v: Vector2<f64>, p: Point2<f64>) -> bool { fn unit_complex_mul_vector(c: UnitComplex<f64>, v: Vector2<f64>, p: Point2<f64>) -> bool {

View File

@ -5,6 +5,7 @@ extern crate quickcheck;
extern crate approx; extern crate approx;
extern crate num_traits as num; extern crate num_traits as num;
extern crate serde_json; extern crate serde_json;
extern crate abomonation;
extern crate rand; extern crate rand;
extern crate alga; extern crate alga;
extern crate nalgebra as na; extern crate nalgebra as na;