diff --git a/src/core/conversion.rs b/src/core/conversion.rs index 8c99d6c5..2ed03ece 100644 --- a/src/core/conversion.rs +++ b/src/core/conversion.rs @@ -1,7 +1,11 @@ +use std::ptr; +use std::mem; +use std::convert::{From, Into, AsRef, AsMut}; +use typenum::{self, Cmp, Equal}; use alga::general::{SubsetOf, SupersetOf}; use core::{Scalar, Matrix}; -use core::dimension::Dim; +use core::dimension::{Dim, DimName, DimNameMul, DimNameProd, U1, U2, U3, U4, U5, U6}; use core::constraint::{ShapeConstraint, SameNumberOfRows, SameNumberOfColumns}; use core::storage::OwnedStorage; use core::allocator::{OwnedAllocator, SameShapeAllocator}; @@ -57,3 +61,155 @@ impl SubsetOf> for Matrix res } } + + +macro_rules! impl_from_into_asref_1D( + ($($Dim: ident => $SZ: expr);* $(;)*) => {$( + impl From<[N; $SZ]> for Matrix + where N: Scalar, + R: DimName + DimNameMul, + C: DimName, + S: OwnedStorage, + S::Alloc: OwnedAllocator, + as DimName>::Value: Cmp { + #[inline] + fn from(arr: [N; $SZ]) -> Self { + unsafe { + let mut res = Self::new_uninitialized(); + ptr::copy_nonoverlapping(&arr[0], res.data.ptr_mut(), $SZ); + + res + } + } + } + + impl Into<[N; $SZ]> for Matrix + where N: Scalar, + R: DimName + DimNameMul, + C: DimName, + S: OwnedStorage, + S::Alloc: OwnedAllocator, + as DimName>::Value: Cmp { + #[inline] + fn into(self) -> [N; $SZ] { + unsafe { + let mut res: [N; $SZ] = mem::uninitialized(); + ptr::copy_nonoverlapping(self.data.ptr(), &mut res[0], $SZ); + + res + } + } + } + + impl AsRef<[N; $SZ]> for Matrix + where N: Scalar, + R: DimName + DimNameMul, + C: DimName, + S: OwnedStorage, + S::Alloc: OwnedAllocator, + as DimName>::Value: Cmp { + #[inline] + fn as_ref(&self) -> &[N; $SZ] { + unsafe { + mem::transmute(self.data.ptr()) + } + } + } + + impl AsMut<[N; $SZ]> for Matrix + where N: Scalar, + R: DimName + DimNameMul, + C: DimName, + S: OwnedStorage, + S::Alloc: OwnedAllocator, + as DimName>::Value: Cmp { + #[inline] + fn as_mut(&mut self) -> &mut [N; $SZ] { + unsafe { + mem::transmute(self.data.ptr_mut()) + } + } + } + )*} +); + +// Implement for vectors of dimension 1 .. 36 and matrices with shape 1x1 .. 6x6. +impl_from_into_asref_1D!( + U1 => 1; U2 => 2; U3 => 3; U4 => 4; U5 => 5; U6 => 6; + U7 => 7; U8 => 8; U9 => 9; U10 => 10; U11 => 11; U12 => 12; + U13 => 13; U14 => 14; U15 => 15; U16 => 16; U17 => 17; U18 => 18; + U19 => 19; U20 => 20; U21 => 21; U22 => 22; U23 => 23; U24 => 24; + U25 => 25; U26 => 26; U27 => 27; U28 => 28; U29 => 29; U30 => 30; + U31 => 31; U32 => 32; U33 => 33; U34 => 34; U35 => 35; U36 => 36; +); + + + +macro_rules! impl_from_into_asref_2D( + ($(($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr));* $(;)*) => {$( + impl From<[[N; $SZRows]; $SZCols]> for Matrix + where N: Scalar, + S: OwnedStorage, + S::Alloc: OwnedAllocator { + #[inline] + fn from(arr: [[N; $SZRows]; $SZCols]) -> Self { + unsafe { + let mut res = Self::new_uninitialized(); + ptr::copy_nonoverlapping(&arr[0][0], res.data.ptr_mut(), $SZRows * $SZCols); + + res + } + } + } + + impl Into<[[N; $SZRows]; $SZCols]> for Matrix + where N: Scalar, + S: OwnedStorage, + S::Alloc: OwnedAllocator { + #[inline] + fn into(self) -> [[N; $SZRows]; $SZCols] { + unsafe { + let mut res: [[N; $SZRows]; $SZCols] = mem::uninitialized(); + ptr::copy_nonoverlapping(self.data.ptr(), &mut res[0][0], $SZRows * $SZCols); + + res + } + } + } + + impl AsRef<[[N; $SZRows]; $SZCols]> for Matrix + where N: Scalar, + S: OwnedStorage, + S::Alloc: OwnedAllocator { + #[inline] + fn as_ref(&self) -> &[[N; $SZRows]; $SZCols] { + unsafe { + mem::transmute(self.data.ptr()) + } + } + } + + impl AsMut<[[N; $SZRows]; $SZCols]> for Matrix + where N: Scalar, + S: OwnedStorage, + S::Alloc: OwnedAllocator { + #[inline] + fn as_mut(&mut self) -> &mut [[N; $SZRows]; $SZCols] { + unsafe { + mem::transmute(self.data.ptr_mut()) + } + } + } + )*} +); + + +// Implement for matrices with shape 1x1 .. 4x4. +impl_from_into_asref_2D!( + (U1, U1) => (1, 1); (U1, U2) => (1, 2); (U1, U3) => (1, 3); (U1, U4) => (1, 4); (U1, U5) => (1, 5); (U1, U6) => (1, 6); + (U2, U1) => (2, 1); (U2, U2) => (2, 2); (U2, U3) => (2, 3); (U2, U4) => (2, 4); (U2, U5) => (2, 5); (U2, U6) => (2, 6); + (U3, U1) => (3, 1); (U3, U2) => (3, 2); (U3, U3) => (3, 3); (U3, U4) => (3, 4); (U3, U5) => (3, 5); (U3, U6) => (3, 6); + (U4, U1) => (4, 1); (U4, U2) => (4, 2); (U4, U3) => (4, 3); (U4, U4) => (4, 4); (U4, U5) => (4, 5); (U4, U6) => (4, 6); + (U5, U1) => (5, 1); (U5, U2) => (5, 2); (U5, U3) => (5, 3); (U5, U4) => (5, 4); (U5, U5) => (5, 5); (U5, U6) => (5, 6); + (U6, U1) => (6, 1); (U6, U2) => (6, 2); (U6, U3) => (6, 3); (U6, U4) => (6, 4); (U6, U5) => (6, 5); (U6, U6) => (6, 6); +); diff --git a/tests/conversion.rs b/tests/conversion.rs index 558b6a6f..673227d9 100644 --- a/tests/conversion.rs +++ b/tests/conversion.rs @@ -8,8 +8,16 @@ extern crate alga; extern crate nalgebra as na; use alga::linear::Transformation; -use na::{Vector3, Point3, Translation3, Isometry3, Similarity3, Affine3, Projective3, Transform3, - Rotation3, UnitQuaternion}; +use na::{ + Vector1, Vector2, Vector3, Vector4, Vector5, Vector6, + Matrix2, Matrix3, Matrix4, Matrix5, Matrix6, + Matrix2x3, Matrix2x4, Matrix2x5, Matrix2x6, + Matrix3x2, Matrix3x4, Matrix3x5, Matrix3x6, + Matrix4x2, Matrix4x3, Matrix4x5, Matrix4x6, + Matrix5x2, Matrix5x3, Matrix5x4, Matrix5x6, + Matrix6x2, Matrix6x3, Matrix6x4, Matrix6x5, + Point3, Translation3, Isometry3, Similarity3, Affine3, + Projective3, Transform3, Rotation3, UnitQuaternion}; #[cfg(feature = "arbitrary")] @@ -145,3 +153,84 @@ quickcheck!{ // XXX test TransformBase } + +macro_rules! array_vector_conversion( + ($($array_vector_conversion_i: ident, $Vector: ident, $SZ: expr);* $(;)*) => {$( + #[test] + fn $array_vector_conversion_i() { + let v = $Vector::from_fn(|i, _| i); + let arr: [usize; $SZ] = v.into(); + let arr_ref: &[usize; $SZ] = v.as_ref(); + let v2 = $Vector::from(arr); + + for i in 0 .. $SZ { + assert_eq!(arr[i], i); + assert_eq!(arr_ref[i], i); + } + + assert_eq!(v, v2); + } + )*} +); + +array_vector_conversion!( + array_vector_conversion_1, Vector1, 1; + array_vector_conversion_2, Vector2, 2; + array_vector_conversion_3, Vector3, 3; + array_vector_conversion_4, Vector4, 4; + array_vector_conversion_5, Vector5, 5; + array_vector_conversion_6, Vector6, 6; +); + +macro_rules! array_matrix_conversion( + ($($array_matrix_conversion_i_j: ident, $Matrix: ident, ($NRows: expr, $NCols: expr));* $(;)*) => {$( + #[test] + fn $array_matrix_conversion_i_j() { + let m = $Matrix::from_fn(|i, j| i * 10 + j); + let arr: [[usize; $NRows]; $NCols] = m.into(); + let arr_ref: &[[usize; $NRows]; $NCols] = m.as_ref(); + let m2 = $Matrix::from(arr); + + for i in 0 .. $NRows { + for j in 0 .. $NCols { + assert_eq!(arr[j][i], i * 10 + j); + assert_eq!(arr_ref[j][i], i * 10 + j); + } + } + + assert_eq!(m, m2); + } + )*} +); + +array_matrix_conversion!( + array_matrix_conversion_2_2, Matrix2, (2, 2); + array_matrix_conversion_2_3, Matrix2x3, (2, 3); + array_matrix_conversion_2_4, Matrix2x4, (2, 4); + array_matrix_conversion_2_5, Matrix2x5, (2, 5); + array_matrix_conversion_2_6, Matrix2x6, (2, 6); + + array_matrix_conversion_3_2, Matrix3x2, (3, 2); + array_matrix_conversion_3_3, Matrix3, (3, 3); + array_matrix_conversion_3_4, Matrix3x4, (3, 4); + array_matrix_conversion_3_5, Matrix3x5, (3, 5); + array_matrix_conversion_3_6, Matrix3x6, (3, 6); + + array_matrix_conversion_4_2, Matrix4x2, (4, 2); + array_matrix_conversion_4_3, Matrix4x3, (4, 3); + array_matrix_conversion_4_4, Matrix4, (4, 4); + array_matrix_conversion_4_5, Matrix4x5, (4, 5); + array_matrix_conversion_4_6, Matrix4x6, (4, 6); + + array_matrix_conversion_5_2, Matrix5x2, (5, 2); + array_matrix_conversion_5_3, Matrix5x3, (5, 3); + array_matrix_conversion_5_4, Matrix5x4, (5, 4); + array_matrix_conversion_5_5, Matrix5, (5, 5); + array_matrix_conversion_5_6, Matrix5x6, (5, 6); + + array_matrix_conversion_6_2, Matrix6x2, (6, 2); + array_matrix_conversion_6_3, Matrix6x3, (6, 3); + array_matrix_conversion_6_4, Matrix6x4, (6, 4); + array_matrix_conversion_6_5, Matrix6x5, (6, 5); + array_matrix_conversion_6_6, Matrix6, (6, 6); +);