From f70e7f77d1517d67ff8f62ea5e10e4c6212ac30a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Mon, 12 Apr 2021 17:43:04 +0200 Subject: [PATCH 01/57] Fix serialization of DVector --- src/base/dimension.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/base/dimension.rs b/src/base/dimension.rs index ec70dc4c..dd87647d 100644 --- a/src/base/dimension.rs +++ b/src/base/dimension.rs @@ -211,6 +211,26 @@ pub trait DimName: Dim { fn dim() -> usize; } +#[cfg(feature = "serde-serialize-no-std")] +impl Serialize for Const { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + ().serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize-no-std")] +impl<'de, const D: usize> Deserialize<'de> for Const { + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'de>, + { + <()>::deserialize(deserializer).map(|_| Const::) + } +} + pub trait ToConst { type Const: DimName; } From 3ec57016b94bcdcd630938c3825cc813bd6b57cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Mon, 12 Apr 2021 17:52:59 +0200 Subject: [PATCH 02/57] Release v0.26.1 --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 3bab7b93..3b86323f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra" -version = "0.26.0" +version = "0.26.1" authors = [ "Sébastien Crozet " ] description = "General-purpose linear algebra library with transformations and statically-sized or dynamically-sized matrices." From 28bfb4ad6d13388476d180129c459652428f628e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Mon, 12 Apr 2021 17:54:06 +0200 Subject: [PATCH 03/57] Update Changelog. --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 54e7c0fe..615cdd71 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,9 @@ documented here. This project adheres to [Semantic Versioning](https://semver.org/). +## [0.26.1] +Fix a regression introduced in 0.26.0 preventing `DVector` from being serialized with `serde`. + ## [0.26.0] This releases integrates `min-const-generics` to nalgebra. See [our blog post](https://dimforge.com/blog/2021/04/12/nalgebra-const-generics) From 984bb1a63943aa68b6f26ff4a6acf8f68b833b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Mon, 12 Apr 2021 18:15:16 +0200 Subject: [PATCH 04/57] Fix const-generics blog post url in the changelog. --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 615cdd71..8c762fd5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ Fix a regression introduced in 0.26.0 preventing `DVector` from being serialized ## [0.26.0] This releases integrates `min-const-generics` to nalgebra. See -[our blog post](https://dimforge.com/blog/2021/04/12/nalgebra-const-generics) +[our blog post](https://www.dimforge.com/blog/2021/04/12/integrating-const-generics-to-nalgebra) for details about this release. ### Added From 43cf22af288205bb769e734bf8174b1f3e7aeb82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Tue, 27 Apr 2021 13:16:01 +0200 Subject: [PATCH 05/57] Cleanup conversion between static arrays and static matrices. --- src/base/conversion.rs | 83 +++++++++++++++--------------------------- 1 file changed, 30 insertions(+), 53 deletions(-) diff --git a/src/base/conversion.rs b/src/base/conversion.rs index 24a088a2..b329dba1 100644 --- a/src/base/conversion.rs +++ b/src/base/conversion.rs @@ -3,7 +3,6 @@ use alloc::vec::Vec; use simba::scalar::{SubsetOf, SupersetOf}; use std::convert::{AsMut, AsRef, From, Into}; use std::mem; -use std::ptr; use simba::simd::{PrimitiveSimdValue, SimdValue}; @@ -24,6 +23,7 @@ use crate::base::{ use crate::base::{DVector, VecStorage}; use crate::base::{SliceStorage, SliceStorageMut}; use crate::constraint::DimEq; +use crate::{SMatrix, SVector}; // TODO: too bad this won't work allo slice conversions. impl SubsetOf> for OMatrix @@ -103,35 +103,23 @@ impl<'a, T: Scalar, R: Dim, C: Dim, S: StorageMut> IntoIterator } } +impl From<[T; D]> for SVector { + #[inline] + fn from(arr: [T; D]) -> Self { + unsafe { Self::from_data_statically_unchecked(ArrayStorage([arr; 1])) } + } +} + +impl Into<[T; D]> for SVector { + #[inline] + fn into(self) -> [T; D] { + // TODO: unfortunately, we must clone because we can move out of an array. + self.data.0[0].clone() + } +} + macro_rules! impl_from_into_asref_1D( ($(($NRows: ident, $NCols: ident) => $SZ: expr);* $(;)*) => {$( - impl From<[T; $SZ]> for OMatrix - where T: Scalar, - DefaultAllocator: Allocator { - #[inline] - fn from(arr: [T; $SZ]) -> Self { - unsafe { - let mut res = Self::new_uninitialized(); - ptr::copy_nonoverlapping(&arr[0], (*res.as_mut_ptr()).data.ptr_mut(), $SZ); - - res.assume_init() - } - } - } - - impl Into<[T; $SZ]> for Matrix - where T: Scalar, - S: ContiguousStorage { - #[inline] - fn into(self) -> [T; $SZ] { - let mut res = mem::MaybeUninit::<[T; $SZ]>::uninit(); - - unsafe { ptr::copy_nonoverlapping(self.data.ptr(), res.as_mut_ptr() as *mut T, $SZ) }; - - unsafe { res.assume_init() } - } - } - impl AsRef<[T; $SZ]> for Matrix where T: Scalar, S: ContiguousStorage { @@ -171,33 +159,22 @@ impl_from_into_asref_1D!( (U13, U1) => 13; (U14, U1) => 14; (U15, U1) => 15; (U16, U1) => 16; ); +impl From<[[T; R]; C]> for SMatrix { + #[inline] + fn from(arr: [[T; R]; C]) -> Self { + unsafe { Self::from_data_statically_unchecked(ArrayStorage(arr)) } + } +} + +impl Into<[[T; R]; C]> for SMatrix { + #[inline] + fn into(self) -> [[T; R]; C] { + self.data.0 + } +} + macro_rules! impl_from_into_asref_2D( ($(($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr));* $(;)*) => {$( - impl From<[[T; $SZRows]; $SZCols]> for OMatrix - where DefaultAllocator: Allocator { - #[inline] - fn from(arr: [[T; $SZRows]; $SZCols]) -> Self { - unsafe { - let mut res = Self::new_uninitialized(); - ptr::copy_nonoverlapping(&arr[0][0], (*res.as_mut_ptr()).data.ptr_mut(), $SZRows * $SZCols); - - res.assume_init() - } - } - } - - impl Into<[[T; $SZRows]; $SZCols]> for Matrix - where S: ContiguousStorage { - #[inline] - fn into(self) -> [[T; $SZRows]; $SZCols] { - let mut res = mem::MaybeUninit::<[[T; $SZRows]; $SZCols]>::uninit(); - - unsafe { ptr::copy_nonoverlapping(self.data.ptr(), res.as_mut_ptr() as *mut T, $SZRows * $SZCols) }; - - unsafe { res.assume_init() } - } - } - impl AsRef<[[T; $SZRows]; $SZCols]> for Matrix where S: ContiguousStorage { #[inline] From 09be376cd9c87806845792e8a7f21a676bdc9b10 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Tue, 27 Apr 2021 13:16:44 +0200 Subject: [PATCH 06/57] Add more conversion for Isometry Add [T; D] -> Isometry Add SVector -> Isometry Add Point -> Isometry --- src/geometry/isometry_conversion.rs | 30 +++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/geometry/isometry_conversion.rs b/src/geometry/isometry_conversion.rs index b8cc4568..75c0d98d 100644 --- a/src/geometry/isometry_conversion.rs +++ b/src/geometry/isometry_conversion.rs @@ -9,6 +9,7 @@ use crate::geometry::{ AbstractRotation, Isometry, Isometry3, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, UnitDualQuaternion, UnitQuaternion, }; +use crate::{Point, SVector}; /* * This file provides the following conversions: @@ -198,6 +199,35 @@ where } } +impl From<[T; D]> for Isometry +where + R: AbstractRotation, +{ + #[inline] + fn from(coords: [T; D]) -> Self { + Self::from_parts(coords.into(), R::identity()) + } +} + +impl From> for Isometry +where + R: AbstractRotation, +{ + #[inline] + fn from(coords: SVector) -> Self { + Self::from_parts(coords.into(), R::identity()) + } +} +impl From> for Isometry +where + R: AbstractRotation, +{ + #[inline] + fn from(coords: Point) -> Self { + Self::from_parts(coords.into(), R::identity()) + } +} + impl From<[Isometry; 2]> for Isometry where From db27a080f15444fec66bc3257a1d91e64cbc5e54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Tue, 27 Apr 2021 13:17:12 +0200 Subject: [PATCH 07/57] Cleanup conversions between points and static vectors. --- src/geometry/point_construction.rs | 14 -------------- src/geometry/point_conversion.rs | 16 ++++++++++++++++ 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/src/geometry/point_construction.rs b/src/geometry/point_construction.rs index f50a3fc1..7e34137c 100644 --- a/src/geometry/point_construction.rs +++ b/src/geometry/point_construction.rs @@ -225,17 +225,3 @@ componentwise_constructors_impl!( "# use nalgebra::Point6;\nlet p = Point6::new(1.0, 2.0, 3.0, 4.0, 5.0, 6.0);\nassert!(p.x == 1.0 && p.y == 2.0 && p.z == 3.0 && p.w == 4.0 && p.a == 5.0 && p.b == 6.0);"; Point6, Vector6, x:0, y:1, z:2, w:3, a:4, b:5; ); - -macro_rules! from_array_impl( - ($($Point: ident, $len: expr);*) => {$( - impl From<[T; $len]> for $Point { - fn from(coords: [T; $len]) -> Self { - Self { - coords: coords.into() - } - } - } - )*} -); - -from_array_impl!(Point1, 1; Point2, 2; Point3, 3; Point4, 4; Point5, 5; Point6, 6); diff --git a/src/geometry/point_conversion.rs b/src/geometry/point_conversion.rs index 08438ec0..91cd62ce 100644 --- a/src/geometry/point_conversion.rs +++ b/src/geometry/point_conversion.rs @@ -81,6 +81,22 @@ where } } +impl From<[T; D]> for Point { + #[inline] + fn from(coords: [T; D]) -> Self { + Point { + coords: coords.into(), + } + } +} + +impl Into<[T; D]> for Point { + #[inline] + fn into(self) -> [T; D] { + self.coords.into() + } +} + impl From>> for Point { #[inline] fn from(coords: OVector>) -> Self { From 65b94ccb915e705f8afba254a36d08ad848e3822 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Tue, 27 Apr 2021 13:17:51 +0200 Subject: [PATCH 08/57] Add more conversions for translations Add [T; D] <-> Translation Add Point -> Translation --- src/geometry/translation_conversion.rs | 26 ++++++++++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/geometry/translation_conversion.rs b/src/geometry/translation_conversion.rs index 8c8f860f..ff8e797f 100644 --- a/src/geometry/translation_conversion.rs +++ b/src/geometry/translation_conversion.rs @@ -11,6 +11,7 @@ use crate::geometry::{ AbstractRotation, Isometry, Similarity, SuperTCategoryOf, TAffine, Transform, Translation, Translation3, UnitDualQuaternion, UnitQuaternion, }; +use crate::Point; /* * This file provides the following conversions: @@ -199,6 +200,31 @@ impl From>> for Translation } } +impl From<[T; D]> for Translation { + #[inline] + fn from(coords: [T; D]) -> Self { + Translation { + vector: coords.into(), + } + } +} + +impl From> for Translation { + #[inline] + fn from(pt: Point) -> Self { + Translation { + vector: pt.coords.into(), + } + } +} + +impl Into<[T; D]> for Translation { + #[inline] + fn into(self) -> [T; D] { + self.vector.into() + } +} + impl From<[Translation; 2]> for Translation where From d59d4381890e87d99899c8f6af06c8e53a71e805 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Tue, 27 Apr 2021 13:21:46 +0200 Subject: [PATCH 09/57] Add more conversion for glam types Add Isometry3 <-> (Vec3, Quat) Add Isometry2 <-> (Vec3, Quat) Add Translation2/3/4 <-> Vec2/3/4 --- src/third_party/glam/glam_isometry.rs | 68 +++++++++++++++++++++++- src/third_party/glam/glam_translation.rs | 65 ++++++++++++++++++++++ src/third_party/glam/mod.rs | 1 + 3 files changed, 132 insertions(+), 2 deletions(-) create mode 100644 src/third_party/glam/glam_translation.rs diff --git a/src/third_party/glam/glam_isometry.rs b/src/third_party/glam/glam_isometry.rs index 52c36e37..34a321e5 100644 --- a/src/third_party/glam/glam_isometry.rs +++ b/src/third_party/glam/glam_isometry.rs @@ -1,5 +1,5 @@ use crate::{Isometry2, Isometry3}; -use glam::{DMat3, DMat4, Mat3, Mat4}; +use glam::{DMat3, DMat4, DQuat, DVec3, Mat3, Mat4, Quat, Vec3}; impl From> for Mat3 { fn from(iso: Isometry2) -> Mat3 { @@ -23,10 +23,74 @@ impl From> for DMat4 { } } +impl From> for (Vec3, Quat) { + fn from(iso: Isometry3) -> (Vec3, Quat) { + (iso.translation.into(), iso.rotation.into()) + } +} + +impl From> for (DVec3, DQuat) { + fn from(iso: Isometry3) -> (DVec3, DQuat) { + (iso.translation.into(), iso.rotation.into()) + } +} + +impl From> for (Vec3, Quat) { + fn from(iso: Isometry2) -> (Vec3, Quat) { + let tra = Vec3::new(iso.translation.x, iso.translation.y, 0.0); + let rot = Quat::from_axis_angle(Vec3::new(0.0, 0.0, 1.0), iso.rotation.angle()); + (tra, rot) + } +} + +impl From> for (DVec3, DQuat) { + fn from(iso: Isometry2) -> (DVec3, DQuat) { + let tra = DVec3::new(iso.translation.x, iso.translation.y, 0.0); + let rot = DQuat::from_axis_angle(DVec3::new(0.0, 0.0, 1.0), iso.rotation.angle()); + (tra, rot) + } +} + #[cfg(feature = "convert-glam-unchecked")] mod unchecked { use crate::{Isometry2, Isometry3, Matrix3, Matrix4}; - use glam::{DMat3, DMat4, Mat3, Mat4}; + use glam::{DMat3, DMat4, DQuat, DVec2, DVec3, Mat3, Mat4, Quat, Vec2, Vec3}; + + impl From<(Vec3, Quat)> for Isometry3 { + fn from((tra, rot): (Vec3, Quat)) -> Self { + Isometry3::from_parts(tra.into(), rot.into()) + } + } + + impl From<(DVec3, DQuat)> for Isometry3 { + fn from((tra, rot): (DVec3, DQuat)) -> Self { + Isometry3::from_parts(tra.into(), rot.into()) + } + } + + impl From<(Vec3, Quat)> for Isometry2 { + fn from((tra, rot): (Vec3, Quat)) -> Self { + Isometry2::new([tra.x, tra.y].into(), rot.to_axis_angle().1) + } + } + + impl From<(DVec3, DQuat)> for Isometry2 { + fn from((tra, rot): (DVec3, DQuat)) -> Self { + Isometry2::new([tra.x, tra.y].into(), rot.to_axis_angle().1) + } + } + + impl From<(Vec2, Quat)> for Isometry2 { + fn from((tra, rot): (Vec2, Quat)) -> Self { + Isometry2::new([tra.x, tra.y].into(), rot.to_axis_angle().1) + } + } + + impl From<(DVec2, DQuat)> for Isometry2 { + fn from((tra, rot): (DVec2, DQuat)) -> Self { + Isometry2::new([tra.x, tra.y].into(), rot.to_axis_angle().1) + } + } impl From for Isometry2 { fn from(mat3: Mat3) -> Isometry2 { diff --git a/src/third_party/glam/glam_translation.rs b/src/third_party/glam/glam_translation.rs new file mode 100644 index 00000000..f92d3275 --- /dev/null +++ b/src/third_party/glam/glam_translation.rs @@ -0,0 +1,65 @@ +use crate::{Translation2, Translation3, Translation4}; +use glam::{DVec2, DVec3, DVec4, Vec2, Vec3, Vec3A, Vec4}; + +macro_rules! impl_translation_conversion( + ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { + impl From<$Vec2> for Translation2<$N> { + #[inline] + fn from(e: $Vec2) -> Translation2<$N> { + (*e.as_ref()).into() + } + } + + impl From> for $Vec2 { + #[inline] + fn from(e: Translation2<$N>) -> $Vec2 { + e.vector.into() + } + } + + impl From<$Vec3> for Translation3<$N> { + #[inline] + fn from(e: $Vec3) -> Translation3<$N> { + (*e.as_ref()).into() + } + } + + impl From> for $Vec3 { + #[inline] + fn from(e: Translation3<$N>) -> $Vec3 { + e.vector.into() + } + } + + impl From<$Vec4> for Translation4<$N> { + #[inline] + fn from(e: $Vec4) -> Translation4<$N> { + (*e.as_ref()).into() + } + } + + impl From> for $Vec4 { + #[inline] + fn from(e: Translation4<$N>) -> $Vec4 { + e.vector.into() + } + } + } +); + +impl_translation_conversion!(f32, Vec2, Vec3, Vec4); +impl_translation_conversion!(f64, DVec2, DVec3, DVec4); + +impl From for Translation3 { + #[inline] + fn from(e: Vec3A) -> Translation3 { + (*e.as_ref()).into() + } +} + +impl From> for Vec3A { + #[inline] + fn from(e: Translation3) -> Vec3A { + e.vector.into() + } +} diff --git a/src/third_party/glam/mod.rs b/src/third_party/glam/mod.rs index d4f8b643..20925923 100644 --- a/src/third_party/glam/mod.rs +++ b/src/third_party/glam/mod.rs @@ -4,4 +4,5 @@ mod glam_point; mod glam_quaternion; mod glam_rotation; mod glam_similarity; +mod glam_translation; mod glam_unit_complex; From 0745384c2181fe273d1508c2715ff4f6dcb91a51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Tue, 27 Apr 2021 13:29:15 +0200 Subject: [PATCH 10/57] Update changelog. --- CHANGELOG.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 8c762fd5..029532b1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,16 @@ documented here. This project adheres to [Semantic Versioning](https://semver.org/). +## [0.26.2] +###Added +- Conversion from an array `[T; D]` to an isometry `Isometry` (as a translation). +- Conversion from a static vector `SVector` to an isometry `Isometry` (as a translation). +- Conversion from a point `Point` to an isometry `Isometry` (as a translation). +- Conversion of an array `[T; D]` from/to a translation `Translation`. +- Conversion of a point `Point` to a translation `Translation`. +- Conversion of the tuple of glam types `(Vec3, Quat)` from/to an `Isometry2` or `Isometry3`. +- Conversion of a glam type `Vec2/3/4` from/to a `Translation2/3/4`. + ## [0.26.1] Fix a regression introduced in 0.26.0 preventing `DVector` from being serialized with `serde`. From 58bea21d74e9f6df1376eb89ae94f5c1c3184101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Tue, 27 Apr 2021 14:26:09 +0200 Subject: [PATCH 11/57] Release v0.26.2 --- CHANGELOG.md | 2 +- Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 029532b1..450ec596 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,7 @@ documented here. This project adheres to [Semantic Versioning](https://semver.org/). ## [0.26.2] -###Added +### Added - Conversion from an array `[T; D]` to an isometry `Isometry` (as a translation). - Conversion from a static vector `SVector` to an isometry `Isometry` (as a translation). - Conversion from a point `Point` to an isometry `Isometry` (as a translation). diff --git a/Cargo.toml b/Cargo.toml index 3b86323f..45fdb17a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra" -version = "0.26.1" +version = "0.26.2" authors = [ "Sébastien Crozet " ] description = "General-purpose linear algebra library with transformations and statically-sized or dynamically-sized matrices." From c5a44ec66ff45c3c215075dbafca5a2b25aa53df Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Mon, 12 Apr 2021 02:41:13 -0300 Subject: [PATCH 12/57] Update criterion --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 45fdb17a..4a2a2eec 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,7 +85,7 @@ proptest = { version = "1", optional = true, default-features = false, features serde_json = "1.0" rand_xorshift = "0.3" rand_isaac = "0.3" -criterion = "0.2.10" +criterion = "0.3" # For matrix comparison macro matrixcompare = "0.2.0" From 209b4763019cbb05fb9fbf781436372dacc5d000 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Mon, 12 Apr 2021 02:41:31 -0300 Subject: [PATCH 13/57] Mark rand as required for benchmark --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 4a2a2eec..2c95a154 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -103,6 +103,7 @@ required-features = ["compare"] name = "nalgebra_bench" harness = false path = "benches/lib.rs" +required-features = ["rand"] [profile.bench] lto = true From 4bc62bcddbc1112e681d2528ec6b09fda3897964 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Mon, 12 Apr 2021 02:57:10 -0300 Subject: [PATCH 14/57] Fix benchmarks --- benches/core/matrix.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/benches/core/matrix.rs b/benches/core/matrix.rs index df4a5a5b..3c483c35 100644 --- a/benches/core/matrix.rs +++ b/benches/core/matrix.rs @@ -188,7 +188,7 @@ fn tr_mul_to(bench: &mut criterion::Criterion) { let b = DVector::::new_random(1000); let mut c = DVector::from_element(1000, 0.0); - bench.bench_function("", move |bh| bh.iter(|| a.tr_mul_to(&b, &mut c))); + bench.bench_function("tr_mul_to", move |bh| bh.iter(|| a.tr_mul_to(&b, &mut c))); } fn mat_mul_mat(bench: &mut criterion::Criterion) { From 35b96344ba0db5f8ef720b72a19f37c6ec74bc50 Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Mon, 12 Apr 2021 03:45:46 -0300 Subject: [PATCH 15/57] Fix criterion warning --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 2c95a154..2aae001f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -85,7 +85,7 @@ proptest = { version = "1", optional = true, default-features = false, features serde_json = "1.0" rand_xorshift = "0.3" rand_isaac = "0.3" -criterion = "0.3" +criterion = { version = "0.3", features = ["html_reports"] } # For matrix comparison macro matrixcompare = "0.2.0" From 4387a7f391b3277bafa41fe5c58b0236bdae578f Mon Sep 17 00:00:00 2001 From: Vinzent Steinberg Date: Thu, 29 Apr 2021 20:57:27 -0300 Subject: [PATCH 16/57] Use correct feature and remove unused import --- benches/lib.rs | 2 +- benches/linalg/eigen.rs | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/benches/lib.rs b/benches/lib.rs index a77cc743..1f75ff7e 100644 --- a/benches/lib.rs +++ b/benches/lib.rs @@ -1,4 +1,4 @@ -#![feature(test)] +#![feature(bench_black_box)] #![allow(unused_macros)] extern crate nalgebra as na; diff --git a/benches/linalg/eigen.rs b/benches/linalg/eigen.rs index 0b1e6b26..ec775d86 100644 --- a/benches/linalg/eigen.rs +++ b/benches/linalg/eigen.rs @@ -1,4 +1,3 @@ -use test::Bencher; use na::{DMatrix, Eigen}; fn eigen_100x100(bh: &mut criterion::Criterion) { From 105e894c0a350b61c8f86c77ba5e15b7cef6e98d Mon Sep 17 00:00:00 2001 From: Chammika Mannakkara Date: Sun, 2 May 2021 13:50:03 +0900 Subject: [PATCH 17/57] add missing doc tests --- src/base/componentwise.rs | 51 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/src/base/componentwise.rs b/src/base/componentwise.rs index b7030f61..2ba49b2a 100644 --- a/src/base/componentwise.rs +++ b/src/base/componentwise.rs @@ -240,6 +240,16 @@ impl> Matrix ); /// Computes the infimum (aka. componentwise min) of two matrices/vectors. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2; + /// let u = Matrix2::new(4.0, 2.0, 1.0, -2.0); + /// let v = Matrix2::new(2.0, 4.0, -2.0, 1.0); + /// let expected = Matrix2::new(2.0, 2.0, -2.0, -2.0); + /// assert_eq!(u.inf(&v), expected) + /// ``` #[inline] pub fn inf(&self, other: &Self) -> OMatrix where @@ -250,6 +260,16 @@ impl> Matrix } /// Computes the supremum (aka. componentwise max) of two matrices/vectors. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2; + /// let u = Matrix2::new(4.0, 2.0, 1.0, -2.0); + /// let v = Matrix2::new(2.0, 4.0, -2.0, 1.0); + /// let expected = Matrix2::new(4.0, 4.0, 1.0, 1.0); + /// assert_eq!(u.sup(&v), expected) + /// ``` #[inline] pub fn sup(&self, other: &Self) -> OMatrix where @@ -260,6 +280,16 @@ impl> Matrix } /// Computes the (infimum, supremum) of two matrices/vectors. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2; + /// let u = Matrix2::new(4.0, 2.0, 1.0, -2.0); + /// let v = Matrix2::new(2.0, 4.0, -2.0, 1.0); + /// let expected = (Matrix2::new(2.0, 2.0, -2.0, -2.0), Matrix2::new(4.0, 4.0, 1.0, 1.0)); + /// assert_eq!(u.inf_sup(&v), expected) + /// ``` #[inline] pub fn inf_sup(&self, other: &Self) -> (OMatrix, OMatrix) where @@ -271,6 +301,16 @@ impl> Matrix } /// Adds a scalar to `self`. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2; + /// let u = Matrix2::new(1.0, 2.0, 3.0, 4.0); + /// let s = 10.0; + /// let expected = Matrix2::new(11.0, 12.0, 13.0, 14.0); + /// assert_eq!(u.add_scalar(s), expected) + /// ``` #[inline] #[must_use = "Did you mean to use add_scalar_mut()?"] pub fn add_scalar(&self, rhs: T) -> OMatrix @@ -284,6 +324,17 @@ impl> Matrix } /// Adds a scalar to `self` in-place. + /// + /// # Example + /// + /// ``` + /// # use nalgebra::Matrix2; + /// let mut u = Matrix2::new(1.0, 2.0, 3.0, 4.0); + /// let s = 10.0; + /// u.add_scalar_mut(s); + /// let expected = Matrix2::new(11.0, 12.0, 13.0, 14.0); + /// assert_eq!(u, expected) + /// ``` #[inline] pub fn add_scalar_mut(&mut self, rhs: T) where From c420afde9e31bfc658450560132a30507df0a036 Mon Sep 17 00:00:00 2001 From: Chammika Mannakkara Date: Sun, 2 May 2021 20:43:16 +0900 Subject: [PATCH 18/57] CooMatrix::reserve added --- nalgebra-sparse/src/coo.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/nalgebra-sparse/src/coo.rs b/nalgebra-sparse/src/coo.rs index 50c68677..b300327d 100644 --- a/nalgebra-sparse/src/coo.rs +++ b/nalgebra-sparse/src/coo.rs @@ -130,6 +130,30 @@ impl CooMatrix { .map(|((i, j), v)| (*i, *j, v)) } + /// Reserves capacity for COO matrix by at least `additional` elements. + /// + /// This increase the capacities of triplet holding arrays by reserving more space to avoid + /// frequent reallocations, in `push` operations. + /// + /// ## Panics + /// + /// Panics if any of the individual allocation of triplet arrays fail. + /// + /// ## Example + /// + /// ``` + /// # use nalgebra_sparse::coo::CooMatrix; + /// let mut coo = CooMatrix::new(4, 4); + /// // Reserver capacity in advance + /// coo.reserve(10); + /// coo.push(1, 0, 3.0); + /// ``` + pub fn reserve(&mut self, additional: usize) { + self.row_indices.reserve(additional); + self.col_indices.reserve(additional); + self.values.reserve(additional); + } + /// Push a single triplet to the matrix. /// /// This adds the value `v` to the `i`th row and `j`th column in the matrix. From e97692255b863a8b47c037c5b855e00045d4dffa Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Sun, 11 Apr 2021 08:01:30 +0200 Subject: [PATCH 19/57] Initial hacked together prototype without syn --- Cargo.toml | 2 +- nalgebra-macros/Cargo.toml | 16 ++++++ nalgebra-macros/src/lib.rs | 99 ++++++++++++++++++++++++++++++++++ nalgebra-macros/tests/tests.rs | 6 +++ 4 files changed, 122 insertions(+), 1 deletion(-) create mode 100644 nalgebra-macros/Cargo.toml create mode 100644 nalgebra-macros/src/lib.rs create mode 100644 nalgebra-macros/tests/tests.rs diff --git a/Cargo.toml b/Cargo.toml index 45fdb17a..ad24b809 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -92,7 +92,7 @@ matrixcompare = "0.2.0" itertools = "0.10" [workspace] -members = [ "nalgebra-lapack", "nalgebra-glm", "nalgebra-sparse" ] +members = [ "nalgebra-lapack", "nalgebra-glm", "nalgebra-sparse", "nalgebra-macros" ] resolver = "2" [[example]] diff --git a/nalgebra-macros/Cargo.toml b/nalgebra-macros/Cargo.toml new file mode 100644 index 00000000..74b5d1b2 --- /dev/null +++ b/nalgebra-macros/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "nalgebra-macros" +version = "0.1.0" +authors = ["Andreas Longva "] +edition = "2018" + +[lib] +proc-macro = true + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +syn = "1.0" + +[dev-dependencies] +nalgebra = { version = "0.25.4", path = ".." } diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs new file mode 100644 index 00000000..b4e2d4b2 --- /dev/null +++ b/nalgebra-macros/src/lib.rs @@ -0,0 +1,99 @@ +extern crate proc_macro; + +use proc_macro::{TokenStream, TokenTree, Literal, Ident, Punct, Spacing, Group, Delimiter}; +use std::iter::FromIterator; + +struct MatrixEntries { + entries: Vec> +} + +impl MatrixEntries { + fn new() -> Self { + Self { + entries: Vec::new() + } + } + + fn begin_new_row(&mut self) { + self.entries.push(Vec::new()); + } + + fn push_entry(&mut self, entry: TokenTree) { + if self.entries.is_empty() { + self.entries.push(Vec::new()); + } + let mut last_row = self.entries.last_mut().unwrap(); + last_row.push(entry); + } + + fn build_stream(&self) -> TokenStream { + let num_rows = self.entries.len(); + let num_cols = self.entries.first() + .map(|first_row| first_row.len()) + .unwrap_or(0); + + // First check that dimensions are consistent + for (i, row) in self.entries.iter().enumerate() { + if row.len() != num_cols { + panic!("Unexpected number of columns in row {}: {}. Expected {}", i, row.len(), num_cols); + } + } + + let mut array_tokens = Vec::new(); + + // Collect entries in column major order + for i in 0 .. num_rows { + for j in 0 .. num_cols { + let entry = &self.entries[i][j]; + array_tokens.push(entry.clone()); + array_tokens.push(TokenTree::Punct(Punct::new(',', Spacing::Alone))); + } + } + + let row_dim = format!("U{}", num_rows); + let col_dim = format!("U{}", num_cols); + // let imports = format!("use nalgebra::\{Matrix, {}, {}\};", row_dim, col_dim); + // let constructor = format!("Matrix::<_, {}, {}>::from_slice", row_dim, col_dim); + // let array_group = Group::new(Delimiter::Bracket, TokenStream::from_iter(array_tokens.into_iter())); + + let array_stream = TokenStream::from_iter(array_tokens); + + // TODO: Build this up without parsing? + format!(r"{{ + nalgebra::MatrixMN::<_, nalgebra::{row_dim}, nalgebra::{col_dim}>::from_column_slice(&[ + {array_tokens} + ]) + }}", row_dim=row_dim, col_dim=col_dim, array_tokens=array_stream.to_string()).parse().unwrap() + + + // let mut outer_group = Group::new(Delimiter::Brace, + // + // ); + + + // TODO: Outer group + + + + + // todo!() + } +} + +#[proc_macro] +pub fn matrix(stream: TokenStream) -> TokenStream { + let mut entries = MatrixEntries::new(); + for tree in stream { + match tree { + // TokenTree::Ident(ident) => entries.push_entry(tree), + // TokenTree::Literal(literal) => entries.push_entry(tree), + TokenTree::Punct(punct) if punct == ';' => entries.begin_new_row(), + TokenTree::Punct(punct) if punct == ',' => {}, + // TokenTree::Punct(punct) => panic!("Unexpected punctuation: '{}'", punct), + // TokenTree::Group(_) => panic!("Unexpected token group"), + _ => entries.push_entry(tree) + } + } + + entries.build_stream() +} \ No newline at end of file diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs new file mode 100644 index 00000000..5763e139 --- /dev/null +++ b/nalgebra-macros/tests/tests.rs @@ -0,0 +1,6 @@ +use nalgebra_macros::matrix; + +#[test] +fn basic_usage() { + matrix![ 1, 3; 4, 5*3]; +} \ No newline at end of file From ab95cf702067a5cb81fcd98d0aa92d348cd45818 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Sun, 11 Apr 2021 11:08:41 +0200 Subject: [PATCH 20/57] Initial impl using syn and quote --- nalgebra-macros/Cargo.toml | 5 +- nalgebra-macros/src/lib.rs | 142 +++++++++++++++------------------ nalgebra-macros/tests/tests.rs | 4 +- 3 files changed, 71 insertions(+), 80 deletions(-) diff --git a/nalgebra-macros/Cargo.toml b/nalgebra-macros/Cargo.toml index 74b5d1b2..8e98e017 100644 --- a/nalgebra-macros/Cargo.toml +++ b/nalgebra-macros/Cargo.toml @@ -10,7 +10,10 @@ proc-macro = true # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -syn = "1.0" +# TODO: Determine minimal features that we need +syn = { version="1.0", features = ["full"] } +quote = "1.0" +proc-macro2 = "1.0" [dev-dependencies] nalgebra = { version = "0.25.4", path = ".." } diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs index b4e2d4b2..10127094 100644 --- a/nalgebra-macros/src/lib.rs +++ b/nalgebra-macros/src/lib.rs @@ -1,99 +1,85 @@ extern crate proc_macro; -use proc_macro::{TokenStream, TokenTree, Literal, Ident, Punct, Spacing, Group, Delimiter}; -use std::iter::FromIterator; +use syn::{Expr}; +use syn::parse::{Parse, ParseStream, Result, Error}; +use syn::punctuated::{Punctuated}; +use syn::{parse_macro_input, Token}; +use quote::{quote, format_ident}; +use proc_macro::TokenStream; -struct MatrixEntries { - entries: Vec> +struct Matrix { + // Represent the matrix as a row-major vector of vectors of expressions + rows: Vec>, + ncols: usize, } -impl MatrixEntries { - fn new() -> Self { - Self { - entries: Vec::new() +impl Matrix { + fn nrows(&self) -> usize { + self.rows.len() + } + + fn ncols(&self) -> usize { + self.ncols + } + + fn to_col_major_repr(&self) -> Vec { + let mut data = Vec::with_capacity(self.nrows() * self.ncols()); + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + data.push(self.rows[i][j].clone()); + } } + data } +} - fn begin_new_row(&mut self) { - self.entries.push(Vec::new()); - } +type MatrixRowSyntax = Punctuated; +type MatrixSyntax = Punctuated; - fn push_entry(&mut self, entry: TokenTree) { - if self.entries.is_empty() { - self.entries.push(Vec::new()); - } - let mut last_row = self.entries.last_mut().unwrap(); - last_row.push(entry); - } - - fn build_stream(&self) -> TokenStream { - let num_rows = self.entries.len(); - let num_cols = self.entries.first() - .map(|first_row| first_row.len()) +impl Parse for Matrix { + fn parse(input: ParseStream) -> Result { + let span = input.span(); + // TODO: Handle empty matrix case + let ast = MatrixSyntax::parse_separated_nonempty_with(input, + |input| MatrixRowSyntax::parse_separated_nonempty(input))?; + let ncols = ast.first().map(|row| row.len()) .unwrap_or(0); - // First check that dimensions are consistent - for (i, row) in self.entries.iter().enumerate() { - if row.len() != num_cols { - panic!("Unexpected number of columns in row {}: {}. Expected {}", i, row.len(), num_cols); + let mut rows = Vec::new(); + + for row in ast { + if row.len() != ncols { + // TODO: Is this the correct span? + // Currently it returns the span corresponding to the first element in the macro + // invocation, but it would be nice if it returned the span of the first element + // in the first row that has an unexpected number of columns + return Err(Error::new(span, "Unexpected number of columns. TODO")) } + rows.push(row.into_iter().collect()); } - let mut array_tokens = Vec::new(); - - // Collect entries in column major order - for i in 0 .. num_rows { - for j in 0 .. num_cols { - let entry = &self.entries[i][j]; - array_tokens.push(entry.clone()); - array_tokens.push(TokenTree::Punct(Punct::new(',', Spacing::Alone))); - } - } - - let row_dim = format!("U{}", num_rows); - let col_dim = format!("U{}", num_cols); - // let imports = format!("use nalgebra::\{Matrix, {}, {}\};", row_dim, col_dim); - // let constructor = format!("Matrix::<_, {}, {}>::from_slice", row_dim, col_dim); - // let array_group = Group::new(Delimiter::Bracket, TokenStream::from_iter(array_tokens.into_iter())); - - let array_stream = TokenStream::from_iter(array_tokens); - - // TODO: Build this up without parsing? - format!(r"{{ - nalgebra::MatrixMN::<_, nalgebra::{row_dim}, nalgebra::{col_dim}>::from_column_slice(&[ - {array_tokens} - ]) - }}", row_dim=row_dim, col_dim=col_dim, array_tokens=array_stream.to_string()).parse().unwrap() - - - // let mut outer_group = Group::new(Delimiter::Brace, - // - // ); - - - // TODO: Outer group - - - - - // todo!() + Ok(Self { + rows, + ncols + }) } } #[proc_macro] pub fn matrix(stream: TokenStream) -> TokenStream { - let mut entries = MatrixEntries::new(); - for tree in stream { - match tree { - // TokenTree::Ident(ident) => entries.push_entry(tree), - // TokenTree::Literal(literal) => entries.push_entry(tree), - TokenTree::Punct(punct) if punct == ';' => entries.begin_new_row(), - TokenTree::Punct(punct) if punct == ',' => {}, - // TokenTree::Punct(punct) => panic!("Unexpected punctuation: '{}'", punct), - // TokenTree::Group(_) => panic!("Unexpected token group"), - _ => entries.push_entry(tree) - } - } + let matrix = parse_macro_input!(stream as Matrix); - entries.build_stream() + let dim_ident = |dim| format_ident!("U{}", dim); + let row_dim = dim_ident(matrix.nrows()); + let col_dim = dim_ident(matrix.ncols()); + let entries_col_major = matrix.to_col_major_repr(); + + // TODO: Use quote_spanned instead?? + // TODO: Construct directly from array? + let output = quote! { + nalgebra::MatrixMN::<_, nalgebra::dimension::#row_dim, nalgebra::dimension::#col_dim> + ::from_column_slice(&[#(#entries_col_major),*]) + }; + + proc_macro::TokenStream::from(output) } \ No newline at end of file diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index 5763e139..5c87ad87 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -2,5 +2,7 @@ use nalgebra_macros::matrix; #[test] fn basic_usage() { - matrix![ 1, 3; 4, 5*3]; + matrix![ 1, 3; + 4, 5*3; + 3, 3]; } \ No newline at end of file From ed833506a9d152776f251684facf9b7d7154a39d Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Sun, 11 Apr 2021 17:29:33 +0200 Subject: [PATCH 21/57] Fix warnings, refactor code --- nalgebra-macros/src/lib.rs | 40 ++++++++++++++++++++-------------- nalgebra-macros/tests/tests.rs | 10 +++++---- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs index 10127094..3a75b471 100644 --- a/nalgebra-macros/src/lib.rs +++ b/nalgebra-macros/src/lib.rs @@ -34,33 +34,41 @@ impl Matrix { } type MatrixRowSyntax = Punctuated; -type MatrixSyntax = Punctuated; impl Parse for Matrix { fn parse(input: ParseStream) -> Result { - let span = input.span(); - // TODO: Handle empty matrix case - let ast = MatrixSyntax::parse_separated_nonempty_with(input, - |input| MatrixRowSyntax::parse_separated_nonempty(input))?; - let ncols = ast.first().map(|row| row.len()) - .unwrap_or(0); - let mut rows = Vec::new(); + let mut ncols = None; - for row in ast { - if row.len() != ncols { - // TODO: Is this the correct span? - // Currently it returns the span corresponding to the first element in the macro - // invocation, but it would be nice if it returned the span of the first element - // in the first row that has an unexpected number of columns - return Err(Error::new(span, "Unexpected number of columns. TODO")) + while !input.is_empty() { + let row_span = input.span(); + let row = MatrixRowSyntax::parse_separated_nonempty(input)?; + + if let Some(ncols) = ncols { + if row.len() != ncols { + let row_idx = rows.len(); + let error_msg = format!( + "Unexpected number of entries in row {}. Expected {}, found {} entries.", + row_idx, + ncols, + row.len()); + return Err(Error::new(row_span, error_msg)); + } + } else { + ncols = Some(row.len()); } rows.push(row.into_iter().collect()); + + // We've just read a row, so if there are more tokens, there must be a semi-colon, + // otherwise the input is malformed + if !input.is_empty() { + input.parse::()?; + } } Ok(Self { rows, - ncols + ncols: ncols.unwrap_or(0) }) } } diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index 5c87ad87..ddbcc1ed 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -1,8 +1,10 @@ use nalgebra_macros::matrix; +use nalgebra::Matrix3x2; #[test] -fn basic_usage() { - matrix![ 1, 3; - 4, 5*3; - 3, 3]; +fn matrix_basic_construction() { + let matrix: Matrix3x2<_> = matrix![ 1, 2; + 3, 4; + 5, 6 ]; + assert_eq!(matrix, Matrix3x2::new(1, 2, 3, 4, 5, 6)); } \ No newline at end of file From 1dccdb1f20b6579969f82d9c2c5ec4b300085d57 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Mon, 12 Apr 2021 08:36:38 +0200 Subject: [PATCH 22/57] Exhaustive tests for small dimensions --- nalgebra-macros/src/lib.rs | 2 +- nalgebra-macros/tests/tests.rs | 37 ++++++++++++++++++++++++++++------ 2 files changed, 32 insertions(+), 7 deletions(-) diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs index 3a75b471..16fbe6da 100644 --- a/nalgebra-macros/src/lib.rs +++ b/nalgebra-macros/src/lib.rs @@ -85,7 +85,7 @@ pub fn matrix(stream: TokenStream) -> TokenStream { // TODO: Use quote_spanned instead?? // TODO: Construct directly from array? let output = quote! { - nalgebra::MatrixMN::<_, nalgebra::dimension::#row_dim, nalgebra::dimension::#col_dim> + nalgebra::MatrixMN::<_, nalgebra::#row_dim, nalgebra::dimension::#col_dim> ::from_column_slice(&[#(#entries_col_major),*]) }; diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index ddbcc1ed..cd2c3623 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -1,10 +1,35 @@ use nalgebra_macros::matrix; -use nalgebra::Matrix3x2; +use nalgebra::{MatrixMN, Matrix3x2, U0, U1, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2x1, Matrix2, Matrix2x3, Matrix2x4, Matrix3x1, Matrix3, Matrix3x4, Matrix4x1, Matrix4x2, Matrix4x3, Matrix4}; #[test] -fn matrix_basic_construction() { - let matrix: Matrix3x2<_> = matrix![ 1, 2; - 3, 4; - 5, 6 ]; - assert_eq!(matrix, Matrix3x2::new(1, 2, 3, 4, 5, 6)); +fn matrix_small_dims_exhaustive() { + // 0x0 + assert_eq!(matrix![], MatrixMN::::zeros()); + + // 1xN + assert_eq!(matrix![1], MatrixMN::::new(1)); + assert_eq!(matrix![1, 2], Matrix1x2::new(1, 2)); + assert_eq!(matrix![1, 2, 3], Matrix1x3::new(1, 2, 3)); + assert_eq!(matrix![1, 2, 3, 4], Matrix1x4::new(1, 2, 3, 4)); + + // 2xN + assert_eq!(matrix![1; 2], Matrix2x1::new(1, 2)); + assert_eq!(matrix![1, 2; 3, 4], Matrix2::new(1, 2, 3, 4)); + assert_eq!(matrix![1, 2, 3; 4, 5, 6], Matrix2x3::new(1, 2, 3, 4, 5, 6)); + assert_eq!(matrix![1, 2, 3, 4; 5, 6, 7, 8], Matrix2x4::new(1, 2, 3, 4, 5, 6, 7, 8)); + + // 3xN + assert_eq!(matrix![1; 2; 3], Matrix3x1::new(1, 2, 3)); + assert_eq!(matrix![1, 2; 3, 4; 5, 6], Matrix3x2::new(1, 2, 3, 4, 5, 6)); + assert_eq!(matrix![1, 2, 3; 4, 5, 6; 7, 8, 9], Matrix3::new(1, 2, 3, 4, 5, 6, 7, 8, 9)); + assert_eq!(matrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12], + Matrix3x4::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); + + // 4xN + assert_eq!(matrix![1; 2; 3; 4], Matrix4x1::new(1, 2, 3, 4)); + assert_eq!(matrix![1, 2; 3, 4; 5, 6; 7, 8], Matrix4x2::new(1, 2, 3, 4, 5, 6, 7, 8)); + assert_eq!(matrix![1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12], + Matrix4x3::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); + assert_eq!(matrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12; 13, 14, 15, 16], + Matrix4::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); } \ No newline at end of file From e60136fbb18759fe7c9d8275290cabdd5f35df69 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Wed, 14 Apr 2021 17:30:52 +0200 Subject: [PATCH 23/57] Update nalgebra-macros to nalgebra 0.26 and const generics --- nalgebra-macros/Cargo.toml | 2 +- nalgebra-macros/src/lib.rs | 7 +++---- nalgebra-macros/tests/tests.rs | 6 +++--- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/nalgebra-macros/Cargo.toml b/nalgebra-macros/Cargo.toml index 8e98e017..1f27b572 100644 --- a/nalgebra-macros/Cargo.toml +++ b/nalgebra-macros/Cargo.toml @@ -16,4 +16,4 @@ quote = "1.0" proc-macro2 = "1.0" [dev-dependencies] -nalgebra = { version = "0.25.4", path = ".." } +nalgebra = { version = "0.26.1", path = ".." } diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs index 16fbe6da..154f4876 100644 --- a/nalgebra-macros/src/lib.rs +++ b/nalgebra-macros/src/lib.rs @@ -77,15 +77,14 @@ impl Parse for Matrix { pub fn matrix(stream: TokenStream) -> TokenStream { let matrix = parse_macro_input!(stream as Matrix); - let dim_ident = |dim| format_ident!("U{}", dim); - let row_dim = dim_ident(matrix.nrows()); - let col_dim = dim_ident(matrix.ncols()); + let row_dim = matrix.nrows(); + let col_dim = matrix.ncols(); let entries_col_major = matrix.to_col_major_repr(); // TODO: Use quote_spanned instead?? // TODO: Construct directly from array? let output = quote! { - nalgebra::MatrixMN::<_, nalgebra::#row_dim, nalgebra::dimension::#col_dim> + nalgebra::SMatrix::<_, #row_dim, #col_dim> ::from_column_slice(&[#(#entries_col_major),*]) }; diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index cd2c3623..5d5a91b0 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -1,13 +1,13 @@ use nalgebra_macros::matrix; -use nalgebra::{MatrixMN, Matrix3x2, U0, U1, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2x1, Matrix2, Matrix2x3, Matrix2x4, Matrix3x1, Matrix3, Matrix3x4, Matrix4x1, Matrix4x2, Matrix4x3, Matrix4}; +use nalgebra::{SMatrix, Matrix3x2, U0, U1, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2x1, Matrix2, Matrix2x3, Matrix2x4, Matrix3x1, Matrix3, Matrix3x4, Matrix4x1, Matrix4x2, Matrix4x3, Matrix4}; #[test] fn matrix_small_dims_exhaustive() { // 0x0 - assert_eq!(matrix![], MatrixMN::::zeros()); + assert_eq!(matrix![], SMatrix::::zeros()); // 1xN - assert_eq!(matrix![1], MatrixMN::::new(1)); + assert_eq!(matrix![1], SMatrix::::new(1)); assert_eq!(matrix![1, 2], Matrix1x2::new(1, 2)); assert_eq!(matrix![1, 2, 3], Matrix1x3::new(1, 2, 3)); assert_eq!(matrix![1, 2, 3, 4], Matrix1x4::new(1, 2, 3, 4)); From ec2a5a39090ce39ef73f8a133e4a1dc11240e18b Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Sat, 17 Apr 2021 09:43:55 +0200 Subject: [PATCH 24/57] Construct ArrayStorage directly in matrix![] --- nalgebra-macros/src/lib.rs | 30 ++++++++++++++++++++---------- nalgebra-macros/tests/tests.rs | 2 +- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs index 154f4876..06f6a2cc 100644 --- a/nalgebra-macros/src/lib.rs +++ b/nalgebra-macros/src/lib.rs @@ -4,9 +4,12 @@ use syn::{Expr}; use syn::parse::{Parse, ParseStream, Result, Error}; use syn::punctuated::{Punctuated}; use syn::{parse_macro_input, Token}; -use quote::{quote, format_ident}; +use quote::{quote, TokenStreamExt}; use proc_macro::TokenStream; +use proc_macro2::{TokenStream as TokenStream2, Delimiter, TokenTree, Spacing}; +use proc_macro2::{Group, Punct}; + struct Matrix { // Represent the matrix as a row-major vector of vectors of expressions rows: Vec>, @@ -22,14 +25,18 @@ impl Matrix { self.ncols } - fn to_col_major_repr(&self) -> Vec { - let mut data = Vec::with_capacity(self.nrows() * self.ncols()); + /// Produces a stream of tokens representing this matrix as a column-major array. + fn col_major_array_tokens(&self) -> TokenStream2 { + let mut result = TokenStream2::new(); for j in 0 .. self.ncols() { - for i in 0 .. self.nrows() { - data.push(self.rows[i][j].clone()); - } + let mut col = TokenStream2::new(); + let col_iter = (0 .. self.nrows()) + .map(move |i| &self.rows[i][j]); + col.append_separated(col_iter, Punct::new(',', Spacing::Alone)); + result.append(Group::new(Delimiter::Bracket, col)); + result.append(Punct::new(',', Spacing::Alone)); } - data + TokenStream2::from(TokenTree::Group(Group::new(Delimiter::Bracket, result))) } } @@ -79,13 +86,16 @@ pub fn matrix(stream: TokenStream) -> TokenStream { let row_dim = matrix.nrows(); let col_dim = matrix.ncols(); - let entries_col_major = matrix.to_col_major_repr(); + + let array_tokens = matrix.col_major_array_tokens(); // TODO: Use quote_spanned instead?? - // TODO: Construct directly from array? + // TODO: Avoid use of unsafe here let output = quote! { + unsafe { nalgebra::SMatrix::<_, #row_dim, #col_dim> - ::from_column_slice(&[#(#entries_col_major),*]) + ::from_data_statically_unchecked(nalgebra::ArrayStorage(#array_tokens)) + } }; proc_macro::TokenStream::from(output) diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index 5d5a91b0..1113a79d 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -1,5 +1,5 @@ use nalgebra_macros::matrix; -use nalgebra::{SMatrix, Matrix3x2, U0, U1, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2x1, Matrix2, Matrix2x3, Matrix2x4, Matrix3x1, Matrix3, Matrix3x4, Matrix4x1, Matrix4x2, Matrix4x3, Matrix4}; +use nalgebra::{SMatrix, Matrix3x2, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2x1, Matrix2, Matrix2x3, Matrix2x4, Matrix3x1, Matrix3, Matrix3x4, Matrix4x1, Matrix4x2, Matrix4x3, Matrix4}; #[test] fn matrix_small_dims_exhaustive() { From 7098a4f07ec49044514e149b20e07a68b339622e Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Sat, 17 Apr 2021 09:45:53 +0200 Subject: [PATCH 25/57] Test that matrix![] can be used with const --- nalgebra-macros/tests/tests.rs | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index 1113a79d..0b594b31 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -32,4 +32,12 @@ fn matrix_small_dims_exhaustive() { Matrix4x3::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); assert_eq!(matrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12; 13, 14, 15, 16], Matrix4::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); +} + +#[test] +fn matrix_const_fn() { + // Ensure that matrix! can be used in const contexts + const _: SMatrix = matrix![]; + const _: SMatrix = matrix![1, 2]; + const _: SMatrix = matrix![1, 2, 3; 4, 5, 6]; } \ No newline at end of file From 9142dc8f84fa466114c8e784f05b8f6d5f961242 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Sat, 17 Apr 2021 16:41:52 +0200 Subject: [PATCH 26/57] Implement SMatrix::from_array_storage and use it in matriX! impl This allows us to avoid injecting unsafe code into every macro invocation, which seems desirable. --- nalgebra-macros/src/lib.rs | 5 +---- src/base/array_storage.rs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs index 06f6a2cc..a18162ab 100644 --- a/nalgebra-macros/src/lib.rs +++ b/nalgebra-macros/src/lib.rs @@ -90,12 +90,9 @@ pub fn matrix(stream: TokenStream) -> TokenStream { let array_tokens = matrix.col_major_array_tokens(); // TODO: Use quote_spanned instead?? - // TODO: Avoid use of unsafe here let output = quote! { - unsafe { nalgebra::SMatrix::<_, #row_dim, #col_dim> - ::from_data_statically_unchecked(nalgebra::ArrayStorage(#array_tokens)) - } + ::from_array_storage(nalgebra::ArrayStorage(#array_tokens)) }; proc_macro::TokenStream::from(output) diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index 68da4c51..dc6b22ce 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -25,6 +25,7 @@ use crate::base::storage::{ ContiguousStorage, ContiguousStorageMut, Owned, ReshapableStorage, Storage, StorageMut, }; use crate::base::Scalar; +use crate::SMatrix; /* * @@ -299,3 +300,14 @@ where self.as_slice().iter().fold(0, |acc, e| acc + e.extent()) } } + +// TODO: Where to put this impl block? +impl SMatrix { + /// Creates a new statically-allocated matrix from the given [ArrayStorage]. + #[inline(always)] + pub const fn from_array_storage(storage: ArrayStorage) -> Self { + // This is sound because the row and column types are exactly the same as that of the + // storage, so there can be no mismatch + unsafe { Self::from_data_statically_unchecked(storage) } + } +} From d2c11ad7975732b374d1448a4667db0f830f8634 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Sat, 17 Apr 2021 17:00:37 +0200 Subject: [PATCH 27/57] Impl DMatrix/DVector::from_vec_storage These methods enable safe & const construction of DMatrix/DVector from a given VecStorage. --- src/base/vec_storage.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/base/vec_storage.rs b/src/base/vec_storage.rs index 29da127d..15ea9237 100644 --- a/src/base/vec_storage.rs +++ b/src/base/vec_storage.rs @@ -15,6 +15,7 @@ use crate::base::{Scalar, Vector}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; +use crate::{DMatrix, DVector}; /* * @@ -410,3 +411,23 @@ impl Extend for VecStorage { self.nrows = Dynamic::new(self.data.len()); } } + +impl DMatrix +{ + /// Creates a new heap-allocated matrix from the given [VecStorage]. + pub const fn from_vec_storage(storage: VecStorage) -> Self { + // This is sound because the dimensions of the matrix and the storage are guaranteed + // to be the same + unsafe { Self::from_data_statically_unchecked(storage) } + } +} + +impl DVector +{ + /// Creates a new heap-allocated matrix from the given [VecStorage]. + pub const fn from_vec_storage(storage: VecStorage) -> Self { + // This is sound because the dimensions of the matrix and the storage are guaranteed + // to be the same + unsafe { Self::from_data_statically_unchecked(storage) } + } +} From 5c843022c2691664ec20447f406c56c9d9776944 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Thu, 29 Apr 2021 17:06:52 +0200 Subject: [PATCH 28/57] Implement dmatrix![] macro --- nalgebra-macros/src/lib.rs | 42 ++++++++++++++++++++++++++++++---- nalgebra-macros/tests/tests.rs | 39 ++++++++++++++++++++++++++++--- 2 files changed, 74 insertions(+), 7 deletions(-) diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs index a18162ab..c8b9b421 100644 --- a/nalgebra-macros/src/lib.rs +++ b/nalgebra-macros/src/lib.rs @@ -4,7 +4,7 @@ use syn::{Expr}; use syn::parse::{Parse, ParseStream, Result, Error}; use syn::punctuated::{Punctuated}; use syn::{parse_macro_input, Token}; -use quote::{quote, TokenStreamExt}; +use quote::{quote, TokenStreamExt, ToTokens}; use proc_macro::TokenStream; use proc_macro2::{TokenStream as TokenStream2, Delimiter, TokenTree, Spacing}; @@ -25,8 +25,8 @@ impl Matrix { self.ncols } - /// Produces a stream of tokens representing this matrix as a column-major array. - fn col_major_array_tokens(&self) -> TokenStream2 { + /// Produces a stream of tokens representing this matrix as a column-major nested array. + fn to_col_major_nested_array_tokens(&self) -> TokenStream2 { let mut result = TokenStream2::new(); for j in 0 .. self.ncols() { let mut col = TokenStream2::new(); @@ -38,6 +38,19 @@ impl Matrix { } TokenStream2::from(TokenTree::Group(Group::new(Delimiter::Bracket, result))) } + + /// Produces a stream of tokens representing this matrix as a column-major flat array + /// (suitable for representing e.g. a `DMatrix`). + fn to_col_major_flat_array_tokens(&self) -> TokenStream2 { + let mut data = TokenStream2::new(); + for j in 0 .. self.ncols() { + for i in 0 .. self.nrows() { + self.rows[i][j].to_tokens(&mut data); + data.append(Punct::new(',', Spacing::Alone)); + } + } + TokenStream2::from(TokenTree::Group(Group::new(Delimiter::Bracket, data))) + } } type MatrixRowSyntax = Punctuated; @@ -87,7 +100,7 @@ pub fn matrix(stream: TokenStream) -> TokenStream { let row_dim = matrix.nrows(); let col_dim = matrix.ncols(); - let array_tokens = matrix.col_major_array_tokens(); + let array_tokens = matrix.to_col_major_nested_array_tokens(); // TODO: Use quote_spanned instead?? let output = quote! { @@ -95,5 +108,26 @@ pub fn matrix(stream: TokenStream) -> TokenStream { ::from_array_storage(nalgebra::ArrayStorage(#array_tokens)) }; + proc_macro::TokenStream::from(output) +} + +#[proc_macro] +pub fn dmatrix(stream: TokenStream) -> TokenStream { + let matrix = parse_macro_input!(stream as Matrix); + + let row_dim = matrix.nrows(); + let col_dim = matrix.ncols(); + + let array_tokens = matrix.to_col_major_flat_array_tokens(); + + // TODO: Use quote_spanned instead?? + let output = quote! { + nalgebra::DMatrix::<_> + ::from_vec_storage(nalgebra::VecStorage::new( + nalgebra::Dynamic::new(#row_dim), + nalgebra::Dynamic::new(#col_dim), + vec!#array_tokens)) + }; + proc_macro::TokenStream::from(output) } \ No newline at end of file diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index 0b594b31..8610d07e 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -1,5 +1,5 @@ -use nalgebra_macros::matrix; -use nalgebra::{SMatrix, Matrix3x2, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2x1, Matrix2, Matrix2x3, Matrix2x4, Matrix3x1, Matrix3, Matrix3x4, Matrix4x1, Matrix4x2, Matrix4x3, Matrix4}; +use nalgebra_macros::{dmatrix, matrix}; +use nalgebra::{DMatrix, SMatrix, Matrix3x2, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2x1, Matrix2, Matrix2x3, Matrix2x4, Matrix3x1, Matrix3, Matrix3x4, Matrix4x1, Matrix4x2, Matrix4x3, Matrix4}; #[test] fn matrix_small_dims_exhaustive() { @@ -40,4 +40,37 @@ fn matrix_const_fn() { const _: SMatrix = matrix![]; const _: SMatrix = matrix![1, 2]; const _: SMatrix = matrix![1, 2, 3; 4, 5, 6]; -} \ No newline at end of file +} + +#[test] +fn dmatrix_small_dims_exhaustive() { + // 0x0 + assert_eq!(dmatrix![], DMatrix::::zeros(0, 0)); + + // // 1xN + assert_eq!(dmatrix![1], SMatrix::::new(1)); + assert_eq!(dmatrix![1, 2], Matrix1x2::new(1, 2)); + assert_eq!(dmatrix![1, 2, 3], Matrix1x3::new(1, 2, 3)); + assert_eq!(dmatrix![1, 2, 3, 4], Matrix1x4::new(1, 2, 3, 4)); + + // 2xN + assert_eq!(dmatrix![1; 2], Matrix2x1::new(1, 2)); + assert_eq!(dmatrix![1, 2; 3, 4], Matrix2::new(1, 2, 3, 4)); + assert_eq!(dmatrix![1, 2, 3; 4, 5, 6], Matrix2x3::new(1, 2, 3, 4, 5, 6)); + assert_eq!(dmatrix![1, 2, 3, 4; 5, 6, 7, 8], Matrix2x4::new(1, 2, 3, 4, 5, 6, 7, 8)); + + // 3xN + assert_eq!(dmatrix![1; 2; 3], Matrix3x1::new(1, 2, 3)); + assert_eq!(dmatrix![1, 2; 3, 4; 5, 6], Matrix3x2::new(1, 2, 3, 4, 5, 6)); + assert_eq!(dmatrix![1, 2, 3; 4, 5, 6; 7, 8, 9], Matrix3::new(1, 2, 3, 4, 5, 6, 7, 8, 9)); + assert_eq!(dmatrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12], + Matrix3x4::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); + + // 4xN + assert_eq!(dmatrix![1; 2; 3; 4], Matrix4x1::new(1, 2, 3, 4)); + assert_eq!(dmatrix![1, 2; 3, 4; 5, 6; 7, 8], Matrix4x2::new(1, 2, 3, 4, 5, 6, 7, 8)); + assert_eq!(dmatrix![1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12], + Matrix4x3::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); + assert_eq!(dmatrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12; 13, 14, 15, 16], + Matrix4::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); +} From d56db1a079b9aa4a1d550062a250959ab225de3b Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Fri, 30 Apr 2021 10:48:42 +0200 Subject: [PATCH 29/57] Assert type in matrix/dmatrix tests --- nalgebra-macros/tests/tests.rs | 86 +++++++++++++++++++--------------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index 8610d07e..f87028f5 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -1,36 +1,46 @@ use nalgebra_macros::{dmatrix, matrix}; use nalgebra::{DMatrix, SMatrix, Matrix3x2, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2x1, Matrix2, Matrix2x3, Matrix2x4, Matrix3x1, Matrix3, Matrix3x4, Matrix4x1, Matrix4x2, Matrix4x3, Matrix4}; +fn same_type(_: &T, _: &T) {} + +/// Wrapper for `assert_eq` that also asserts that the types are the same +macro_rules! assert_eq_and_type { + ($left:expr, $right:expr $(,)?) => { + same_type(&$left, &$right); + assert_eq!($left, $right); + }; +} + #[test] fn matrix_small_dims_exhaustive() { // 0x0 - assert_eq!(matrix![], SMatrix::::zeros()); + assert_eq_and_type!(matrix![], SMatrix::::zeros()); // 1xN - assert_eq!(matrix![1], SMatrix::::new(1)); - assert_eq!(matrix![1, 2], Matrix1x2::new(1, 2)); - assert_eq!(matrix![1, 2, 3], Matrix1x3::new(1, 2, 3)); - assert_eq!(matrix![1, 2, 3, 4], Matrix1x4::new(1, 2, 3, 4)); + assert_eq_and_type!(matrix![1], SMatrix::::new(1)); + assert_eq_and_type!(matrix![1, 2], Matrix1x2::new(1, 2)); + assert_eq_and_type!(matrix![1, 2, 3], Matrix1x3::new(1, 2, 3)); + assert_eq_and_type!(matrix![1, 2, 3, 4], Matrix1x4::new(1, 2, 3, 4)); // 2xN - assert_eq!(matrix![1; 2], Matrix2x1::new(1, 2)); - assert_eq!(matrix![1, 2; 3, 4], Matrix2::new(1, 2, 3, 4)); - assert_eq!(matrix![1, 2, 3; 4, 5, 6], Matrix2x3::new(1, 2, 3, 4, 5, 6)); - assert_eq!(matrix![1, 2, 3, 4; 5, 6, 7, 8], Matrix2x4::new(1, 2, 3, 4, 5, 6, 7, 8)); + assert_eq_and_type!(matrix![1; 2], Matrix2x1::new(1, 2)); + assert_eq_and_type!(matrix![1, 2; 3, 4], Matrix2::new(1, 2, 3, 4)); + assert_eq_and_type!(matrix![1, 2, 3; 4, 5, 6], Matrix2x3::new(1, 2, 3, 4, 5, 6)); + assert_eq_and_type!(matrix![1, 2, 3, 4; 5, 6, 7, 8], Matrix2x4::new(1, 2, 3, 4, 5, 6, 7, 8)); // 3xN - assert_eq!(matrix![1; 2; 3], Matrix3x1::new(1, 2, 3)); - assert_eq!(matrix![1, 2; 3, 4; 5, 6], Matrix3x2::new(1, 2, 3, 4, 5, 6)); - assert_eq!(matrix![1, 2, 3; 4, 5, 6; 7, 8, 9], Matrix3::new(1, 2, 3, 4, 5, 6, 7, 8, 9)); - assert_eq!(matrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12], + assert_eq_and_type!(matrix![1; 2; 3], Matrix3x1::new(1, 2, 3)); + assert_eq_and_type!(matrix![1, 2; 3, 4; 5, 6], Matrix3x2::new(1, 2, 3, 4, 5, 6)); + assert_eq_and_type!(matrix![1, 2, 3; 4, 5, 6; 7, 8, 9], Matrix3::new(1, 2, 3, 4, 5, 6, 7, 8, 9)); + assert_eq_and_type!(matrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12], Matrix3x4::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); // 4xN - assert_eq!(matrix![1; 2; 3; 4], Matrix4x1::new(1, 2, 3, 4)); - assert_eq!(matrix![1, 2; 3, 4; 5, 6; 7, 8], Matrix4x2::new(1, 2, 3, 4, 5, 6, 7, 8)); - assert_eq!(matrix![1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12], + assert_eq_and_type!(matrix![1; 2; 3; 4], Matrix4x1::new(1, 2, 3, 4)); + assert_eq_and_type!(matrix![1, 2; 3, 4; 5, 6; 7, 8], Matrix4x2::new(1, 2, 3, 4, 5, 6, 7, 8)); + assert_eq_and_type!(matrix![1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12], Matrix4x3::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); - assert_eq!(matrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12; 13, 14, 15, 16], + assert_eq_and_type!(matrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12; 13, 14, 15, 16], Matrix4::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); } @@ -45,32 +55,32 @@ fn matrix_const_fn() { #[test] fn dmatrix_small_dims_exhaustive() { // 0x0 - assert_eq!(dmatrix![], DMatrix::::zeros(0, 0)); + assert_eq_and_type!(dmatrix![], DMatrix::::zeros(0, 0)); - // // 1xN - assert_eq!(dmatrix![1], SMatrix::::new(1)); - assert_eq!(dmatrix![1, 2], Matrix1x2::new(1, 2)); - assert_eq!(dmatrix![1, 2, 3], Matrix1x3::new(1, 2, 3)); - assert_eq!(dmatrix![1, 2, 3, 4], Matrix1x4::new(1, 2, 3, 4)); + // 1xN + assert_eq_and_type!(dmatrix![1], DMatrix::from_row_slice(1, 1, &[1])); + assert_eq_and_type!(dmatrix![1, 2], DMatrix::from_row_slice(1, 2, &[1, 2])); + assert_eq_and_type!(dmatrix![1, 2, 3], DMatrix::from_row_slice(1, 3, &[1, 2, 3])); + assert_eq_and_type!(dmatrix![1, 2, 3, 4], DMatrix::from_row_slice(1, 4, &[1, 2, 3, 4])); // 2xN - assert_eq!(dmatrix![1; 2], Matrix2x1::new(1, 2)); - assert_eq!(dmatrix![1, 2; 3, 4], Matrix2::new(1, 2, 3, 4)); - assert_eq!(dmatrix![1, 2, 3; 4, 5, 6], Matrix2x3::new(1, 2, 3, 4, 5, 6)); - assert_eq!(dmatrix![1, 2, 3, 4; 5, 6, 7, 8], Matrix2x4::new(1, 2, 3, 4, 5, 6, 7, 8)); + assert_eq_and_type!(dmatrix![1; 2], DMatrix::from_row_slice(2, 1, &[1, 2])); + assert_eq_and_type!(dmatrix![1, 2; 3, 4], DMatrix::from_row_slice(2, 2, &[1, 2, 3, 4])); + assert_eq_and_type!(dmatrix![1, 2, 3; 4, 5, 6], DMatrix::from_row_slice(2, 3, &[1, 2, 3, 4, 5, 6])); + assert_eq_and_type!(dmatrix![1, 2, 3, 4; 5, 6, 7, 8], DMatrix::from_row_slice(2, 4, &[1, 2, 3, 4, 5, 6, 7, 8])); // 3xN - assert_eq!(dmatrix![1; 2; 3], Matrix3x1::new(1, 2, 3)); - assert_eq!(dmatrix![1, 2; 3, 4; 5, 6], Matrix3x2::new(1, 2, 3, 4, 5, 6)); - assert_eq!(dmatrix![1, 2, 3; 4, 5, 6; 7, 8, 9], Matrix3::new(1, 2, 3, 4, 5, 6, 7, 8, 9)); - assert_eq!(dmatrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12], - Matrix3x4::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); + assert_eq_and_type!(dmatrix![1; 2; 3], DMatrix::from_row_slice(3, 1, &[1, 2, 3])); + assert_eq_and_type!(dmatrix![1, 2; 3, 4; 5, 6], DMatrix::from_row_slice(3, 2, &[1, 2, 3, 4, 5, 6])); + assert_eq_and_type!(dmatrix![1, 2, 3; 4, 5, 6; 7, 8, 9], DMatrix::from_row_slice(3, 3, &[1, 2, 3, 4, 5, 6, 7, 8, 9])); + assert_eq_and_type!(dmatrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12], + DMatrix::from_row_slice(3, 4, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])); // 4xN - assert_eq!(dmatrix![1; 2; 3; 4], Matrix4x1::new(1, 2, 3, 4)); - assert_eq!(dmatrix![1, 2; 3, 4; 5, 6; 7, 8], Matrix4x2::new(1, 2, 3, 4, 5, 6, 7, 8)); - assert_eq!(dmatrix![1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12], - Matrix4x3::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); - assert_eq!(dmatrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12; 13, 14, 15, 16], - Matrix4::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); + assert_eq_and_type!(dmatrix![1; 2; 3; 4], DMatrix::from_row_slice(4, 1, &[1, 2, 3, 4])); + assert_eq_and_type!(dmatrix![1, 2; 3, 4; 5, 6; 7, 8], DMatrix::from_row_slice(4, 2, &[1, 2, 3, 4, 5, 6, 7, 8])); + assert_eq_and_type!(dmatrix![1, 2, 3; 4, 5, 6; 7, 8, 9; 10, 11, 12], + DMatrix::from_row_slice(4, 3, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12])); + assert_eq_and_type!(dmatrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12; 13, 14, 15, 16], + DMatrix::from_row_slice(4, 4, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])); } From 07d41e457b78778e77fcbd93831ee248c780e3ff Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Fri, 30 Apr 2021 14:09:36 +0200 Subject: [PATCH 30/57] vector! and dvector! macros --- nalgebra-macros/src/lib.rs | 59 ++++++++++++++++++++++++++++++++++ nalgebra-macros/tests/tests.rs | 39 +++++++++++++++++++--- 2 files changed, 94 insertions(+), 4 deletions(-) diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs index c8b9b421..fd29b361 100644 --- a/nalgebra-macros/src/lib.rs +++ b/nalgebra-macros/src/lib.rs @@ -129,5 +129,64 @@ pub fn dmatrix(stream: TokenStream) -> TokenStream { vec!#array_tokens)) }; + proc_macro::TokenStream::from(output) +} + +struct Vector { + elements: Vec, +} + +impl Vector { + fn to_array_tokens(&self) -> TokenStream2 { + let mut data = TokenStream2::new(); + data.append_separated(&self.elements, Punct::new(',', Spacing::Alone)); + TokenStream2::from(TokenTree::Group(Group::new(Delimiter::Bracket, data))) + } + + fn len(&self) -> usize { + self.elements.len() + } +} + +impl Parse for Vector { + fn parse(input: ParseStream) -> Result { + // The syntax of a vector is just the syntax of a single matrix row + if input.is_empty() { + Ok(Self { + elements: Vec::new() + }) + } else { + let elements = MatrixRowSyntax::parse_separated_nonempty(input)?.into_iter().collect(); + Ok(Self { + elements + }) + } + } +} + +#[proc_macro] +pub fn vector(stream: TokenStream) -> TokenStream { + let vector = parse_macro_input!(stream as Vector); + let len = vector.len(); + let array_tokens = vector.to_array_tokens(); + let output = quote! { + nalgebra::SVector::<_, #len> + ::from_array_storage(nalgebra::ArrayStorage([#array_tokens])) + }; + proc_macro::TokenStream::from(output) +} + +#[proc_macro] +pub fn dvector(stream: TokenStream) -> TokenStream { + let vector = parse_macro_input!(stream as Vector); + let len = vector.len(); + let array_tokens = vector.to_array_tokens(); + let output = quote! { + nalgebra::DVector::<_> + ::from_vec_storage(nalgebra::VecStorage::new( + nalgebra::Dynamic::new(#len), + nalgebra::Const::<1>, + vec!#array_tokens)) + }; proc_macro::TokenStream::from(output) } \ No newline at end of file diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index f87028f5..c97ae103 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -1,12 +1,12 @@ -use nalgebra_macros::{dmatrix, matrix}; -use nalgebra::{DMatrix, SMatrix, Matrix3x2, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2x1, Matrix2, Matrix2x3, Matrix2x4, Matrix3x1, Matrix3, Matrix3x4, Matrix4x1, Matrix4x2, Matrix4x3, Matrix4}; +use nalgebra_macros::{dmatrix, dvector, matrix, vector}; +use nalgebra::{DMatrix, DVector, SMatrix, Matrix3x2, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2x1, Matrix2, Matrix2x3, Matrix2x4, Matrix3x1, Matrix3, Matrix3x4, Matrix4x1, Matrix4x2, Matrix4x3, Matrix4, Vector1, Vector2, Vector3, Vector4, Vector5, SVector, Vector6}; -fn same_type(_: &T, _: &T) {} +fn check_statically_same_type(_: &T, _: &T) {} /// Wrapper for `assert_eq` that also asserts that the types are the same macro_rules! assert_eq_and_type { ($left:expr, $right:expr $(,)?) => { - same_type(&$left, &$right); + check_statically_same_type(&$left, &$right); assert_eq!($left, $right); }; } @@ -84,3 +84,34 @@ fn dmatrix_small_dims_exhaustive() { assert_eq_and_type!(dmatrix![1, 2, 3, 4; 5, 6, 7, 8; 9, 10, 11, 12; 13, 14, 15, 16], DMatrix::from_row_slice(4, 4, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])); } + +#[test] +fn vector_small_dims_exhaustive() { + assert_eq_and_type!(vector![], SVector::::zeros()); + assert_eq_and_type!(vector![1], Vector1::::new(1)); + assert_eq_and_type!(vector![1, 2], Vector2::new(1, 2)); + assert_eq_and_type!(vector![1, 2, 3], Vector3::new(1, 2, 3)); + assert_eq_and_type!(vector![1, 2, 3, 4], Vector4::new(1, 2, 3, 4)); + assert_eq_and_type!(vector![1, 2, 3, 4, 5], Vector5::new(1, 2, 3, 4, 5)); + assert_eq_and_type!(vector![1, 2, 3, 4, 5, 6], Vector6::new(1, 2, 3, 4, 5, 6)); +} + +#[test] +fn vector_const_fn() { + // Ensure that vector! can be used in const contexts + const _: SVector = vector![]; + const _: Vector1 = vector![1]; + const _: Vector2 = vector![1, 2]; + const _: Vector6 = vector![1, 2, 3, 4, 5, 6]; +} + +#[test] +fn dvector_small_dims_exhaustive() { + assert_eq_and_type!(dvector![], DVector::::zeros(0)); + assert_eq_and_type!(dvector![1], DVector::from_column_slice(&[1])); + assert_eq_and_type!(dvector![1, 2], DVector::from_column_slice(&[1, 2])); + assert_eq_and_type!(dvector![1, 2, 3], DVector::from_column_slice(&[1, 2, 3])); + assert_eq_and_type!(dvector![1, 2, 3, 4], DVector::from_column_slice(&[1, 2, 3, 4])); + assert_eq_and_type!(dvector![1, 2, 3, 4, 5], DVector::from_column_slice(&[1, 2, 3, 4, 5])); + assert_eq_and_type!(dvector![1, 2, 3, 4, 5, 6], DVector::from_column_slice(&[1, 2, 3, 4, 5, 6])); +} \ No newline at end of file From da077497a2be5f455f4905ed0ef323604a091aca Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Fri, 30 Apr 2021 14:53:49 +0200 Subject: [PATCH 31/57] Add trybuild tests to test error message reported when matrix dims mismatch --- nalgebra-macros/Cargo.toml | 1 + nalgebra-macros/tests/tests.rs | 16 ++++++++++++++++ .../trybuild/dmatrix_mismatched_dimensions.rs | 6 ++++++ .../dmatrix_mismatched_dimensions.stderr | 5 +++++ .../trybuild/matrix_mismatched_dimensions.rs | 6 ++++++ .../trybuild/matrix_mismatched_dimensions.stderr | 5 +++++ 6 files changed, 39 insertions(+) create mode 100644 nalgebra-macros/tests/trybuild/dmatrix_mismatched_dimensions.rs create mode 100644 nalgebra-macros/tests/trybuild/dmatrix_mismatched_dimensions.stderr create mode 100644 nalgebra-macros/tests/trybuild/matrix_mismatched_dimensions.rs create mode 100644 nalgebra-macros/tests/trybuild/matrix_mismatched_dimensions.stderr diff --git a/nalgebra-macros/Cargo.toml b/nalgebra-macros/Cargo.toml index 1f27b572..5ebef960 100644 --- a/nalgebra-macros/Cargo.toml +++ b/nalgebra-macros/Cargo.toml @@ -17,3 +17,4 @@ proc-macro2 = "1.0" [dev-dependencies] nalgebra = { version = "0.26.1", path = ".." } +trybuild = "1.0.42" diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index c97ae103..c9d64d91 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -114,4 +114,20 @@ fn dvector_small_dims_exhaustive() { assert_eq_and_type!(dvector![1, 2, 3, 4], DVector::from_column_slice(&[1, 2, 3, 4])); assert_eq_and_type!(dvector![1, 2, 3, 4, 5], DVector::from_column_slice(&[1, 2, 3, 4, 5])); assert_eq_and_type!(dvector![1, 2, 3, 4, 5, 6], DVector::from_column_slice(&[1, 2, 3, 4, 5, 6])); +} + +#[test] +fn matrix_trybuild_tests() { + let t = trybuild::TestCases::new(); + + // Verify error message when we give a matrix with mismatched dimensions + t.compile_fail("tests/trybuild/matrix_mismatched_dimensions.rs"); +} + +#[test] +fn dmatrix_trybuild_tests() { + let t = trybuild::TestCases::new(); + + // Verify error message when we give a matrix with mismatched dimensions + t.compile_fail("tests/trybuild/dmatrix_mismatched_dimensions.rs"); } \ No newline at end of file diff --git a/nalgebra-macros/tests/trybuild/dmatrix_mismatched_dimensions.rs b/nalgebra-macros/tests/trybuild/dmatrix_mismatched_dimensions.rs new file mode 100644 index 00000000..786b5849 --- /dev/null +++ b/nalgebra-macros/tests/trybuild/dmatrix_mismatched_dimensions.rs @@ -0,0 +1,6 @@ +use nalgebra_macros::dmatrix; + +fn main() { + dmatrix![1, 2, 3; + 4, 5]; +} \ No newline at end of file diff --git a/nalgebra-macros/tests/trybuild/dmatrix_mismatched_dimensions.stderr b/nalgebra-macros/tests/trybuild/dmatrix_mismatched_dimensions.stderr new file mode 100644 index 00000000..eaedc650 --- /dev/null +++ b/nalgebra-macros/tests/trybuild/dmatrix_mismatched_dimensions.stderr @@ -0,0 +1,5 @@ +error: Unexpected number of entries in row 1. Expected 3, found 2 entries. + --> $DIR/dmatrix_mismatched_dimensions.rs:5:13 + | +5 | 4, 5]; + | ^ diff --git a/nalgebra-macros/tests/trybuild/matrix_mismatched_dimensions.rs b/nalgebra-macros/tests/trybuild/matrix_mismatched_dimensions.rs new file mode 100644 index 00000000..c5eb87b7 --- /dev/null +++ b/nalgebra-macros/tests/trybuild/matrix_mismatched_dimensions.rs @@ -0,0 +1,6 @@ +use nalgebra_macros::matrix; + +fn main() { + matrix![1, 2, 3; + 4, 5]; +} \ No newline at end of file diff --git a/nalgebra-macros/tests/trybuild/matrix_mismatched_dimensions.stderr b/nalgebra-macros/tests/trybuild/matrix_mismatched_dimensions.stderr new file mode 100644 index 00000000..c83e8d0c --- /dev/null +++ b/nalgebra-macros/tests/trybuild/matrix_mismatched_dimensions.stderr @@ -0,0 +1,5 @@ +error: Unexpected number of entries in row 1. Expected 3, found 2 entries. + --> $DIR/matrix_mismatched_dimensions.rs:5:13 + | +5 | 4, 5]; + | ^ From b96c75549d2e52b2db92a535b009c1e7973e30de Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Fri, 30 Apr 2021 16:46:29 +0200 Subject: [PATCH 32/57] Document macros --- nalgebra-macros/src/lib.rs | 77 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 77 insertions(+) diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs index fd29b361..133ea41a 100644 --- a/nalgebra-macros/src/lib.rs +++ b/nalgebra-macros/src/lib.rs @@ -93,6 +93,39 @@ impl Parse for Matrix { } } +/// Construct a fixed-size matrix directly from data. +/// +/// This macro facilitates easy construction of matrices when the entries of the matrix are known +/// (either as constants or expressions). This macro produces an instance of `SMatrix`. This means +/// that the data of the matrix is stored on the stack, and its dimensions are fixed at +/// compile-time. If you want to construct a dynamic matrix, use [`dmatrix!`] instead. +/// +/// `matrix!` is intended to be both the simplest and most efficient way to construct (small) +/// matrices, and can also be used in *const fn* contexts. +/// +/// The syntax is MATLAB-like. Column elements are separated by a comma (`,`), and a semi-colon +/// (`;`) designates that a new row begins. +/// +/// # Examples +/// +/// ``` +/// use nalgebra::matrix; +/// +/// // Produces a Matrix3<_> == SMatrix<_, 3, 3> +/// let a = matrix![1, 2, 3; +/// 4, 5, 6; +/// 7, 8, 9]; +/// ``` +/// +/// You can construct matrices with arbitrary expressions for its elements: +/// +/// ``` +/// use nalgebra::{matrix, Matrix2}; +/// let theta = 0.45f64; +/// +/// let r = matrix![theta.cos(), - theta.sin(); +/// theta.sin(), theta.cos()]; +/// ``` #[proc_macro] pub fn matrix(stream: TokenStream) -> TokenStream { let matrix = parse_macro_input!(stream as Matrix); @@ -111,6 +144,20 @@ pub fn matrix(stream: TokenStream) -> TokenStream { proc_macro::TokenStream::from(output) } +/// Construct a dynamic matrix directly from data. +/// +/// The syntax is exactly the same as for [`matrix!`], but instead of producing instances of +/// `SMatrix`, it produces instances of `DMatrix`. At the moment it is not usable +/// in `const fn` contexts. +/// +/// ``` +/// use nalgebra::dmatrix; +/// +/// // Produces a DMatrix<_> +/// let a = dmatrix![1, 2, 3; +/// 4, 5, 6; +/// 7, 8, 9]; +/// ``` #[proc_macro] pub fn dmatrix(stream: TokenStream) -> TokenStream { let matrix = parse_macro_input!(stream as Matrix); @@ -164,6 +211,24 @@ impl Parse for Vector { } } +/// Construct a fixed-size column vector directly from data. +/// +/// Similarly to [`matrix!`], this macro facilitates easy construction of fixed-size vectors. +/// However, whereas the [`matrix!`] macro expects each row to be separated by a semi-colon, +/// the syntax of this macro is instead similar to `vec!`, in that the elements of the vector +/// are simply listed consecutively. +/// +/// `vector!` is intended to be the most readable and performant way of constructing small, +/// fixed-size vectors, and it is usable in `const fn` contexts. +/// +/// ## Examples +/// +/// ``` +/// use nalgebra::vector; +/// +/// // Produces a Vector3<_> == SVector<_, 3> +/// let v = vector![1, 2, 3]; +/// ``` #[proc_macro] pub fn vector(stream: TokenStream) -> TokenStream { let vector = parse_macro_input!(stream as Vector); @@ -176,6 +241,18 @@ pub fn vector(stream: TokenStream) -> TokenStream { proc_macro::TokenStream::from(output) } +/// Construct a dynamic column vector directly from data. +/// +/// The syntax is exactly the same as for [`vector!`], but instead of producing instances of +/// `SVector`, it produces instances of `DVector`. At the moment it is not usable +/// in `const fn` contexts. +/// +/// ``` +/// use nalgebra::dvector; +/// +/// // Produces a DVector<_> +/// let v = dvector![1, 2, 3]; +/// ``` #[proc_macro] pub fn dvector(stream: TokenStream) -> TokenStream { let vector = parse_macro_input!(stream as Vector); From eeab4db69a54c17aa0f43fb9c941e51bf86f5321 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Fri, 30 Apr 2021 16:47:09 +0200 Subject: [PATCH 33/57] Add nalgebra/macros feature and re-export matrix macros from nalgebra --- Cargo.toml | 4 +++- src/lib.rs | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ad24b809..1caec25f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -22,7 +22,7 @@ name = "nalgebra" path = "src/lib.rs" [features] -default = [ "std" ] +default = [ "std", "macros" ] std = [ "matrixmultiply", "simba/std" ] sparse = [ ] debug = [ "approx/num-complex", "rand" ] @@ -32,6 +32,7 @@ compare = [ "matrixcompare-core" ] libm = [ "simba/libm" ] libm-force = [ "simba/libm_force" ] no_unsound_assume_init = [ ] +macros = [ "nalgebra-macros" ] # Conversion convert-mint = [ "mint" ] @@ -60,6 +61,7 @@ proptest-support = [ "proptest" ] slow-tests = [] [dependencies] +nalgebra-macros = { version = "0.1", path = "nalgebra-macros", optional = true } typenum = "1.12" rand-package = { package = "rand", version = "0.8", optional = true, default-features = false } num-traits = { version = "0.2", default-features = false } diff --git a/src/lib.rs b/src/lib.rs index bc6d1718..ea05e17d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -136,6 +136,9 @@ pub use crate::sparse::*; )] pub use base as core; +#[cfg(feature = "macros")] +pub use nalgebra_macros::{dmatrix, dvector, matrix, vector}; + use simba::scalar::SupersetOf; use std::cmp::{self, Ordering, PartialOrd}; From 0bde07f95c3aa178a22466c18d69fc11439b1d81 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Fri, 30 Apr 2021 17:06:59 +0200 Subject: [PATCH 34/57] Document that feature needs to be enabled, and require macros feature for tests --- Cargo.toml | 2 +- nalgebra-macros/src/lib.rs | 13 +++++++++++++ tests/lib.rs | 8 +++++--- 3 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1caec25f..71f72384 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -111,4 +111,4 @@ lto = true [package.metadata.docs.rs] # Enable certain features when building docs for docs.rs -features = [ "proptest-support", "compare" ] +features = [ "proptest-support", "compare", "macros" ] diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs index 133ea41a..c00a538f 100644 --- a/nalgebra-macros/src/lib.rs +++ b/nalgebra-macros/src/lib.rs @@ -1,3 +1,8 @@ +//! Macros for `nalgebra`. +//! +//! This crate is not intended for direct consumption. Instead, the macros are re-exported by +//! `nalgebra` if the `macros` feature is enabled (enabled by default). + extern crate proc_macro; use syn::{Expr}; @@ -95,6 +100,8 @@ impl Parse for Matrix { /// Construct a fixed-size matrix directly from data. /// +/// **Note: Requires the `macro` feature to be enabled (enabled by default)**. +/// /// This macro facilitates easy construction of matrices when the entries of the matrix are known /// (either as constants or expressions). This macro produces an instance of `SMatrix`. This means /// that the data of the matrix is stored on the stack, and its dimensions are fixed at @@ -146,6 +153,8 @@ pub fn matrix(stream: TokenStream) -> TokenStream { /// Construct a dynamic matrix directly from data. /// +/// **Note: Requires the `macro` feature to be enabled (enabled by default)**. +/// /// The syntax is exactly the same as for [`matrix!`], but instead of producing instances of /// `SMatrix`, it produces instances of `DMatrix`. At the moment it is not usable /// in `const fn` contexts. @@ -213,6 +222,8 @@ impl Parse for Vector { /// Construct a fixed-size column vector directly from data. /// +/// **Note: Requires the `macro` feature to be enabled (enabled by default)**. +/// /// Similarly to [`matrix!`], this macro facilitates easy construction of fixed-size vectors. /// However, whereas the [`matrix!`] macro expects each row to be separated by a semi-colon, /// the syntax of this macro is instead similar to `vec!`, in that the elements of the vector @@ -243,6 +254,8 @@ pub fn vector(stream: TokenStream) -> TokenStream { /// Construct a dynamic column vector directly from data. /// +/// **Note: Requires the `macro` feature to be enabled (enabled by default)**. +/// /// The syntax is exactly the same as for [`vector!`], but instead of producing instances of /// `SVector`, it produces instances of `DVector`. At the moment it is not usable /// in `const fn` contexts. diff --git a/tests/lib.rs b/tests/lib.rs index 8ee85f07..b1da01c3 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,7 +1,7 @@ -#[cfg(not(all(feature = "debug", feature = "compare", feature = "rand")))] +#[cfg(not(all(feature = "debug", feature = "compare", feature = "rand", feature = "macros")))] compile_error!( - "Please enable the `debug`, `compare`, and `rand` features in order to compile and run the tests. - Example: `cargo test --features debug,compare,rand`" + "Please enable the `debug`, `compare`, `rand` and `macros` features in order to compile and run the tests. + Example: `cargo test --features debug,compare,rand,macros`" ); #[cfg(feature = "abomonation-serialize")] @@ -25,6 +25,8 @@ mod linalg; #[cfg(feature = "proptest-support")] mod proptest; +mod macros; + //#[cfg(all(feature = "debug", feature = "compare", feature = "rand"))] //#[cfg(feature = "sparse")] //mod sparse; From 041b8c4b2c6eb1caada5d673adb4a8cd505920e6 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Fri, 30 Apr 2021 17:07:21 +0200 Subject: [PATCH 35/57] Add macro sanity tests to macros --- tests/core/macros.rs | 11 +++++++++++ tests/core/mod.rs | 3 +++ tests/lib.rs | 2 -- 3 files changed, 14 insertions(+), 2 deletions(-) create mode 100644 tests/core/macros.rs diff --git a/tests/core/macros.rs b/tests/core/macros.rs new file mode 100644 index 00000000..cdc4de03 --- /dev/null +++ b/tests/core/macros.rs @@ -0,0 +1,11 @@ +use nalgebra::{dmatrix, dvector, matrix, vector}; + +#[test] +fn sanity_test() { + // The macros are already tested in `nalgebra-macros`. Here we just test that they compile fine. + + let _ = matrix![1, 2, 3; 4, 5, 6]; + let _ = dmatrix![1, 2, 3; 4, 5, 6]; + let _ = vector![1, 2, 3, 4, 5, 6]; + let _ = dvector![1, 2, 3, 4, 5, 6]; +} \ No newline at end of file diff --git a/tests/core/mod.rs b/tests/core/mod.rs index 4f9bc745..aa005264 100644 --- a/tests/core/mod.rs +++ b/tests/core/mod.rs @@ -16,3 +16,6 @@ mod matrixcompare; #[cfg(feature = "arbitrary")] pub mod helper; + +#[cfg(feature = "macros")] +mod macros; \ No newline at end of file diff --git a/tests/lib.rs b/tests/lib.rs index b1da01c3..d08f4807 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -25,8 +25,6 @@ mod linalg; #[cfg(feature = "proptest-support")] mod proptest; -mod macros; - //#[cfg(all(feature = "debug", feature = "compare", feature = "rand"))] //#[cfg(feature = "sparse")] //mod sparse; From 08a77dd05e02cb497d33cc96a182ad00fef30a96 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Fri, 30 Apr 2021 17:16:18 +0200 Subject: [PATCH 36/57] Test nalgebra-macros on CI --- .github/workflows/nalgebra-ci-build.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/nalgebra-ci-build.yml b/.github/workflows/nalgebra-ci-build.yml index d302c908..fd3ec273 100644 --- a/.github/workflows/nalgebra-ci-build.yml +++ b/.github/workflows/nalgebra-ci-build.yml @@ -69,6 +69,12 @@ jobs: - name: test nalgebra-sparse (slow tests) # Unfortunately, the "slow-tests" take so much time that we need to run them with --release run: PROPTEST_CASES=10000 cargo test --release --manifest-path=nalgebra-sparse/Cargo.toml --features compare,proptest-support,slow-tests slow + test-nalgebra-macros: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - name: test nalgebra-macros + run: cargo test -p nalgebra-macros build-wasm: runs-on: ubuntu-latest # env: From 8552fc8385f1b4da955b8d5f7b9a1777d0c596bb Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Mon, 3 May 2021 13:50:48 +0200 Subject: [PATCH 37/57] Cargo fmt --- nalgebra-macros/src/lib.rs | 38 +++++++++++++++++----------------- nalgebra-macros/tests/tests.rs | 16 ++++++++++++-- src/base/vec_storage.rs | 8 +++---- tests/core/macros.rs | 2 +- tests/core/mod.rs | 2 +- tests/lib.rs | 7 ++++++- 6 files changed, 44 insertions(+), 29 deletions(-) diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs index c00a538f..5b1dd677 100644 --- a/nalgebra-macros/src/lib.rs +++ b/nalgebra-macros/src/lib.rs @@ -5,14 +5,14 @@ extern crate proc_macro; -use syn::{Expr}; -use syn::parse::{Parse, ParseStream, Result, Error}; -use syn::punctuated::{Punctuated}; -use syn::{parse_macro_input, Token}; -use quote::{quote, TokenStreamExt, ToTokens}; use proc_macro::TokenStream; +use quote::{quote, ToTokens, TokenStreamExt}; +use syn::parse::{Error, Parse, ParseStream, Result}; +use syn::punctuated::Punctuated; +use syn::Expr; +use syn::{parse_macro_input, Token}; -use proc_macro2::{TokenStream as TokenStream2, Delimiter, TokenTree, Spacing}; +use proc_macro2::{Delimiter, Spacing, TokenStream as TokenStream2, TokenTree}; use proc_macro2::{Group, Punct}; struct Matrix { @@ -33,10 +33,9 @@ impl Matrix { /// Produces a stream of tokens representing this matrix as a column-major nested array. fn to_col_major_nested_array_tokens(&self) -> TokenStream2 { let mut result = TokenStream2::new(); - for j in 0 .. self.ncols() { + for j in 0..self.ncols() { let mut col = TokenStream2::new(); - let col_iter = (0 .. self.nrows()) - .map(move |i| &self.rows[i][j]); + let col_iter = (0..self.nrows()).map(move |i| &self.rows[i][j]); col.append_separated(col_iter, Punct::new(',', Spacing::Alone)); result.append(Group::new(Delimiter::Bracket, col)); result.append(Punct::new(',', Spacing::Alone)); @@ -48,8 +47,8 @@ impl Matrix { /// (suitable for representing e.g. a `DMatrix`). fn to_col_major_flat_array_tokens(&self) -> TokenStream2 { let mut data = TokenStream2::new(); - for j in 0 .. self.ncols() { - for i in 0 .. self.nrows() { + for j in 0..self.ncols() { + for i in 0..self.nrows() { self.rows[i][j].to_tokens(&mut data); data.append(Punct::new(',', Spacing::Alone)); } @@ -76,7 +75,8 @@ impl Parse for Matrix { "Unexpected number of entries in row {}. Expected {}, found {} entries.", row_idx, ncols, - row.len()); + row.len() + ); return Err(Error::new(row_span, error_msg)); } } else { @@ -93,7 +93,7 @@ impl Parse for Matrix { Ok(Self { rows, - ncols: ncols.unwrap_or(0) + ncols: ncols.unwrap_or(0), }) } } @@ -209,13 +209,13 @@ impl Parse for Vector { // The syntax of a vector is just the syntax of a single matrix row if input.is_empty() { Ok(Self { - elements: Vec::new() + elements: Vec::new(), }) } else { - let elements = MatrixRowSyntax::parse_separated_nonempty(input)?.into_iter().collect(); - Ok(Self { - elements - }) + let elements = MatrixRowSyntax::parse_separated_nonempty(input)? + .into_iter() + .collect(); + Ok(Self { elements }) } } } @@ -279,4 +279,4 @@ pub fn dvector(stream: TokenStream) -> TokenStream { vec!#array_tokens)) }; proc_macro::TokenStream::from(output) -} \ No newline at end of file +} diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index c9d64d91..88fbb9ae 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -1,5 +1,9 @@ +use nalgebra::{ + DMatrix, DVector, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2, Matrix2x1, Matrix2x3, Matrix2x4, + Matrix3, Matrix3x1, Matrix3x2, Matrix3x4, Matrix4, Matrix4x1, Matrix4x2, Matrix4x3, SMatrix, + SVector, Vector1, Vector2, Vector3, Vector4, Vector5, Vector6, +}; use nalgebra_macros::{dmatrix, dvector, matrix, vector}; -use nalgebra::{DMatrix, DVector, SMatrix, Matrix3x2, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2x1, Matrix2, Matrix2x3, Matrix2x4, Matrix3x1, Matrix3, Matrix3x4, Matrix4x1, Matrix4x2, Matrix4x3, Matrix4, Vector1, Vector2, Vector3, Vector4, Vector5, SVector, Vector6}; fn check_statically_same_type(_: &T, _: &T) {} @@ -11,6 +15,8 @@ macro_rules! assert_eq_and_type { }; } +// Skip rustfmt because it just makes the test bloated without making it more readable +#[rustfmt::skip] #[test] fn matrix_small_dims_exhaustive() { // 0x0 @@ -52,6 +58,8 @@ fn matrix_const_fn() { const _: SMatrix = matrix![1, 2, 3; 4, 5, 6]; } +// Skip rustfmt because it just makes the test bloated without making it more readable +#[rustfmt::skip] #[test] fn dmatrix_small_dims_exhaustive() { // 0x0 @@ -85,6 +93,8 @@ fn dmatrix_small_dims_exhaustive() { DMatrix::from_row_slice(4, 4, &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16])); } +// Skip rustfmt because it just makes the test bloated without making it more readable +#[rustfmt::skip] #[test] fn vector_small_dims_exhaustive() { assert_eq_and_type!(vector![], SVector::::zeros()); @@ -105,6 +115,8 @@ fn vector_const_fn() { const _: Vector6 = vector![1, 2, 3, 4, 5, 6]; } +// Skip rustfmt because it just makes the test bloated without making it more readable +#[rustfmt::skip] #[test] fn dvector_small_dims_exhaustive() { assert_eq_and_type!(dvector![], DVector::::zeros(0)); @@ -130,4 +142,4 @@ fn dmatrix_trybuild_tests() { // Verify error message when we give a matrix with mismatched dimensions t.compile_fail("tests/trybuild/dmatrix_mismatched_dimensions.rs"); -} \ No newline at end of file +} diff --git a/src/base/vec_storage.rs b/src/base/vec_storage.rs index 15ea9237..f8d28769 100644 --- a/src/base/vec_storage.rs +++ b/src/base/vec_storage.rs @@ -13,9 +13,9 @@ use crate::base::storage::{ }; use crate::base::{Scalar, Vector}; +use crate::{DMatrix, DVector}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -use crate::{DMatrix, DVector}; /* * @@ -412,8 +412,7 @@ impl Extend for VecStorage { } } -impl DMatrix -{ +impl DMatrix { /// Creates a new heap-allocated matrix from the given [VecStorage]. pub const fn from_vec_storage(storage: VecStorage) -> Self { // This is sound because the dimensions of the matrix and the storage are guaranteed @@ -422,8 +421,7 @@ impl DMatrix } } -impl DVector -{ +impl DVector { /// Creates a new heap-allocated matrix from the given [VecStorage]. pub const fn from_vec_storage(storage: VecStorage) -> Self { // This is sound because the dimensions of the matrix and the storage are guaranteed diff --git a/tests/core/macros.rs b/tests/core/macros.rs index cdc4de03..eaa134ff 100644 --- a/tests/core/macros.rs +++ b/tests/core/macros.rs @@ -8,4 +8,4 @@ fn sanity_test() { let _ = dmatrix![1, 2, 3; 4, 5, 6]; let _ = vector![1, 2, 3, 4, 5, 6]; let _ = dvector![1, 2, 3, 4, 5, 6]; -} \ No newline at end of file +} diff --git a/tests/core/mod.rs b/tests/core/mod.rs index aa005264..c03461dc 100644 --- a/tests/core/mod.rs +++ b/tests/core/mod.rs @@ -18,4 +18,4 @@ mod matrixcompare; pub mod helper; #[cfg(feature = "macros")] -mod macros; \ No newline at end of file +mod macros; diff --git a/tests/lib.rs b/tests/lib.rs index d08f4807..20d38d7a 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1,4 +1,9 @@ -#[cfg(not(all(feature = "debug", feature = "compare", feature = "rand", feature = "macros")))] +#[cfg(not(all( + feature = "debug", + feature = "compare", + feature = "rand", + feature = "macros" +)))] compile_error!( "Please enable the `debug`, `compare`, `rand` and `macros` features in order to compile and run the tests. Example: `cargo test --features debug,compare,rand,macros`" From 5d638a32b8070c12244e3ad1794a670779fda545 Mon Sep 17 00:00:00 2001 From: Chammika Mannakkara Date: Tue, 4 May 2021 12:29:25 +0900 Subject: [PATCH 38/57] correct all gramatical mistakes pointed by @Andlon --- nalgebra-sparse/src/coo.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nalgebra-sparse/src/coo.rs b/nalgebra-sparse/src/coo.rs index b300327d..364083a9 100644 --- a/nalgebra-sparse/src/coo.rs +++ b/nalgebra-sparse/src/coo.rs @@ -133,18 +133,18 @@ impl CooMatrix { /// Reserves capacity for COO matrix by at least `additional` elements. /// /// This increase the capacities of triplet holding arrays by reserving more space to avoid - /// frequent reallocations, in `push` operations. + /// frequent reallocations in `push` operations. /// /// ## Panics /// - /// Panics if any of the individual allocation of triplet arrays fail. + /// Panics if any of the individual allocation of triplet arrays fails. /// /// ## Example /// /// ``` /// # use nalgebra_sparse::coo::CooMatrix; /// let mut coo = CooMatrix::new(4, 4); - /// // Reserver capacity in advance + /// // Reserve capacity in advance /// coo.reserve(10); /// coo.push(1, 0, 3.0); /// ``` From f42ecf0ebb8d14a55155a5443058f782a3d70a77 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Wed, 5 May 2021 08:51:16 +0200 Subject: [PATCH 39/57] Improve nalgebra-macros/Cargo.toml metadata --- nalgebra-macros/Cargo.toml | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/nalgebra-macros/Cargo.toml b/nalgebra-macros/Cargo.toml index 5ebef960..d95784e0 100644 --- a/nalgebra-macros/Cargo.toml +++ b/nalgebra-macros/Cargo.toml @@ -1,16 +1,21 @@ [package] name = "nalgebra-macros" version = "0.1.0" -authors = ["Andreas Longva "] +authors = [ "Andreas Longva", "Sébastien Crozet " ] edition = "2018" +description = "Procedural macros for nalgebra" +documentation = "https://www.nalgebra.org/docs" +homepage = "https://nalgebra.org" +repository = "https://github.com/dimforge/nalgebra" +readme = "../README.md" +categories = [ "science", "mathematics" ] +keywords = [ "linear", "algebra", "matrix", "vector", "math" ] +license = "Apache-2.0" [lib] proc-macro = true -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] -# TODO: Determine minimal features that we need syn = { version="1.0", features = ["full"] } quote = "1.0" proc-macro2 = "1.0" From 57541aa2533e2331505ad474b6d16ab07a7d543d Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Wed, 5 May 2021 09:42:31 +0200 Subject: [PATCH 40/57] Add tests to ensure macros compile for all built-in types --- nalgebra-macros/tests/tests.rs | 68 ++++++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index 88fbb9ae..206e5e66 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -143,3 +143,71 @@ fn dmatrix_trybuild_tests() { // Verify error message when we give a matrix with mismatched dimensions t.compile_fail("tests/trybuild/dmatrix_mismatched_dimensions.rs"); } + +#[test] +fn matrix_builtin_types() { + // Check that matrix! compiles for all built-in types + const _: SMatrix = matrix![0, 1; 2, 3]; + const _: SMatrix = matrix![0, 1; 2, 3]; + const _: SMatrix = matrix![0, 1; 2, 3]; + const _: SMatrix = matrix![0, 1; 2, 3]; + const _: SMatrix = matrix![0, 1; 2, 3]; + const _: SMatrix = matrix![0, 1; 2, 3]; + const _: SMatrix = matrix![0, 1; 2, 3]; + const _: SMatrix = matrix![0, 1; 2, 3]; + const _: SMatrix = matrix![0, 1; 2, 3]; + const _: SMatrix = matrix![0, 1; 2, 3]; + const _: SMatrix = matrix![0.0, 1.0; 2.0, 3.0]; + const _: SMatrix = matrix![0.0, 1.0; 2.0, 3.0]; +} + +#[test] +fn vector_builtin_types() { + // Check that vector! compiles for all built-in types + const _: SVector = vector![0, 1, 2, 3]; + const _: SVector = vector![0, 1, 2, 3]; + const _: SVector = vector![0, 1, 2, 3]; + const _: SVector = vector![0, 1, 2, 3]; + const _: SVector = vector![0, 1, 2, 3]; + const _: SVector = vector![0, 1, 2, 3]; + const _: SVector = vector![0, 1, 2, 3]; + const _: SVector = vector![0, 1, 2, 3]; + const _: SVector = vector![0, 1, 2, 3]; + const _: SVector = vector![0, 1, 2, 3]; + const _: SVector = vector![0.0, 1.0, 2.0, 3.0]; + const _: SVector = vector![0.0, 1.0, 2.0, 3.0]; +} + +#[test] +fn dmatrix_builtin_types() { + // Check that dmatrix! compiles for all built-in types + let _: DMatrix = dmatrix![0, 1; 2, 3]; + let _: DMatrix = dmatrix![0, 1; 2, 3]; + let _: DMatrix = dmatrix![0, 1; 2, 3]; + let _: DMatrix = dmatrix![0, 1; 2, 3]; + let _: DMatrix = dmatrix![0, 1; 2, 3]; + let _: DMatrix = dmatrix![0, 1; 2, 3]; + let _: DMatrix = dmatrix![0, 1; 2, 3]; + let _: DMatrix = dmatrix![0, 1; 2, 3]; + let _: DMatrix = dmatrix![0, 1; 2, 3]; + let _: DMatrix = dmatrix![0, 1; 2, 3]; + let _: DMatrix = dmatrix![0.0, 1.0; 2.0, 3.0]; + let _: DMatrix = dmatrix![0.0, 1.0; 2.0, 3.0]; +} + +#[test] +fn dvector_builtin_types() { + // Check that dvector! compiles for all built-in types + let _: DVector = dvector![0, 1, 2, 3]; + let _: DVector = dvector![0, 1, 2, 3]; + let _: DVector = dvector![0, 1, 2, 3]; + let _: DVector = dvector![0, 1, 2, 3]; + let _: DVector = dvector![0, 1, 2, 3]; + let _: DVector = dvector![0, 1, 2, 3]; + let _: DVector = dvector![0, 1, 2, 3]; + let _: DVector = dvector![0, 1, 2, 3]; + let _: DVector = dvector![0, 1, 2, 3]; + let _: DVector = dvector![0, 1, 2, 3]; + let _: DVector = dvector![0.0, 1.0, 2.0, 3.0]; + let _: DVector = dvector![0.0, 1.0, 2.0, 3.0]; +} \ No newline at end of file From 6026a0543349ee39c48847b165045df39116cc90 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Wed, 5 May 2021 10:03:18 +0200 Subject: [PATCH 41/57] Test that matrix macros work with arbitrary expressions --- nalgebra-macros/tests/tests.rs | 45 ++++++++++++++++++++++++++++++++++ 1 file changed, 45 insertions(+) diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index 206e5e66..22daaf8d 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -210,4 +210,49 @@ fn dvector_builtin_types() { let _: DVector = dvector![0, 1, 2, 3]; let _: DVector = dvector![0.0, 1.0, 2.0, 3.0]; let _: DVector = dvector![0.0, 1.0, 2.0, 3.0]; +} + +/// Black box function that's just used for testing macros with function call expressions. +fn f(x: T) -> T { + x +} + +#[rustfmt::skip] +#[test] +fn matrix_arbitrary_expressions() { + // Test that matrix! supports arbitrary expressions for its elements + let a = matrix![1 + 2 , 2 * 3; + 4 * f(5 + 6), 7 - 8 * 9]; + let a_expected = Matrix2::new(1 + 2 , 2 * 3, + 4 * f(5 + 6), 7 - 8 * 9); + assert_eq_and_type!(a, a_expected); +} + +#[rustfmt::skip] +#[test] +fn dmatrix_arbitrary_expressions() { + // Test that dmatrix! supports arbitrary expressions for its elements + let a = dmatrix![1 + 2 , 2 * 3; + 4 * f(5 + 6), 7 - 8 * 9]; + let a_expected = DMatrix::from_row_slice(2, 2, &[1 + 2 , 2 * 3, + 4 * f(5 + 6), 7 - 8 * 9]); + assert_eq_and_type!(a, a_expected); +} + +#[rustfmt::skip] +#[test] +fn vector_arbitrary_expressions() { + // Test that vector! supports arbitrary expressions for its elements + let a = vector![1 + 2, 2 * 3, 4 * f(5 + 6), 7 - 8 * 9]; + let a_expected = Vector4::new(1 + 2, 2 * 3, 4 * f(5 + 6), 7 - 8 * 9); + assert_eq_and_type!(a, a_expected); +} + +#[rustfmt::skip] +#[test] +fn dvector_arbitrary_expressions() { + // Test that dvector! supports arbitrary expressions for its elements + let a = dvector![1 + 2, 2 * 3, 4 * f(5 + 6), 7 - 8 * 9]; + let a_expected = DVector::from_column_slice(&[1 + 2, 2 * 3, 4 * f(5 + 6), 7 - 8 * 9]); + assert_eq_and_type!(a, a_expected); } \ No newline at end of file From 39b275fc924b49d0f3d6507753532aae7ea48ca9 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Wed, 5 May 2021 10:04:47 +0200 Subject: [PATCH 42/57] Formatting --- nalgebra-macros/tests/tests.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index 22daaf8d..339dd048 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -255,4 +255,4 @@ fn dvector_arbitrary_expressions() { let a = dvector![1 + 2, 2 * 3, 4 * f(5 + 6), 7 - 8 * 9]; let a_expected = DVector::from_column_slice(&[1 + 2, 2 * 3, 4 * f(5 + 6), 7 - 8 * 9]); assert_eq_and_type!(a, a_expected); -} \ No newline at end of file +} From 5bff5368bf38ddfa31416e4ae9897b163031a513 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Thu, 6 May 2021 18:15:49 +0200 Subject: [PATCH 43/57] Manually implement Serialize and Deserialize for VecStorage --- src/base/vec_storage.rs | 49 ++++++++++++++++++++++++++++++++++++++++- tests/core/serde.rs | 30 +++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/src/base/vec_storage.rs b/src/base/vec_storage.rs index 29da127d..8b2d2ef2 100644 --- a/src/base/vec_storage.rs +++ b/src/base/vec_storage.rs @@ -13,6 +13,12 @@ use crate::base::storage::{ }; use crate::base::{Scalar, Vector}; +#[cfg(feature = "serde-serialize-no-std")] +use serde::{ + de::{Deserialize, Deserializer, Error}, + ser::{Serialize, Serializer}, +}; + #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; @@ -24,13 +30,54 @@ use abomonation::Abomonation; /// A Vec-based matrix data storage. It may be dynamically-sized. #[repr(C)] #[derive(Eq, Debug, Clone, PartialEq)] -#[cfg_attr(feature = "serde-serialize", derive(Serialize, Deserialize))] pub struct VecStorage { data: Vec, nrows: R, ncols: C, } +#[cfg(feature = "serde-serialize")] +impl Serialize for VecStorage +where + T: Serialize, + R: Serialize, + C: Serialize, +{ + fn serialize(&self, serializer: Ser) -> Result + where + Ser: Serializer, + { + (&self.data, &self.nrows, &self.ncols).serialize(serializer) + } +} + +#[cfg(feature = "serde-serialize")] +impl<'a, T, R: Dim, C: Dim> Deserialize<'a> for VecStorage +where + T: Deserialize<'a>, + R: Deserialize<'a>, + C: Deserialize<'a>, +{ + fn deserialize(deserializer: Des) -> Result + where + Des: Deserializer<'a>, + { + let (data, nrows, ncols): (Vec, R, C) = Deserialize::deserialize(deserializer)?; + + // SAFETY: make sure the data we deserialize have the + // correct number of elements. + if nrows.value() * ncols.value() != data.len() { + return Err(Des::Error::custom(format!( + "Expected {} components, found {}", + nrows.value() * ncols.value(), + data.len() + ))); + } + + Ok(Self { data, nrows, ncols }) + } +} + #[deprecated(note = "renamed to `VecStorage`")] /// Renamed to [VecStorage]. pub type MatrixVec = VecStorage; diff --git a/tests/core/serde.rs b/tests/core/serde.rs index 0a3be7e9..34429eeb 100644 --- a/tests/core/serde.rs +++ b/tests/core/serde.rs @@ -1,8 +1,8 @@ #![cfg(feature = "serde-serialize")] use na::{ - DMatrix, Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, Matrix3x4, Point2, Point3, - Quaternion, Rotation2, Rotation3, Similarity2, Similarity3, SimilarityMatrix2, + DMatrix, Isometry2, Isometry3, IsometryMatrix2, IsometryMatrix3, Matrix2x3, Matrix3x4, Point2, + Point3, Quaternion, Rotation2, Rotation3, Similarity2, Similarity3, SimilarityMatrix2, SimilarityMatrix3, Translation2, Translation3, Unit, Vector2, }; use rand; @@ -27,6 +27,32 @@ fn serde_dmatrix() { let serialized = serde_json::to_string(&v).unwrap(); let deserialized: DMatrix = serde_json::from_str(&serialized).unwrap(); assert_eq!(v, deserialized); + + let m = DMatrix::from_column_slice(2, 3, &[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]); + let mat_str = "[[1.0, 2.0, 3.0, 4.0, 5.0, 6.0],2,3]"; + let deserialized: DMatrix = serde_json::from_str(&mat_str).unwrap(); + assert_eq!(m, deserialized); + + let m = Matrix2x3::from_column_slice(&[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]); + let mat_str = "[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]"; + let deserialized: Matrix2x3 = serde_json::from_str(&mat_str).unwrap(); + assert_eq!(m, deserialized); +} + +#[test] +#[should_panic] +fn serde_dmatrix_invalid_len() { + // This must fail: we attempt to deserialize a 2x3 with only 5 elements. + let mat_str = "[[1.0, 2.0, 3.0, 4.0, 5.0],2,3]"; + let _: DMatrix = serde_json::from_str(&mat_str).unwrap(); +} + +#[test] +#[should_panic] +fn serde_smatrix_invalid_len() { + // This must fail: we attempt to deserialize a 2x3 with only 5 elements. + let mat_str = "[1.0, 2.0, 3.0, 4.0, 5.0]"; + let _: Matrix2x3 = serde_json::from_str(&mat_str).unwrap(); } test_serde!( From b398a5e1894300d4e3efdd4ccf0e528700513093 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Thu, 6 May 2021 18:22:04 +0200 Subject: [PATCH 44/57] Re-add conversion between arrays and row vectors. --- src/base/conversion.rs | 24 ++++++++++++++++++++++-- tests/core/conversion.rs | 11 ++--------- 2 files changed, 24 insertions(+), 11 deletions(-) diff --git a/src/base/conversion.rs b/src/base/conversion.rs index b329dba1..532ab8ed 100644 --- a/src/base/conversion.rs +++ b/src/base/conversion.rs @@ -23,9 +23,9 @@ use crate::base::{ use crate::base::{DVector, VecStorage}; use crate::base::{SliceStorage, SliceStorageMut}; use crate::constraint::DimEq; -use crate::{SMatrix, SVector}; +use crate::{IsNotStaticOne, RowSVector, SMatrix, SVector}; -// TODO: too bad this won't work allo slice conversions. +// TODO: too bad this won't work for slice conversions. impl SubsetOf> for OMatrix where R1: Dim, @@ -118,6 +118,26 @@ impl Into<[T; D]> for SVector { } } +impl From<[T; D]> for RowSVector +where + Const: IsNotStaticOne, +{ + #[inline] + fn from(arr: [T; D]) -> Self { + SVector::::from(arr).transpose() + } +} + +impl Into<[T; D]> for RowSVector +where + Const: IsNotStaticOne, +{ + #[inline] + fn into(self) -> [T; D] { + self.transpose().into() + } +} + macro_rules! impl_from_into_asref_1D( ($(($NRows: ident, $NCols: ident) => $SZ: expr);* $(;)*) => {$( impl AsRef<[T; $SZ]> for Matrix diff --git a/tests/core/conversion.rs b/tests/core/conversion.rs index 58ac179a..5374c399 100644 --- a/tests/core/conversion.rs +++ b/tests/core/conversion.rs @@ -1,5 +1,4 @@ -#![cfg(all(feature = "proptest-support", feature = "alga"))] -use alga::linear::Transformation; +#![cfg(all(feature = "proptest-support"))] use na::{ self, Affine3, Isometry3, Matrix2, Matrix2x3, Matrix2x4, Matrix2x5, Matrix2x6, Matrix3, Matrix3x2, Matrix3x4, Matrix3x5, Matrix3x6, Matrix4, Matrix4x2, Matrix4x3, Matrix4x5, @@ -16,7 +15,7 @@ use proptest::{prop_assert, prop_assert_eq, proptest}; proptest! { #[test] - fn translation_conversion(t in translation3(), v in vector3(), p in point3()) { + fn translation_conversion(t in translation3(), p in point3()) { let iso: Isometry3 = na::convert(t); let sim: Similarity3 = na::convert(t); let aff: Affine3 = na::convert(t); @@ -29,12 +28,6 @@ proptest! { prop_assert_eq!(t, na::try_convert(prj).unwrap()); prop_assert_eq!(t, na::try_convert(tr).unwrap() ); - prop_assert_eq!(t.transform_vector(&v), iso * v); - prop_assert_eq!(t.transform_vector(&v), sim * v); - prop_assert_eq!(t.transform_vector(&v), aff * v); - prop_assert_eq!(t.transform_vector(&v), prj * v); - prop_assert_eq!(t.transform_vector(&v), tr * v); - prop_assert_eq!(t * p, iso * p); prop_assert_eq!(t * p, sim * p); prop_assert_eq!(t * p, aff * p); From 3a3bc55f667b7a928eea0608e650ac4c6c3f4ffc Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Fri, 7 May 2021 09:00:29 +0200 Subject: [PATCH 45/57] Move from_{}_storage impl blocks to matrix.rs --- src/base/array_storage.rs | 12 ----------- src/base/matrix.rs | 43 ++++++++++++++++++++++++++++++++++++++- src/base/vec_storage.rs | 19 ----------------- 3 files changed, 42 insertions(+), 32 deletions(-) diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index dc6b22ce..68da4c51 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -25,7 +25,6 @@ use crate::base::storage::{ ContiguousStorage, ContiguousStorageMut, Owned, ReshapableStorage, Storage, StorageMut, }; use crate::base::Scalar; -use crate::SMatrix; /* * @@ -300,14 +299,3 @@ where self.as_slice().iter().fold(0, |acc, e| acc + e.extent()) } } - -// TODO: Where to put this impl block? -impl SMatrix { - /// Creates a new statically-allocated matrix from the given [ArrayStorage]. - #[inline(always)] - pub const fn from_array_storage(storage: ArrayStorage) -> Self { - // This is sound because the row and column types are exactly the same as that of the - // storage, so there can be no mismatch - unsafe { Self::from_data_statically_unchecked(storage) } - } -} diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 3b4bc50c..f9b391ef 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -29,7 +29,7 @@ use crate::base::storage::{ ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut, }; use crate::base::{Const, DefaultAllocator, OMatrix, OVector, Scalar, Unit}; -use crate::SimdComplexField; +use crate::{ArrayStorage, DMatrix, DVector, Dynamic, SMatrix, SimdComplexField, VecStorage}; /// A square matrix. pub type SquareMatrix = Matrix; @@ -317,6 +317,47 @@ impl Matrix { } } +impl SMatrix { + /// Creates a new statically-allocated matrix from the given [ArrayStorage]. + /// + /// This method exists primarily as a workaround for the fact that `from_data` can not + /// work in `const fn` contexts. + #[inline(always)] + pub const fn from_array_storage(storage: ArrayStorage) -> Self { + // This is sound because the row and column types are exactly the same as that of the + // storage, so there can be no mismatch + unsafe { Self::from_data_statically_unchecked(storage) } + } +} + +// TODO: Consider removing/deprecating `from_vec_storage` once we are able to make +// `from_data` const fn compatible +impl DMatrix { + /// Creates a new heap-allocated matrix from the given [VecStorage]. + /// + /// This method exists primarily as a workaround for the fact that `from_data` can not + /// work in `const fn` contexts. + pub const fn from_vec_storage(storage: VecStorage) -> Self { + // This is sound because the dimensions of the matrix and the storage are guaranteed + // to be the same + unsafe { Self::from_data_statically_unchecked(storage) } + } +} + +// TODO: Consider removing/deprecating `from_vec_storage` once we are able to make +// `from_data` const fn compatible +impl DVector { + /// Creates a new heap-allocated matrix from the given [VecStorage]. + /// + /// This method exists primarily as a workaround for the fact that `from_data` can not + /// work in `const fn` contexts. + pub const fn from_vec_storage(storage: VecStorage) -> Self { + // This is sound because the dimensions of the matrix and the storage are guaranteed + // to be the same + unsafe { Self::from_data_statically_unchecked(storage) } + } +} + impl> Matrix { /// Creates a new matrix with the given data. #[inline(always)] diff --git a/src/base/vec_storage.rs b/src/base/vec_storage.rs index f8d28769..29da127d 100644 --- a/src/base/vec_storage.rs +++ b/src/base/vec_storage.rs @@ -13,7 +13,6 @@ use crate::base::storage::{ }; use crate::base::{Scalar, Vector}; -use crate::{DMatrix, DVector}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; @@ -411,21 +410,3 @@ impl Extend for VecStorage { self.nrows = Dynamic::new(self.data.len()); } } - -impl DMatrix { - /// Creates a new heap-allocated matrix from the given [VecStorage]. - pub const fn from_vec_storage(storage: VecStorage) -> Self { - // This is sound because the dimensions of the matrix and the storage are guaranteed - // to be the same - unsafe { Self::from_data_statically_unchecked(storage) } - } -} - -impl DVector { - /// Creates a new heap-allocated matrix from the given [VecStorage]. - pub const fn from_vec_storage(storage: VecStorage) -> Self { - // This is sound because the dimensions of the matrix and the storage are guaranteed - // to be the same - unsafe { Self::from_data_statically_unchecked(storage) } - } -} From 922393b04f64d34bb4ff1ad4e5d3171697a706d2 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Fri, 7 May 2021 09:09:10 +0200 Subject: [PATCH 46/57] Enable from_{}_storage only when std/alloc available --- src/base/matrix.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/base/matrix.rs b/src/base/matrix.rs index f9b391ef..3cde8a4f 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -29,7 +29,10 @@ use crate::base::storage::{ ContiguousStorage, ContiguousStorageMut, Owned, SameShapeStorage, Storage, StorageMut, }; use crate::base::{Const, DefaultAllocator, OMatrix, OVector, Scalar, Unit}; -use crate::{ArrayStorage, DMatrix, DVector, Dynamic, SMatrix, SimdComplexField, VecStorage}; +use crate::{ArrayStorage, SMatrix, SimdComplexField}; + +#[cfg(any(feature = "std", feature = "alloc"))] +use crate::{DMatrix, DVector, Dynamic, VecStorage}; /// A square matrix. pub type SquareMatrix = Matrix; @@ -332,6 +335,7 @@ impl SMatrix { // TODO: Consider removing/deprecating `from_vec_storage` once we are able to make // `from_data` const fn compatible +#[cfg(any(feature = "std", feature = "alloc"))] impl DMatrix { /// Creates a new heap-allocated matrix from the given [VecStorage]. /// @@ -346,6 +350,7 @@ impl DMatrix { // TODO: Consider removing/deprecating `from_vec_storage` once we are able to make // `from_data` const fn compatible +#[cfg(any(feature = "std", feature = "alloc"))] impl DVector { /// Creates a new heap-allocated matrix from the given [VecStorage]. /// From b85335bd9c95b8ede23364d6c31a7197c8ddd0d2 Mon Sep 17 00:00:00 2001 From: Andreas Longva Date: Fri, 7 May 2021 09:23:44 +0200 Subject: [PATCH 47/57] Update matrixcompare version to 0.3.0 Fixes some warnings produced by earlier versions since Rust 1.51. See https://github.com/Andlon/matrixcompare/pull/5 for more details. Note that we only update dev-dependencies, so there is no API breakage. --- Cargo.toml | 2 +- nalgebra-sparse/Cargo.toml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 45fdb17a..5c0b4e4a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -88,7 +88,7 @@ rand_isaac = "0.3" criterion = "0.2.10" # For matrix comparison macro -matrixcompare = "0.2.0" +matrixcompare = "0.3.0" itertools = "0.10" [workspace] diff --git a/nalgebra-sparse/Cargo.toml b/nalgebra-sparse/Cargo.toml index 36dc8f30..6666bfb9 100644 --- a/nalgebra-sparse/Cargo.toml +++ b/nalgebra-sparse/Cargo.toml @@ -27,7 +27,7 @@ matrixcompare-core = { version = "0.1.0", optional = true } [dev-dependencies] itertools = "0.10" -matrixcompare = { version = "0.2.0", features = [ "proptest-support" ] } +matrixcompare = { version = "0.3.0", features = [ "proptest-support" ] } nalgebra = { version="0.26", path = "../", features = ["compare"] } [package.metadata.docs.rs] From b48b104d5784604ebf437ded1bc78791693cc78b Mon Sep 17 00:00:00 2001 From: David Koloski Date: Wed, 5 May 2021 11:14:18 -0400 Subject: [PATCH 48/57] Add rkyv implementations for a few types --- Cargo.toml | 5 ++++- src/base/array_storage.rs | 4 ++++ src/base/dimension.rs | 4 ++++ src/base/matrix.rs | 4 ++++ src/base/unit.rs | 4 ++++ src/geometry/isometry.rs | 4 ++++ src/geometry/quaternion.rs | 4 ++++ src/geometry/translation.rs | 4 ++++ 8 files changed, 32 insertions(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index bfd3f166..1a356c3d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,8 @@ convert-bytemuck = [ "bytemuck" ] serde-serialize-no-std = [ "serde", "num-complex/serde" ] serde-serialize = [ "serde-serialize-no-std", "serde/std" ] abomonation-serialize = [ "abomonation" ] +rkyv-serialize-no-std = [ "rkyv" ] +rkyv-serialize = [ "rkyv-serialize-no-std", "rkyv/std" ] # Randomness ## To use rand in a #[no-std] environment, enable the @@ -74,6 +76,7 @@ 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 } abomonation = { version = "0.7", optional = true } +rkyv = { version = "~0.6.3", default-features = false, features = ["const_generics"], optional = true } mint = { version = "0.5", optional = true } glam = { version = "0.13", optional = true } quickcheck = { version = "1", optional = true } @@ -81,7 +84,7 @@ pest = { version = "2", optional = true } pest_derive = { version = "2", optional = true } bytemuck = { version = "1.5", optional = true } matrixcompare-core = { version = "0.1", optional = true } -proptest = { version = "1", optional = true, default-features = false, features = ["std"] } +proptest = { version = "1", optional = true, default-features = false, features = ["std"] } [dev-dependencies] serde_json = "1.0" diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index 68da4c51..e575229c 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -18,6 +18,9 @@ use std::mem; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; +#[cfg(feature = "rkyv-serialize-no-std")] +use rkyv::{Archive, Deserialize, Serialize}; + use crate::base::allocator::Allocator; use crate::base::default_allocator::DefaultAllocator; use crate::base::dimension::{Const, ToTypenum}; @@ -34,6 +37,7 @@ use crate::base::Scalar; /// A array-based statically sized matrix data storage. #[repr(C)] #[derive(Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Deserialize, Serialize))] pub struct ArrayStorage(pub [[T; R]; C]); // TODO: remove this once the stdlib implements Default for arrays. diff --git a/src/base/dimension.rs b/src/base/dimension.rs index dd87647d..2c51b2f4 100644 --- a/src/base/dimension.rs +++ b/src/base/dimension.rs @@ -11,6 +11,9 @@ use typenum::{self, Diff, Max, Maximum, Min, Minimum, Prod, Quot, Sum, Unsigned} #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "rkyv-serialize-no-std")] +use rkyv::{Archive, Deserialize, Serialize}; + /// Dim of dynamically-sized algebraic entities. #[derive(Clone, Copy, Eq, PartialEq, Debug)] pub struct Dynamic { @@ -197,6 +200,7 @@ dim_ops!( ); #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] +#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Deserialize, Serialize))] pub struct Const; /// Trait implemented exclusively by type-level integers. diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 3cde8a4f..c7e02e22 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -16,6 +16,9 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; +#[cfg(feature = "rkyv-serialize-no-std")] +use rkyv::{Archive, Deserialize, Serialize}; + use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub, Field, SupersetOf}; use simba::simd::SimdPartialOrd; @@ -153,6 +156,7 @@ pub type MatrixCross = /// some concrete types for `T` and a compatible data storage type `S`). #[repr(C)] #[derive(Clone, Copy)] +#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Deserialize, Serialize))] pub struct Matrix { /// The data storage that contains all the matrix components. Disappointed? /// diff --git a/src/base/unit.rs b/src/base/unit.rs index c2e60da3..4b1d1948 100644 --- a/src/base/unit.rs +++ b/src/base/unit.rs @@ -6,6 +6,9 @@ use std::ops::Deref; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "rkyv-serialize-no-std")] +use rkyv::{Archive, Deserialize, Serialize}; + #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; @@ -26,6 +29,7 @@ use crate::{Dim, Matrix, OMatrix, RealField, Scalar, SimdComplexField, SimdRealF /// in their documentation, read their dedicated pages directly. #[repr(transparent)] #[derive(Clone, Hash, Debug, Copy)] +#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Deserialize, Serialize))] pub struct Unit { pub(crate) value: T, } diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index c5fd844c..7c8686c0 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -7,6 +7,9 @@ use std::io::{Result as IOResult, Write}; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Serialize}; +#[cfg(feature = "rkyv-serialize-no-std")] +use rkyv::{Archive, Deserialize, Serialize}; + #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; @@ -68,6 +71,7 @@ use crate::geometry::{AbstractRotation, Point, Translation}; DefaultAllocator: Allocator>, Owned>: Deserialize<'de>")) )] +#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Serialize, Deserialize))] pub struct Isometry { /// The pure rotational part of this isometry. pub rotation: R, diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 365095b8..9a920a8a 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -10,6 +10,9 @@ use crate::base::storage::Owned; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "rkyv-serialize-no-std")] +use rkyv::{Archive, Deserialize, Serialize}; + #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; @@ -28,6 +31,7 @@ use crate::geometry::{Point3, Rotation}; /// that may be used as a rotation. #[repr(C)] #[derive(Debug, Copy, Clone)] +#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Deserialize, Serialize))] pub struct Quaternion { /// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order. pub coords: Vector4, diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs index 1a8f4b04..92747dab 100755 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -8,6 +8,9 @@ use std::io::{Result as IOResult, Write}; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; +#[cfg(feature = "rkyv-serialize-no-std")] +use rkyv::{Archive, Deserialize, Serialize}; + #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; @@ -23,6 +26,7 @@ use crate::geometry::Point; /// A translation. #[repr(C)] #[derive(Debug)] +#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Deserialize, Serialize))] pub struct Translation { /// The translation coordinates, i.e., how much is added to a point's coordinates when it is /// translated. From 38dd3345e03f565eb134a68526af6c7205df9fae Mon Sep 17 00:00:00 2001 From: David Koloski Date: Thu, 6 May 2021 20:59:02 -0400 Subject: [PATCH 49/57] Switch to distributive implementations --- Cargo.toml | 2 +- src/base/array_storage.rs | 32 +++++++++++++++++++++++- src/base/dimension.rs | 24 +++++++++++++++++- src/base/matrix.rs | 35 +++++++++++++++++++++++++- src/base/unit.rs | 34 ++++++++++++++++++++++++- src/geometry/isometry.rs | 50 ++++++++++++++++++++++++++++++++++++- src/geometry/quaternion.rs | 34 ++++++++++++++++++++++++- src/geometry/translation.rs | 34 ++++++++++++++++++++++++- 8 files changed, 237 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1a356c3d..f1d65128 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -76,7 +76,7 @@ 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 } abomonation = { version = "0.7", optional = true } -rkyv = { version = "~0.6.3", default-features = false, features = ["const_generics"], optional = true } +rkyv = { version = "~0.6.4", default-features = false, features = ["const_generics"], optional = true } mint = { version = "0.5", optional = true } glam = { version = "0.13", optional = true } quickcheck = { version = "1", optional = true } diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index e575229c..350240cd 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -37,7 +37,6 @@ use crate::base::Scalar; /// A array-based statically sized matrix data storage. #[repr(C)] #[derive(Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Deserialize, Serialize))] pub struct ArrayStorage(pub [[T; R]; C]); // TODO: remove this once the stdlib implements Default for arrays. @@ -303,3 +302,34 @@ where self.as_slice().iter().fold(0, |acc, e| acc + e.extent()) } } + +#[cfg(feature = "rkyv-serialize-no-std")] +impl Archive for ArrayStorage { + type Archived = ArrayStorage; + type Resolver = <[[T; R]; C] as Archive>::Resolver; + + fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut core::mem::MaybeUninit) { + self.0.resolve( + pos + rkyv::offset_of!(Self::Archived, 0), + resolver, + rkyv::project_struct!(out: Self::Archived => 0) + ); + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl, S: rkyv::Fallible + ?Sized, const R: usize, const C: usize> Serialize for ArrayStorage { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(self.0.serialize(serializer)?) + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl Deserialize, D> for ArrayStorage +where + T::Archived: Deserialize, +{ + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(ArrayStorage(self.0.deserialize(deserializer)?)) + } +} diff --git a/src/base/dimension.rs b/src/base/dimension.rs index 2c51b2f4..3ee762f1 100644 --- a/src/base/dimension.rs +++ b/src/base/dimension.rs @@ -200,7 +200,6 @@ dim_ops!( ); #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] -#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Deserialize, Serialize))] pub struct Const; /// Trait implemented exclusively by type-level integers. @@ -235,6 +234,29 @@ impl<'de, const D: usize> Deserialize<'de> for Const { } } +#[cfg(feature = "rkyv-serialize-no-std")] +impl Archive for Const { + type Archived = Self; + type Resolver = (); + + fn resolve(&self, _: usize, _: Self::Resolver, _: &mut core::mem::MaybeUninit) { + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl Serialize for Const { + fn serialize(&self, _: &mut S) -> Result { + Ok(()) + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl Deserialize for Const { + fn deserialize(&self, _: &mut D) -> Result { + Ok(Const) + } +} + pub trait ToConst { type Const: DimName; } diff --git a/src/base/matrix.rs b/src/base/matrix.rs index c7e02e22..939e78b3 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -156,7 +156,6 @@ pub type MatrixCross = /// some concrete types for `T` and a compatible data storage type `S`). #[repr(C)] #[derive(Clone, Copy)] -#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Deserialize, Serialize))] pub struct Matrix { /// The data storage that contains all the matrix components. Disappointed? /// @@ -312,6 +311,40 @@ where { } +#[cfg(feature = "rkyv-serialize-no-std")] +impl Archive for Matrix { + type Archived = Matrix; + type Resolver = S::Resolver; + + fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut core::mem::MaybeUninit) { + self.data.resolve( + pos + rkyv::offset_of!(Self::Archived, data), + resolver, + rkyv::project_struct!(out: Self::Archived => data) + ); + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl, _S: rkyv::Fallible + ?Sized> Serialize<_S> for Matrix { + fn serialize(&self, serializer: &mut _S) -> Result { + Ok(self.data.serialize(serializer)?) + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl Deserialize, D> for Matrix +where + S::Archived: Deserialize, +{ + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(Matrix { + data: self.data.deserialize(deserializer)?, + _phantoms: PhantomData, + }) + } +} + impl Matrix { /// Creates a new matrix with the given data without statically checking that the matrix /// dimension matches the storage dimension. diff --git a/src/base/unit.rs b/src/base/unit.rs index 4b1d1948..0c30f961 100644 --- a/src/base/unit.rs +++ b/src/base/unit.rs @@ -29,7 +29,6 @@ use crate::{Dim, Matrix, OMatrix, RealField, Scalar, SimdComplexField, SimdRealF /// in their documentation, read their dedicated pages directly. #[repr(transparent)] #[derive(Clone, Hash, Debug, Copy)] -#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Deserialize, Serialize))] pub struct Unit { pub(crate) value: T, } @@ -75,6 +74,39 @@ impl Abomonation for Unit { } } +#[cfg(feature = "rkyv-serialize-no-std")] +impl Archive for Unit { + type Archived = Unit; + type Resolver = T::Resolver; + + fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut ::core::mem::MaybeUninit) { + self.value.resolve( + pos + rkyv::offset_of!(Self::Archived, value), + resolver, + rkyv::project_struct!(out: Self::Archived => value), + ); + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl, S: rkyv::Fallible + ?Sized> Serialize for Unit { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(self.value.serialize(serializer)?) + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl Deserialize, D> for Unit +where + T::Archived: Deserialize, +{ + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(Unit { + value: self.value.deserialize(deserializer)?, + }) + } +} + impl PartialEq for Unit> where T: Scalar + PartialEq, diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index 7c8686c0..dea1b1be 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -71,7 +71,6 @@ use crate::geometry::{AbstractRotation, Point, Translation}; DefaultAllocator: Allocator>, Owned>: Deserialize<'de>")) )] -#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Serialize, Deserialize))] pub struct Isometry { /// The pure rotational part of this isometry. pub rotation: R, @@ -102,6 +101,55 @@ where } } +#[cfg(feature = "rkyv-serialize-no-std")] +impl Archive for Isometry +where + T::Archived: Scalar, +{ + type Archived = Isometry; + type Resolver = (R::Resolver, as Archive>::Resolver); + + fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut core::mem::MaybeUninit) { + self.rotation.resolve( + pos + rkyv::offset_of!(Self::Archived, rotation), + resolver.0, + rkyv::project_struct!(out: Self::Archived => rotation) + ); + self.translation.resolve( + pos + rkyv::offset_of!(Self::Archived, translation), + resolver.1, + rkyv::project_struct!(out: Self::Archived => translation) + ); + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl, R: Serialize, S: rkyv::Fallible + ?Sized, const D: usize> Serialize for Isometry +where + T::Archived: Scalar, +{ + fn serialize(&self, serializer: &mut S) -> Result { + Ok(( + self.rotation.serialize(serializer)?, + self.translation.serialize(serializer)?, + )) + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl Deserialize, _D> for Isometry +where + T::Archived: Scalar + Deserialize, + R::Archived: Scalar + Deserialize, +{ + fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { + Ok(Isometry { + rotation: self.rotation.deserialize(deserializer)?, + translation: self.translation.deserialize(deserializer)?, + }) + } +} + impl hash::Hash for Isometry where Owned>: hash::Hash, diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 9a920a8a..7c6a70ae 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -31,7 +31,6 @@ use crate::geometry::{Point3, Rotation}; /// that may be used as a rotation. #[repr(C)] #[derive(Debug, Copy, Clone)] -#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Deserialize, Serialize))] pub struct Quaternion { /// This quaternion as a 4D vector of coordinates in the `[ x, y, z, w ]` storage order. pub coords: Vector4, @@ -117,6 +116,39 @@ where } } +#[cfg(feature = "rkyv-serialize-no-std")] +impl Archive for Quaternion { + type Archived = Quaternion; + type Resolver = as Archive>::Resolver; + + fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut core::mem::MaybeUninit) { + self.coords.resolve( + pos + rkyv::offset_of!(Self::Archived, coords), + resolver, + rkyv::project_struct!(out: Self::Archived => coords) + ); + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl, S: rkyv::Fallible + ?Sized> Serialize for Quaternion { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(self.coords.serialize(serializer)?) + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl Deserialize, D> for Quaternion +where + T::Archived: Deserialize, +{ + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(Quaternion { + coords: self.coords.deserialize(deserializer)?, + }) + } +} + impl Quaternion where T::Element: SimdRealField, diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs index 92747dab..7f3665ae 100755 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -26,7 +26,6 @@ use crate::geometry::Point; /// A translation. #[repr(C)] #[derive(Debug)] -#[cfg_attr(feature = "rkyv-serialize-no-std", derive(Archive, Deserialize, Serialize))] pub struct Translation { /// The translation coordinates, i.e., how much is added to a point's coordinates when it is /// translated. @@ -101,6 +100,39 @@ where } } +#[cfg(feature = "rkyv-serialize-no-std")] +impl Archive for Translation { + type Archived = Translation; + type Resolver = as Archive>::Resolver; + + fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut core::mem::MaybeUninit) { + self.vector.resolve( + pos + rkyv::offset_of!(Self::Archived, vector), + resolver, + rkyv::project_struct!(out: Self::Archived => vector) + ); + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl, S: rkyv::Fallible + ?Sized, const D: usize> Serialize for Translation { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(self.vector.serialize(serializer)?) + } +} + +#[cfg(feature = "rkyv-serialize-no-std")] +impl Deserialize, _D> for Translation +where + T::Archived: Deserialize, +{ + fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { + Ok(Translation { + vector: self.vector.deserialize(deserializer)?, + }) + } +} + impl Translation { /// Creates a new translation from the given vector. #[inline] From 9fff10b1f08f76aabc0a7ad8039eeae22020229c Mon Sep 17 00:00:00 2001 From: David Koloski Date: Sun, 9 May 2021 11:28:49 -0400 Subject: [PATCH 50/57] Move rkyv impls into separate modules --- src/base/array_storage.rs | 66 ++++++++++++++------------ src/base/dimension.rs | 39 ++++++++------- src/base/matrix.rs | 66 +++++++++++++++----------- src/base/unit.rs | 59 ++++++++++++----------- src/geometry/isometry.rs | 94 ++++++++++++++++++++----------------- src/geometry/quaternion.rs | 60 ++++++++++++----------- src/geometry/translation.rs | 61 +++++++++++++----------- 7 files changed, 247 insertions(+), 198 deletions(-) diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index 350240cd..6d681ed5 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -18,9 +18,6 @@ use std::mem; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -#[cfg(feature = "rkyv-serialize-no-std")] -use rkyv::{Archive, Deserialize, Serialize}; - use crate::base::allocator::Allocator; use crate::base::default_allocator::DefaultAllocator; use crate::base::dimension::{Const, ToTypenum}; @@ -304,32 +301,43 @@ where } #[cfg(feature = "rkyv-serialize-no-std")] -impl Archive for ArrayStorage { - type Archived = ArrayStorage; - type Resolver = <[[T; R]; C] as Archive>::Resolver; +mod rkyv_impl { + use super::ArrayStorage; + use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; - fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut core::mem::MaybeUninit) { - self.0.resolve( - pos + rkyv::offset_of!(Self::Archived, 0), - resolver, - rkyv::project_struct!(out: Self::Archived => 0) - ); - } -} - -#[cfg(feature = "rkyv-serialize-no-std")] -impl, S: rkyv::Fallible + ?Sized, const R: usize, const C: usize> Serialize for ArrayStorage { - fn serialize(&self, serializer: &mut S) -> Result { - Ok(self.0.serialize(serializer)?) - } -} - -#[cfg(feature = "rkyv-serialize-no-std")] -impl Deserialize, D> for ArrayStorage -where - T::Archived: Deserialize, -{ - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - Ok(ArrayStorage(self.0.deserialize(deserializer)?)) + impl Archive for ArrayStorage { + type Archived = ArrayStorage; + type Resolver = <[[T; R]; C] as Archive>::Resolver; + + fn resolve( + &self, + pos: usize, + resolver: Self::Resolver, + out: &mut core::mem::MaybeUninit, + ) { + self.0.resolve( + pos + offset_of!(Self::Archived, 0), + resolver, + project_struct!(out: Self::Archived => 0), + ); + } + } + + impl, S: Fallible + ?Sized, const R: usize, const C: usize> Serialize + for ArrayStorage + { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(self.0.serialize(serializer)?) + } + } + + impl + Deserialize, D> for ArrayStorage + where + T::Archived: Deserialize, + { + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(ArrayStorage(self.0.deserialize(deserializer)?)) + } } } diff --git a/src/base/dimension.rs b/src/base/dimension.rs index 3ee762f1..2b5ccec3 100644 --- a/src/base/dimension.rs +++ b/src/base/dimension.rs @@ -11,9 +11,6 @@ use typenum::{self, Diff, Max, Maximum, Min, Minimum, Prod, Quot, Sum, Unsigned} #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(feature = "rkyv-serialize-no-std")] -use rkyv::{Archive, Deserialize, Serialize}; - /// Dim of dynamically-sized algebraic entities. #[derive(Clone, Copy, Eq, PartialEq, Debug)] pub struct Dynamic { @@ -235,25 +232,33 @@ impl<'de, const D: usize> Deserialize<'de> for Const { } #[cfg(feature = "rkyv-serialize-no-std")] -impl Archive for Const { - type Archived = Self; - type Resolver = (); +mod rkyv_impl { + use super::Const; + use rkyv::{Archive, Deserialize, Fallible, Serialize}; - fn resolve(&self, _: usize, _: Self::Resolver, _: &mut core::mem::MaybeUninit) { + impl Archive for Const { + type Archived = Self; + type Resolver = (); + + fn resolve( + &self, + _: usize, + _: Self::Resolver, + _: &mut core::mem::MaybeUninit, + ) { + } } -} -#[cfg(feature = "rkyv-serialize-no-std")] -impl Serialize for Const { - fn serialize(&self, _: &mut S) -> Result { - Ok(()) + impl Serialize for Const { + fn serialize(&self, _: &mut S) -> Result { + Ok(()) + } } -} -#[cfg(feature = "rkyv-serialize-no-std")] -impl Deserialize for Const { - fn deserialize(&self, _: &mut D) -> Result { - Ok(Const) + impl Deserialize for Const { + fn deserialize(&self, _: &mut D) -> Result { + Ok(Const) + } } } diff --git a/src/base/matrix.rs b/src/base/matrix.rs index 939e78b3..bc9942be 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -16,9 +16,6 @@ use serde::{Deserialize, Deserializer, Serialize, Serializer}; #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; -#[cfg(feature = "rkyv-serialize-no-std")] -use rkyv::{Archive, Deserialize, Serialize}; - use simba::scalar::{ClosedAdd, ClosedMul, ClosedSub, Field, SupersetOf}; use simba::simd::SimdPartialOrd; @@ -312,36 +309,49 @@ where } #[cfg(feature = "rkyv-serialize-no-std")] -impl Archive for Matrix { - type Archived = Matrix; - type Resolver = S::Resolver; +mod rkyv_impl { + use super::Matrix; + use core::marker::PhantomData; + use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; - fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut core::mem::MaybeUninit) { - self.data.resolve( - pos + rkyv::offset_of!(Self::Archived, data), - resolver, - rkyv::project_struct!(out: Self::Archived => data) - ); + impl Archive for Matrix { + type Archived = Matrix; + type Resolver = S::Resolver; + + fn resolve( + &self, + pos: usize, + resolver: Self::Resolver, + out: &mut core::mem::MaybeUninit, + ) { + self.data.resolve( + pos + offset_of!(Self::Archived, data), + resolver, + project_struct!(out: Self::Archived => data), + ); + } } -} -#[cfg(feature = "rkyv-serialize-no-std")] -impl, _S: rkyv::Fallible + ?Sized> Serialize<_S> for Matrix { - fn serialize(&self, serializer: &mut _S) -> Result { - Ok(self.data.serialize(serializer)?) + impl, _S: Fallible + ?Sized> Serialize<_S> + for Matrix + { + fn serialize(&self, serializer: &mut _S) -> Result { + Ok(self.data.serialize(serializer)?) + } } -} -#[cfg(feature = "rkyv-serialize-no-std")] -impl Deserialize, D> for Matrix -where - S::Archived: Deserialize, -{ - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - Ok(Matrix { - data: self.data.deserialize(deserializer)?, - _phantoms: PhantomData, - }) + impl + Deserialize, D> + for Matrix + where + S::Archived: Deserialize, + { + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(Matrix { + data: self.data.deserialize(deserializer)?, + _phantoms: PhantomData, + }) + } } } diff --git a/src/base/unit.rs b/src/base/unit.rs index 0c30f961..b5a4096f 100644 --- a/src/base/unit.rs +++ b/src/base/unit.rs @@ -6,9 +6,6 @@ use std::ops::Deref; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(feature = "rkyv-serialize-no-std")] -use rkyv::{Archive, Deserialize, Serialize}; - #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; @@ -75,35 +72,43 @@ impl Abomonation for Unit { } #[cfg(feature = "rkyv-serialize-no-std")] -impl Archive for Unit { - type Archived = Unit; - type Resolver = T::Resolver; +mod rkyv_impl { + use super::Unit; + use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; - fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut ::core::mem::MaybeUninit) { - self.value.resolve( - pos + rkyv::offset_of!(Self::Archived, value), - resolver, - rkyv::project_struct!(out: Self::Archived => value), - ); + impl Archive for Unit { + type Archived = Unit; + type Resolver = T::Resolver; + + fn resolve( + &self, + pos: usize, + resolver: Self::Resolver, + out: &mut ::core::mem::MaybeUninit, + ) { + self.value.resolve( + pos + offset_of!(Self::Archived, value), + resolver, + project_struct!(out: Self::Archived => value), + ); + } } -} -#[cfg(feature = "rkyv-serialize-no-std")] -impl, S: rkyv::Fallible + ?Sized> Serialize for Unit { - fn serialize(&self, serializer: &mut S) -> Result { - Ok(self.value.serialize(serializer)?) + impl, S: Fallible + ?Sized> Serialize for Unit { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(self.value.serialize(serializer)?) + } } -} -#[cfg(feature = "rkyv-serialize-no-std")] -impl Deserialize, D> for Unit -where - T::Archived: Deserialize, -{ - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - Ok(Unit { - value: self.value.deserialize(deserializer)?, - }) + impl Deserialize, D> for Unit + where + T::Archived: Deserialize, + { + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(Unit { + value: self.value.deserialize(deserializer)?, + }) + } } } diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index dea1b1be..d307c393 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -7,9 +7,6 @@ use std::io::{Result as IOResult, Write}; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Serialize}; -#[cfg(feature = "rkyv-serialize-no-std")] -use rkyv::{Archive, Deserialize, Serialize}; - #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; @@ -102,51 +99,62 @@ where } #[cfg(feature = "rkyv-serialize-no-std")] -impl Archive for Isometry -where - T::Archived: Scalar, -{ - type Archived = Isometry; - type Resolver = (R::Resolver, as Archive>::Resolver); +mod rkyv_impl { + use super::Isometry; + use crate::{base::Scalar, geometry::Translation}; + use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; - fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut core::mem::MaybeUninit) { - self.rotation.resolve( - pos + rkyv::offset_of!(Self::Archived, rotation), - resolver.0, - rkyv::project_struct!(out: Self::Archived => rotation) - ); - self.translation.resolve( - pos + rkyv::offset_of!(Self::Archived, translation), - resolver.1, - rkyv::project_struct!(out: Self::Archived => translation) - ); + impl Archive for Isometry + where + T::Archived: Scalar, + { + type Archived = Isometry; + type Resolver = (R::Resolver, as Archive>::Resolver); + + fn resolve( + &self, + pos: usize, + resolver: Self::Resolver, + out: &mut core::mem::MaybeUninit, + ) { + self.rotation.resolve( + pos + offset_of!(Self::Archived, rotation), + resolver.0, + project_struct!(out: Self::Archived => rotation), + ); + self.translation.resolve( + pos + offset_of!(Self::Archived, translation), + resolver.1, + project_struct!(out: Self::Archived => translation), + ); + } } -} -#[cfg(feature = "rkyv-serialize-no-std")] -impl, R: Serialize, S: rkyv::Fallible + ?Sized, const D: usize> Serialize for Isometry -where - T::Archived: Scalar, -{ - fn serialize(&self, serializer: &mut S) -> Result { - Ok(( - self.rotation.serialize(serializer)?, - self.translation.serialize(serializer)?, - )) + impl, R: Serialize, S: Fallible + ?Sized, const D: usize> + Serialize for Isometry + where + T::Archived: Scalar, + { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(( + self.rotation.serialize(serializer)?, + self.translation.serialize(serializer)?, + )) + } } -} -#[cfg(feature = "rkyv-serialize-no-std")] -impl Deserialize, _D> for Isometry -where - T::Archived: Scalar + Deserialize, - R::Archived: Scalar + Deserialize, -{ - fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { - Ok(Isometry { - rotation: self.rotation.deserialize(deserializer)?, - translation: self.translation.deserialize(deserializer)?, - }) + impl + Deserialize, _D> for Isometry + where + T::Archived: Scalar + Deserialize, + R::Archived: Scalar + Deserialize, + { + fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { + Ok(Isometry { + rotation: self.rotation.deserialize(deserializer)?, + translation: self.translation.deserialize(deserializer)?, + }) + } } } diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 7c6a70ae..6852335b 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -10,9 +10,6 @@ use crate::base::storage::Owned; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(feature = "rkyv-serialize-no-std")] -use rkyv::{Archive, Deserialize, Serialize}; - #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; @@ -117,35 +114,44 @@ where } #[cfg(feature = "rkyv-serialize-no-std")] -impl Archive for Quaternion { - type Archived = Quaternion; - type Resolver = as Archive>::Resolver; +mod rkyv_impl { + use super::Quaternion; + use crate::base::Vector4; + use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; - fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut core::mem::MaybeUninit) { - self.coords.resolve( - pos + rkyv::offset_of!(Self::Archived, coords), - resolver, - rkyv::project_struct!(out: Self::Archived => coords) - ); + impl Archive for Quaternion { + type Archived = Quaternion; + type Resolver = as Archive>::Resolver; + + fn resolve( + &self, + pos: usize, + resolver: Self::Resolver, + out: &mut core::mem::MaybeUninit, + ) { + self.coords.resolve( + pos + offset_of!(Self::Archived, coords), + resolver, + project_struct!(out: Self::Archived => coords), + ); + } } -} -#[cfg(feature = "rkyv-serialize-no-std")] -impl, S: rkyv::Fallible + ?Sized> Serialize for Quaternion { - fn serialize(&self, serializer: &mut S) -> Result { - Ok(self.coords.serialize(serializer)?) + impl, S: Fallible + ?Sized> Serialize for Quaternion { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(self.coords.serialize(serializer)?) + } } -} -#[cfg(feature = "rkyv-serialize-no-std")] -impl Deserialize, D> for Quaternion -where - T::Archived: Deserialize, -{ - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - Ok(Quaternion { - coords: self.coords.deserialize(deserializer)?, - }) + impl Deserialize, D> for Quaternion + where + T::Archived: Deserialize, + { + fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { + Ok(Quaternion { + coords: self.coords.deserialize(deserializer)?, + }) + } } } diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs index 7f3665ae..dcb7b603 100755 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -8,9 +8,6 @@ use std::io::{Result as IOResult, Write}; #[cfg(feature = "serde-serialize-no-std")] use serde::{Deserialize, Deserializer, Serialize, Serializer}; -#[cfg(feature = "rkyv-serialize-no-std")] -use rkyv::{Archive, Deserialize, Serialize}; - #[cfg(feature = "abomonation-serialize")] use abomonation::Abomonation; @@ -101,35 +98,45 @@ where } #[cfg(feature = "rkyv-serialize-no-std")] -impl Archive for Translation { - type Archived = Translation; - type Resolver = as Archive>::Resolver; +mod rkyv_impl { + use super::Translation; + use crate::base::SVector; + use rkyv::{offset_of, project_struct, Archive, Deserialize, Fallible, Serialize}; - fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut core::mem::MaybeUninit) { - self.vector.resolve( - pos + rkyv::offset_of!(Self::Archived, vector), - resolver, - rkyv::project_struct!(out: Self::Archived => vector) - ); + impl Archive for Translation { + type Archived = Translation; + type Resolver = as Archive>::Resolver; + + fn resolve( + &self, + pos: usize, + resolver: Self::Resolver, + out: &mut core::mem::MaybeUninit, + ) { + self.vector.resolve( + pos + offset_of!(Self::Archived, vector), + resolver, + project_struct!(out: Self::Archived => vector), + ); + } } -} -#[cfg(feature = "rkyv-serialize-no-std")] -impl, S: rkyv::Fallible + ?Sized, const D: usize> Serialize for Translation { - fn serialize(&self, serializer: &mut S) -> Result { - Ok(self.vector.serialize(serializer)?) + impl, S: Fallible + ?Sized, const D: usize> Serialize for Translation { + fn serialize(&self, serializer: &mut S) -> Result { + Ok(self.vector.serialize(serializer)?) + } } -} -#[cfg(feature = "rkyv-serialize-no-std")] -impl Deserialize, _D> for Translation -where - T::Archived: Deserialize, -{ - fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { - Ok(Translation { - vector: self.vector.deserialize(deserializer)?, - }) + impl Deserialize, _D> + for Translation + where + T::Archived: Deserialize, + { + fn deserialize(&self, deserializer: &mut _D) -> Result, _D::Error> { + Ok(Translation { + vector: self.vector.deserialize(deserializer)?, + }) + } } } From 79ef862fe9bd5f6d97a864c36274e0eb69468025 Mon Sep 17 00:00:00 2001 From: Dave Farnham Date: Sun, 9 May 2021 14:58:26 -0600 Subject: [PATCH 51/57] Fix docs on csc_data(), csc_data_mut() --- nalgebra-sparse/src/csc.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nalgebra-sparse/src/csc.rs b/nalgebra-sparse/src/csc.rs index 3a4d3f6f..6a88c1d5 100644 --- a/nalgebra-sparse/src/csc.rs +++ b/nalgebra-sparse/src/csc.rs @@ -440,12 +440,12 @@ impl CscMatrix { .expect("Out of bounds matrix indices encountered") } - /// Returns a triplet of slices `(row_offsets, col_indices, values)` that make up the CSC data. + /// Returns a triplet of slices `(col_offsets, row_indices, values)` that make up the CSC data. pub fn csc_data(&self) -> (&[usize], &[usize], &[T]) { self.cs.cs_data() } - /// Returns a triplet of slices `(row_offsets, col_indices, values)` that make up the CSC data, + /// Returns a triplet of slices `(col_offsets, row_indices, values)` that make up the CSC data, /// where the `values` array is mutable. pub fn csc_data_mut(&mut self) -> (&[usize], &[usize], &mut [T]) { self.cs.cs_data_mut() From 8810b85a2f23981f61770747edf125b9535d4902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Mon, 24 May 2021 17:53:59 +0200 Subject: [PATCH 52/57] Add a point! macro for construction points This macro is similar to the `vector!` macro, except that it builds a point instead of a vector. --- nalgebra-macros/src/lib.rs | 31 +++++++++++++++++++ nalgebra-macros/tests/tests.rs | 55 ++++++++++++++++++++++++++++++++-- src/lib.rs | 2 +- tests/core/macros.rs | 3 +- 4 files changed, 86 insertions(+), 5 deletions(-) diff --git a/nalgebra-macros/src/lib.rs b/nalgebra-macros/src/lib.rs index 5b1dd677..beddfc74 100644 --- a/nalgebra-macros/src/lib.rs +++ b/nalgebra-macros/src/lib.rs @@ -280,3 +280,34 @@ pub fn dvector(stream: TokenStream) -> TokenStream { }; proc_macro::TokenStream::from(output) } + +/// Construct a fixed-size point directly from data. +/// +/// **Note: Requires the `macro` feature to be enabled (enabled by default)**. +/// +/// Similarly to [`vector!`], this macro facilitates easy construction of points. +/// +/// `point!` is intended to be the most readable and performant way of constructing small, +/// points, and it is usable in `const fn` contexts. +/// +/// ## Examples +/// +/// ``` +/// use nalgebra::point; +/// +/// // Produces a Point3<_> +/// let v = point![1, 2, 3]; +/// ``` +#[proc_macro] +pub fn point(stream: TokenStream) -> TokenStream { + let vector = parse_macro_input!(stream as Vector); + let len = vector.len(); + let array_tokens = vector.to_array_tokens(); + let output = quote! { + nalgebra::Point::<_, #len> { + coords: nalgebra::SVector::<_, #len> + ::from_array_storage(nalgebra::ArrayStorage([#array_tokens])) + } + }; + proc_macro::TokenStream::from(output) +} diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index 339dd048..e69f9e6b 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -1,9 +1,10 @@ use nalgebra::{ DMatrix, DVector, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2, Matrix2x1, Matrix2x3, Matrix2x4, - Matrix3, Matrix3x1, Matrix3x2, Matrix3x4, Matrix4, Matrix4x1, Matrix4x2, Matrix4x3, SMatrix, - SVector, Vector1, Vector2, Vector3, Vector4, Vector5, Vector6, + Matrix3, Matrix3x1, Matrix3x2, Matrix3x4, Matrix4, Matrix4x1, Matrix4x2, Matrix4x3, PEoint4, + Point, Point1, Point2, Point3, Point4, Point5, Point6, SMatrix, SVector, Vector1, Vector2, + Vector3, Vector4, Vector5, Vector6, }; -use nalgebra_macros::{dmatrix, dvector, matrix, vector}; +use nalgebra_macros::{dmatrix, dvector, matrix, point, vector}; fn check_statically_same_type(_: &T, _: &T) {} @@ -106,6 +107,19 @@ fn vector_small_dims_exhaustive() { assert_eq_and_type!(vector![1, 2, 3, 4, 5, 6], Vector6::new(1, 2, 3, 4, 5, 6)); } +// Skip rustfmt because it just makes the test bloated without making it more readable +#[rustfmt::skip] +#[test] +fn point_small_dims_exhaustive() { + assert_eq_and_type!(point![], Point::::origin()); + assert_eq_and_type!(point![1], Point1::::new(1)); + assert_eq_and_type!(point![1, 2], Point2::new(1, 2)); + assert_eq_and_type!(point![1, 2, 3], Point3::new(1, 2, 3)); + assert_eq_and_type!(point![1, 2, 3, 4], Point4::new(1, 2, 3, 4)); + assert_eq_and_type!(point![1, 2, 3, 4, 5], Point5::new(1, 2, 3, 4, 5)); + assert_eq_and_type!(point![1, 2, 3, 4, 5, 6], Point6::new(1, 2, 3, 4, 5, 6)); +} + #[test] fn vector_const_fn() { // Ensure that vector! can be used in const contexts @@ -115,6 +129,15 @@ fn vector_const_fn() { const _: Vector6 = vector![1, 2, 3, 4, 5, 6]; } +#[test] +fn point_const_fn() { + // Ensure that vector! can be used in const contexts + const _: Point = vector![]; + const _: Point1 = vector![1]; + const _: Point2 = vector![1, 2]; + const _: Point6 = vector![1, 2, 3, 4, 5, 6]; +} + // Skip rustfmt because it just makes the test bloated without making it more readable #[rustfmt::skip] #[test] @@ -195,6 +218,23 @@ fn dmatrix_builtin_types() { let _: DMatrix = dmatrix![0.0, 1.0; 2.0, 3.0]; } +#[test] +fn point_builtin_types() { + // Check that point! compiles for all built-in types + const _: Point = point![0, 1, 2, 3]; + const _: Point = point![0, 1, 2, 3]; + const _: Point = point![0, 1, 2, 3]; + const _: Point = point![0, 1, 2, 3]; + const _: Point = point![0, 1, 2, 3]; + const _: Point = point![0, 1, 2, 3]; + const _: Point = point![0, 1, 2, 3]; + const _: Point = point![0, 1, 2, 3]; + const _: Point = point![0, 1, 2, 3]; + const _: Point = point![0, 1, 2, 3]; + const _: Point = point![0.0, 1.0, 2.0, 3.0]; + const _: Point = point![0.0, 1.0, 2.0, 3.0]; +} + #[test] fn dvector_builtin_types() { // Check that dvector! compiles for all built-in types @@ -248,6 +288,15 @@ fn vector_arbitrary_expressions() { assert_eq_and_type!(a, a_expected); } +#[rustfmt::skip] +#[test] +fn point_arbitrary_expressions() { + // Test that point! supports arbitrary expressions for its elements + let a = point![1 + 2, 2 * 3, 4 * f(5 + 6), 7 - 8 * 9]; + let a_expected = Point4::new(1 + 2, 2 * 3, 4 * f(5 + 6), 7 - 8 * 9); + assert_eq_and_type!(a, a_expected); +} + #[rustfmt::skip] #[test] fn dvector_arbitrary_expressions() { diff --git a/src/lib.rs b/src/lib.rs index ea05e17d..8378b272 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -137,7 +137,7 @@ pub use crate::sparse::*; pub use base as core; #[cfg(feature = "macros")] -pub use nalgebra_macros::{dmatrix, dvector, matrix, vector}; +pub use nalgebra_macros::{dmatrix, dvector, matrix, point, vector}; use simba::scalar::SupersetOf; use std::cmp::{self, Ordering, PartialOrd}; diff --git a/tests/core/macros.rs b/tests/core/macros.rs index eaa134ff..2987a41b 100644 --- a/tests/core/macros.rs +++ b/tests/core/macros.rs @@ -1,4 +1,4 @@ -use nalgebra::{dmatrix, dvector, matrix, vector}; +use nalgebra::{dmatrix, dvector, matrix, point, vector}; #[test] fn sanity_test() { @@ -6,6 +6,7 @@ fn sanity_test() { let _ = matrix![1, 2, 3; 4, 5, 6]; let _ = dmatrix![1, 2, 3; 4, 5, 6]; + let _ = point![1, 2, 3, 4, 5, 6]; let _ = vector![1, 2, 3, 4, 5, 6]; let _ = dvector![1, 2, 3, 4, 5, 6]; } From d6d2a3e96869c9bb6f90ff4844898bf1161d2721 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Mon, 24 May 2021 18:00:30 +0200 Subject: [PATCH 53/57] Fix macros tests. --- nalgebra-macros/tests/tests.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index e69f9e6b..68b09610 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -132,10 +132,10 @@ fn vector_const_fn() { #[test] fn point_const_fn() { // Ensure that vector! can be used in const contexts - const _: Point = vector![]; - const _: Point1 = vector![1]; - const _: Point2 = vector![1, 2]; - const _: Point6 = vector![1, 2, 3, 4, 5, 6]; + const _: Point = point![]; + const _: Point1 = point![1]; + const _: Point2 = point![1, 2]; + const _: Point6 = point![1, 2, 3, 4, 5, 6]; } // Skip rustfmt because it just makes the test bloated without making it more readable From 0490a844fbc5b1f99e949b699449838c8eb25d01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Mon, 24 May 2021 18:10:26 +0200 Subject: [PATCH 54/57] Fix typo --- nalgebra-macros/tests/tests.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/nalgebra-macros/tests/tests.rs b/nalgebra-macros/tests/tests.rs index 68b09610..0e52da1f 100644 --- a/nalgebra-macros/tests/tests.rs +++ b/nalgebra-macros/tests/tests.rs @@ -1,8 +1,8 @@ use nalgebra::{ DMatrix, DVector, Matrix1x2, Matrix1x3, Matrix1x4, Matrix2, Matrix2x1, Matrix2x3, Matrix2x4, - Matrix3, Matrix3x1, Matrix3x2, Matrix3x4, Matrix4, Matrix4x1, Matrix4x2, Matrix4x3, PEoint4, - Point, Point1, Point2, Point3, Point4, Point5, Point6, SMatrix, SVector, Vector1, Vector2, - Vector3, Vector4, Vector5, Vector6, + Matrix3, Matrix3x1, Matrix3x2, Matrix3x4, Matrix4, Matrix4x1, Matrix4x2, Matrix4x3, Point, + Point1, Point2, Point3, Point4, Point5, Point6, SMatrix, SVector, Vector1, Vector2, Vector3, + Vector4, Vector5, Vector6, }; use nalgebra_macros::{dmatrix, dvector, matrix, point, vector}; From 4af979c55b37bb757616bc2db59f01feeecfb0e3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Tue, 1 Jun 2021 10:27:32 +0200 Subject: [PATCH 55/57] Support multiple version of the optional glam conversion --- Cargo.toml | 13 +++- .../glam/{ => common}/glam_isometry.rs | 76 ++++++++++++++++++- .../glam/{ => common}/glam_matrix.rs | 6 +- .../glam/{ => common}/glam_point.rs | 4 +- .../glam/{ => common}/glam_quaternion.rs | 4 +- .../glam/{ => common}/glam_rotation.rs | 4 +- .../glam/{ => common}/glam_similarity.rs | 4 +- .../glam/{ => common}/glam_translation.rs | 2 +- .../glam/{ => common}/glam_unit_complex.rs | 4 +- src/third_party/glam/mod.rs | 14 ++-- src/third_party/glam/v013/mod.rs | 18 +++++ src/third_party/glam/v014/mod.rs | 18 +++++ src/third_party/glam/v015/mod.rs | 18 +++++ src/third_party/mod.rs | 1 - 14 files changed, 158 insertions(+), 28 deletions(-) rename src/third_party/glam/{ => common}/glam_isometry.rs (61%) rename src/third_party/glam/{ => common}/glam_matrix.rs (99%) rename src/third_party/glam/{ => common}/glam_point.rs (98%) rename src/third_party/glam/{ => common}/glam_quaternion.rs (95%) rename src/third_party/glam/{ => common}/glam_rotation.rs (93%) rename src/third_party/glam/{ => common}/glam_similarity.rs (93%) rename src/third_party/glam/{ => common}/glam_translation.rs (96%) rename src/third_party/glam/{ => common}/glam_unit_complex.rs (91%) create mode 100644 src/third_party/glam/v013/mod.rs create mode 100644 src/third_party/glam/v014/mod.rs create mode 100644 src/third_party/glam/v015/mod.rs diff --git a/Cargo.toml b/Cargo.toml index f1d65128..f879ae1f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -36,9 +36,13 @@ macros = [ "nalgebra-macros" ] # Conversion convert-mint = [ "mint" ] -convert-glam = [ "glam" ] -convert-glam-unchecked = [ "convert-glam" ] # Enable edgy conversions like Mat4 -> Isometry3 convert-bytemuck = [ "bytemuck" ] +convert-glam013 = [ "glam013" ] +convert-glam013-unchecked = [ "convert-glam013" ] # Enable edgy conversions like Mat4 -> Isometry3 +convert-glam014 = [ "glam014" ] +convert-glam014-unchecked = [ "convert-glam014" ] # Enable edgy conversions like Mat4 -> Isometry3 +convert-glam015 = [ "glam015" ] +convert-glam015-unchecked = [ "convert-glam015" ] # Enable edgy conversions like Mat4 -> Isometry3 # Serialization ## To use serde in a #[no-std] environment, enable the @@ -78,13 +82,16 @@ serde = { version = "1.0", default-features = false, features = [ "deri abomonation = { version = "0.7", optional = true } rkyv = { version = "~0.6.4", default-features = false, features = ["const_generics"], optional = true } mint = { version = "0.5", optional = true } -glam = { version = "0.13", optional = true } quickcheck = { version = "1", optional = true } pest = { version = "2", optional = true } pest_derive = { version = "2", optional = true } bytemuck = { version = "1.5", optional = true } matrixcompare-core = { version = "0.1", optional = true } proptest = { version = "1", optional = true, default-features = false, features = ["std"] } +glam013 = { package = "glam", version = "0.13", optional = true } +glam014 = { package = "glam", version = "0.14", optional = true } +glam015 = { package = "glam", version = "0.15", optional = true } + [dev-dependencies] serde_json = "1.0" diff --git a/src/third_party/glam/glam_isometry.rs b/src/third_party/glam/common/glam_isometry.rs similarity index 61% rename from src/third_party/glam/glam_isometry.rs rename to src/third_party/glam/common/glam_isometry.rs index 34a321e5..3d2cbaba 100644 --- a/src/third_party/glam/glam_isometry.rs +++ b/src/third_party/glam/common/glam_isometry.rs @@ -1,5 +1,5 @@ +use super::glam::{DMat3, DMat4, DQuat, DVec3, Mat3, Mat4, Quat, Vec3}; use crate::{Isometry2, Isometry3}; -use glam::{DMat3, DMat4, DQuat, DVec3, Mat3, Mat4, Quat, Vec3}; impl From> for Mat3 { fn from(iso: Isometry2) -> Mat3 { @@ -53,8 +53,8 @@ impl From> for (DVec3, DQuat) { #[cfg(feature = "convert-glam-unchecked")] mod unchecked { + use super::super::glam::{DMat3, DMat4, DQuat, DVec2, DVec3, Mat3, Mat4, Quat, Vec2, Vec3}; use crate::{Isometry2, Isometry3, Matrix3, Matrix4}; - use glam::{DMat3, DMat4, DQuat, DVec2, DVec3, Mat3, Mat4, Quat, Vec2, Vec3}; impl From<(Vec3, Quat)> for Isometry3 { fn from((tra, rot): (Vec3, Quat)) -> Self { @@ -92,6 +92,78 @@ mod unchecked { } } + impl From<(Vec2, f32)> for Isometry2 { + fn from((tra, rot): (Vec2, f32)) -> Self { + Isometry2::new([tra.x, tra.y].into(), rot) + } + } + + impl From<(DVec2, f64)> for Isometry2 { + fn from((tra, rot): (DVec2, f64)) -> Self { + Isometry2::new([tra.x, tra.y].into(), rot) + } + } + + impl From for Isometry3 { + fn from(rot: Quat) -> Self { + Isometry3::from_parts(crate::one(), rot.into()) + } + } + + impl From for Isometry3 { + fn from(rot: DQuat) -> Self { + Isometry3::from_parts(crate::one(), rot.into()) + } + } + + impl From for Isometry2 { + fn from(rot: Quat) -> Self { + Isometry2::new(crate::zero(), rot.to_axis_angle().1) + } + } + + impl From for Isometry2 { + fn from(rot: DQuat) -> Self { + Isometry2::new(crate::zero(), rot.to_axis_angle().1) + } + } + + impl From for Isometry3 { + fn from(tra: Vec3) -> Self { + Isometry3::from_parts(tra.into(), crate::one()) + } + } + + impl From for Isometry3 { + fn from(tra: DVec3) -> Self { + Isometry3::from_parts(tra.into(), crate::one()) + } + } + + impl From for Isometry2 { + fn from(tra: Vec2) -> Self { + Isometry2::new(tra.into(), crate::one()) + } + } + + impl From for Isometry2 { + fn from(tra: DVec2) -> Self { + Isometry2::new(tra.into(), crate::one()) + } + } + + impl From for Isometry2 { + fn from(tra: Vec3) -> Self { + Isometry2::new([tra.x, tra.y].into(), crate::one()) + } + } + + impl From for Isometry2 { + fn from(tra: DVec3) -> Self { + Isometry2::new([tra.x, tra.y].into(), crate::one()) + } + } + impl From for Isometry2 { fn from(mat3: Mat3) -> Isometry2 { crate::convert_unchecked(Matrix3::from(mat3)) diff --git a/src/third_party/glam/glam_matrix.rs b/src/third_party/glam/common/glam_matrix.rs similarity index 99% rename from src/third_party/glam/glam_matrix.rs rename to src/third_party/glam/common/glam_matrix.rs index bbb2bd17..77b68b5e 100644 --- a/src/third_party/glam/glam_matrix.rs +++ b/src/third_party/glam/common/glam_matrix.rs @@ -1,9 +1,9 @@ -use crate::storage::Storage; -use crate::{Matrix, Matrix2, Matrix3, Matrix4, Vector, Vector2, Vector3, Vector4, U2, U3, U4}; -use glam::{ +use super::glam::{ BVec2, BVec3, BVec4, DMat2, DMat3, DMat4, DVec2, DVec3, DVec4, IVec2, IVec3, IVec4, Mat2, Mat3, Mat4, UVec2, UVec3, UVec4, Vec2, Vec3, Vec3A, Vec4, }; +use crate::storage::Storage; +use crate::{Matrix, Matrix2, Matrix3, Matrix4, Vector, Vector2, Vector3, Vector4, U2, U3, U4}; macro_rules! impl_vec_conversion( ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { diff --git a/src/third_party/glam/glam_point.rs b/src/third_party/glam/common/glam_point.rs similarity index 98% rename from src/third_party/glam/glam_point.rs rename to src/third_party/glam/common/glam_point.rs index 823dc806..b15a6c6d 100644 --- a/src/third_party/glam/glam_point.rs +++ b/src/third_party/glam/common/glam_point.rs @@ -1,8 +1,8 @@ -use crate::{Point2, Point3, Point4}; -use glam::{ +use super::glam::{ BVec2, BVec3, BVec4, DVec2, DVec3, DVec4, IVec2, IVec3, IVec4, UVec2, UVec3, UVec4, Vec2, Vec3, Vec3A, Vec4, }; +use crate::{Point2, Point3, Point4}; macro_rules! impl_point_conversion( ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { diff --git a/src/third_party/glam/glam_quaternion.rs b/src/third_party/glam/common/glam_quaternion.rs similarity index 95% rename from src/third_party/glam/glam_quaternion.rs rename to src/third_party/glam/common/glam_quaternion.rs index e57b7714..a622bab7 100644 --- a/src/third_party/glam/glam_quaternion.rs +++ b/src/third_party/glam/common/glam_quaternion.rs @@ -1,5 +1,5 @@ +use super::glam::{DQuat, Quat}; use crate::{Quaternion, UnitQuaternion}; -use glam::{DQuat, Quat}; impl From for Quaternion { #[inline] @@ -45,8 +45,8 @@ impl From> for DQuat { #[cfg(feature = "convert-glam-unchecked")] mod unchecked { + use super::super::glam::{DQuat, Quat}; use crate::{Quaternion, UnitQuaternion}; - use glam::{DQuat, Quat}; impl From for UnitQuaternion { #[inline] diff --git a/src/third_party/glam/glam_rotation.rs b/src/third_party/glam/common/glam_rotation.rs similarity index 93% rename from src/third_party/glam/glam_rotation.rs rename to src/third_party/glam/common/glam_rotation.rs index 2db9f50e..6ae8d809 100644 --- a/src/third_party/glam/glam_rotation.rs +++ b/src/third_party/glam/common/glam_rotation.rs @@ -1,5 +1,5 @@ +use super::glam::{DMat2, DQuat, Mat2, Quat}; use crate::{Rotation2, Rotation3, UnitQuaternion}; -use glam::{DMat2, DQuat, Mat2, Quat}; impl From> for Mat2 { #[inline] @@ -31,8 +31,8 @@ impl From> for DQuat { #[cfg(feature = "convert-glam-unchecked")] mod unchecked { + use super::super::glam::{DMat2, DQuat, Mat2, Quat}; use crate::{Rotation2, Rotation3, UnitQuaternion}; - use glam::{DMat2, DQuat, Mat2, Quat}; impl From for Rotation2 { #[inline] diff --git a/src/third_party/glam/glam_similarity.rs b/src/third_party/glam/common/glam_similarity.rs similarity index 93% rename from src/third_party/glam/glam_similarity.rs rename to src/third_party/glam/common/glam_similarity.rs index 92107074..12295502 100644 --- a/src/third_party/glam/glam_similarity.rs +++ b/src/third_party/glam/common/glam_similarity.rs @@ -1,5 +1,5 @@ +use super::glam::{DMat3, DMat4, Mat3, Mat4}; use crate::{Similarity2, Similarity3}; -use glam::{DMat3, DMat4, Mat3, Mat4}; impl From> for Mat3 { fn from(iso: Similarity2) -> Mat3 { @@ -25,8 +25,8 @@ impl From> for DMat4 { #[cfg(feature = "convert-glam-unchecked")] mod unchecked { + use super::super::glam::{DMat3, DMat4, Mat3, Mat4}; use crate::{Matrix3, Matrix4, Similarity2, Similarity3}; - use glam::{DMat3, DMat4, Mat3, Mat4}; impl From for Similarity2 { fn from(mat3: Mat3) -> Similarity2 { diff --git a/src/third_party/glam/glam_translation.rs b/src/third_party/glam/common/glam_translation.rs similarity index 96% rename from src/third_party/glam/glam_translation.rs rename to src/third_party/glam/common/glam_translation.rs index f92d3275..6dbbf602 100644 --- a/src/third_party/glam/glam_translation.rs +++ b/src/third_party/glam/common/glam_translation.rs @@ -1,5 +1,5 @@ +use super::glam::{DVec2, DVec3, DVec4, Vec2, Vec3, Vec3A, Vec4}; use crate::{Translation2, Translation3, Translation4}; -use glam::{DVec2, DVec3, DVec4, Vec2, Vec3, Vec3A, Vec4}; macro_rules! impl_translation_conversion( ($N: ty, $Vec2: ty, $Vec3: ty, $Vec4: ty) => { diff --git a/src/third_party/glam/glam_unit_complex.rs b/src/third_party/glam/common/glam_unit_complex.rs similarity index 91% rename from src/third_party/glam/glam_unit_complex.rs rename to src/third_party/glam/common/glam_unit_complex.rs index c5d9cc6a..ac5e405c 100644 --- a/src/third_party/glam/glam_unit_complex.rs +++ b/src/third_party/glam/common/glam_unit_complex.rs @@ -1,5 +1,5 @@ +use super::glam::{DMat2, Mat2}; use crate::UnitComplex; -use glam::{DMat2, Mat2}; impl From> for Mat2 { #[inline] @@ -17,8 +17,8 @@ impl From> for DMat2 { #[cfg(feature = "convert-glam-unchecked")] mod unchecked { + use super::super::glam::{DMat2, Mat2}; use crate::{Rotation2, UnitComplex}; - use glam::{DMat2, Mat2}; impl From for UnitComplex { #[inline] diff --git a/src/third_party/glam/mod.rs b/src/third_party/glam/mod.rs index 20925923..a09e37ca 100644 --- a/src/third_party/glam/mod.rs +++ b/src/third_party/glam/mod.rs @@ -1,8 +1,6 @@ -mod glam_isometry; -mod glam_matrix; -mod glam_point; -mod glam_quaternion; -mod glam_rotation; -mod glam_similarity; -mod glam_translation; -mod glam_unit_complex; +#[cfg(feature = "glam013")] +mod v013; +#[cfg(feature = "glam014")] +mod v014; +#[cfg(feature = "glam015")] +mod v015; diff --git a/src/third_party/glam/v013/mod.rs b/src/third_party/glam/v013/mod.rs new file mode 100644 index 00000000..4787fb21 --- /dev/null +++ b/src/third_party/glam/v013/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam013 as glam; diff --git a/src/third_party/glam/v014/mod.rs b/src/third_party/glam/v014/mod.rs new file mode 100644 index 00000000..3f9b8286 --- /dev/null +++ b/src/third_party/glam/v014/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam014 as glam; diff --git a/src/third_party/glam/v015/mod.rs b/src/third_party/glam/v015/mod.rs new file mode 100644 index 00000000..83b79848 --- /dev/null +++ b/src/third_party/glam/v015/mod.rs @@ -0,0 +1,18 @@ +#[path = "../common/glam_isometry.rs"] +mod glam_isometry; +#[path = "../common/glam_matrix.rs"] +mod glam_matrix; +#[path = "../common/glam_point.rs"] +mod glam_point; +#[path = "../common/glam_quaternion.rs"] +mod glam_quaternion; +#[path = "../common/glam_rotation.rs"] +mod glam_rotation; +#[path = "../common/glam_similarity.rs"] +mod glam_similarity; +#[path = "../common/glam_translation.rs"] +mod glam_translation; +#[path = "../common/glam_unit_complex.rs"] +mod glam_unit_complex; + +pub(self) use glam015 as glam; diff --git a/src/third_party/mod.rs b/src/third_party/mod.rs index ce0fcaad..218c6879 100644 --- a/src/third_party/mod.rs +++ b/src/third_party/mod.rs @@ -1,6 +1,5 @@ #[cfg(feature = "alga")] mod alga; -#[cfg(feature = "glam")] mod glam; #[cfg(feature = "mint")] mod mint; From 47a4f52e8d07903eecfeb11b2d6dd0ccf8de58ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Tue, 1 Jun 2021 10:48:24 +0200 Subject: [PATCH 56/57] Replace unchecked glam conversion by TryFrom or checks --- Cargo.toml | 3 - src/third_party/glam/common/glam_isometry.rs | 281 +++++++++--------- .../glam/common/glam_quaternion.rs | 28 +- src/third_party/glam/common/glam_rotation.rs | 58 ++-- .../glam/common/glam_similarity.rs | 55 ++-- .../glam/common/glam_unit_complex.rs | 30 +- 6 files changed, 218 insertions(+), 237 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f879ae1f..012b9c80 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -38,11 +38,8 @@ macros = [ "nalgebra-macros" ] convert-mint = [ "mint" ] convert-bytemuck = [ "bytemuck" ] convert-glam013 = [ "glam013" ] -convert-glam013-unchecked = [ "convert-glam013" ] # Enable edgy conversions like Mat4 -> Isometry3 convert-glam014 = [ "glam014" ] -convert-glam014-unchecked = [ "convert-glam014" ] # Enable edgy conversions like Mat4 -> Isometry3 convert-glam015 = [ "glam015" ] -convert-glam015-unchecked = [ "convert-glam015" ] # Enable edgy conversions like Mat4 -> Isometry3 # Serialization ## To use serde in a #[no-std] environment, enable the diff --git a/src/third_party/glam/common/glam_isometry.rs b/src/third_party/glam/common/glam_isometry.rs index 3d2cbaba..6bd970d2 100644 --- a/src/third_party/glam/common/glam_isometry.rs +++ b/src/third_party/glam/common/glam_isometry.rs @@ -1,5 +1,6 @@ -use super::glam::{DMat3, DMat4, DQuat, DVec3, Mat3, Mat4, Quat, Vec3}; -use crate::{Isometry2, Isometry3}; +use super::glam::{DMat3, DMat4, DQuat, DVec2, DVec3, Mat3, Mat4, Quat, Vec2, Vec3}; +use crate::{Isometry2, Isometry3, Matrix3, Matrix4}; +use std::convert::TryFrom; impl From> for Mat3 { fn from(iso: Isometry2) -> Mat3 { @@ -38,7 +39,7 @@ impl From> for (DVec3, DQuat) { impl From> for (Vec3, Quat) { fn from(iso: Isometry2) -> (Vec3, Quat) { let tra = Vec3::new(iso.translation.x, iso.translation.y, 0.0); - let rot = Quat::from_axis_angle(Vec3::new(0.0, 0.0, 1.0), iso.rotation.angle()); + let rot = Quat::from_axis_angle(Vec3::Z, iso.rotation.angle()); (tra, rot) } } @@ -46,145 +47,147 @@ impl From> for (Vec3, Quat) { impl From> for (DVec3, DQuat) { fn from(iso: Isometry2) -> (DVec3, DQuat) { let tra = DVec3::new(iso.translation.x, iso.translation.y, 0.0); - let rot = DQuat::from_axis_angle(DVec3::new(0.0, 0.0, 1.0), iso.rotation.angle()); + let rot = DQuat::from_axis_angle(DVec3::Z, iso.rotation.angle()); (tra, rot) } } -#[cfg(feature = "convert-glam-unchecked")] -mod unchecked { - use super::super::glam::{DMat3, DMat4, DQuat, DVec2, DVec3, Mat3, Mat4, Quat, Vec2, Vec3}; - use crate::{Isometry2, Isometry3, Matrix3, Matrix4}; - - impl From<(Vec3, Quat)> for Isometry3 { - fn from((tra, rot): (Vec3, Quat)) -> Self { - Isometry3::from_parts(tra.into(), rot.into()) - } - } - - impl From<(DVec3, DQuat)> for Isometry3 { - fn from((tra, rot): (DVec3, DQuat)) -> Self { - Isometry3::from_parts(tra.into(), rot.into()) - } - } - - impl From<(Vec3, Quat)> for Isometry2 { - fn from((tra, rot): (Vec3, Quat)) -> Self { - Isometry2::new([tra.x, tra.y].into(), rot.to_axis_angle().1) - } - } - - impl From<(DVec3, DQuat)> for Isometry2 { - fn from((tra, rot): (DVec3, DQuat)) -> Self { - Isometry2::new([tra.x, tra.y].into(), rot.to_axis_angle().1) - } - } - - impl From<(Vec2, Quat)> for Isometry2 { - fn from((tra, rot): (Vec2, Quat)) -> Self { - Isometry2::new([tra.x, tra.y].into(), rot.to_axis_angle().1) - } - } - - impl From<(DVec2, DQuat)> for Isometry2 { - fn from((tra, rot): (DVec2, DQuat)) -> Self { - Isometry2::new([tra.x, tra.y].into(), rot.to_axis_angle().1) - } - } - - impl From<(Vec2, f32)> for Isometry2 { - fn from((tra, rot): (Vec2, f32)) -> Self { - Isometry2::new([tra.x, tra.y].into(), rot) - } - } - - impl From<(DVec2, f64)> for Isometry2 { - fn from((tra, rot): (DVec2, f64)) -> Self { - Isometry2::new([tra.x, tra.y].into(), rot) - } - } - - impl From for Isometry3 { - fn from(rot: Quat) -> Self { - Isometry3::from_parts(crate::one(), rot.into()) - } - } - - impl From for Isometry3 { - fn from(rot: DQuat) -> Self { - Isometry3::from_parts(crate::one(), rot.into()) - } - } - - impl From for Isometry2 { - fn from(rot: Quat) -> Self { - Isometry2::new(crate::zero(), rot.to_axis_angle().1) - } - } - - impl From for Isometry2 { - fn from(rot: DQuat) -> Self { - Isometry2::new(crate::zero(), rot.to_axis_angle().1) - } - } - - impl From for Isometry3 { - fn from(tra: Vec3) -> Self { - Isometry3::from_parts(tra.into(), crate::one()) - } - } - - impl From for Isometry3 { - fn from(tra: DVec3) -> Self { - Isometry3::from_parts(tra.into(), crate::one()) - } - } - - impl From for Isometry2 { - fn from(tra: Vec2) -> Self { - Isometry2::new(tra.into(), crate::one()) - } - } - - impl From for Isometry2 { - fn from(tra: DVec2) -> Self { - Isometry2::new(tra.into(), crate::one()) - } - } - - impl From for Isometry2 { - fn from(tra: Vec3) -> Self { - Isometry2::new([tra.x, tra.y].into(), crate::one()) - } - } - - impl From for Isometry2 { - fn from(tra: DVec3) -> Self { - Isometry2::new([tra.x, tra.y].into(), crate::one()) - } - } - - impl From for Isometry2 { - fn from(mat3: Mat3) -> Isometry2 { - crate::convert_unchecked(Matrix3::from(mat3)) - } - } - - impl From for Isometry3 { - fn from(mat4: Mat4) -> Isometry3 { - crate::convert_unchecked(Matrix4::from(mat4)) - } - } - - impl From for Isometry2 { - fn from(mat3: DMat3) -> Isometry2 { - crate::convert_unchecked(Matrix3::from(mat3)) - } - } - - impl From for Isometry3 { - fn from(mat4: DMat4) -> Isometry3 { - crate::convert_unchecked(Matrix4::from(mat4)) - } +impl From<(Vec3, Quat)> for Isometry3 { + fn from((tra, rot): (Vec3, Quat)) -> Self { + Isometry3::from_parts(tra.into(), rot.into()) + } +} + +impl From<(DVec3, DQuat)> for Isometry3 { + fn from((tra, rot): (DVec3, DQuat)) -> Self { + Isometry3::from_parts(tra.into(), rot.into()) + } +} + +impl From<(Vec3, Quat)> for Isometry2 { + fn from((tra, rot): (Vec3, Quat)) -> Self { + Isometry2::new([tra.x, tra.y].into(), rot.to_axis_angle().1) + } +} + +impl From<(DVec3, DQuat)> for Isometry2 { + fn from((tra, rot): (DVec3, DQuat)) -> Self { + Isometry2::new([tra.x, tra.y].into(), rot.to_axis_angle().1) + } +} + +impl From<(Vec2, Quat)> for Isometry2 { + fn from((tra, rot): (Vec2, Quat)) -> Self { + Isometry2::new(tra.into(), rot.to_axis_angle().1) + } +} + +impl From<(DVec2, DQuat)> for Isometry2 { + fn from((tra, rot): (DVec2, DQuat)) -> Self { + Isometry2::new(tra.into(), rot.to_axis_angle().1) + } +} + +impl From<(Vec2, f32)> for Isometry2 { + fn from((tra, rot): (Vec2, f32)) -> Self { + Isometry2::new(tra.into(), rot) + } +} + +impl From<(DVec2, f64)> for Isometry2 { + fn from((tra, rot): (DVec2, f64)) -> Self { + Isometry2::new(tra.into(), rot) + } +} + +impl From for Isometry3 { + fn from(rot: Quat) -> Self { + Isometry3::from_parts(crate::one(), rot.into()) + } +} + +impl From for Isometry3 { + fn from(rot: DQuat) -> Self { + Isometry3::from_parts(crate::one(), rot.into()) + } +} + +impl From for Isometry2 { + fn from(rot: Quat) -> Self { + Isometry2::new(crate::zero(), rot.to_axis_angle().1) + } +} + +impl From for Isometry2 { + fn from(rot: DQuat) -> Self { + Isometry2::new(crate::zero(), rot.to_axis_angle().1) + } +} + +impl From for Isometry3 { + fn from(tra: Vec3) -> Self { + Isometry3::from_parts(tra.into(), crate::one()) + } +} + +impl From for Isometry3 { + fn from(tra: DVec3) -> Self { + Isometry3::from_parts(tra.into(), crate::one()) + } +} + +impl From for Isometry2 { + fn from(tra: Vec2) -> Self { + Isometry2::new(tra.into(), crate::one()) + } +} + +impl From for Isometry2 { + fn from(tra: DVec2) -> Self { + Isometry2::new(tra.into(), crate::one()) + } +} + +impl From for Isometry2 { + fn from(tra: Vec3) -> Self { + Isometry2::new([tra.x, tra.y].into(), crate::one()) + } +} + +impl From for Isometry2 { + fn from(tra: DVec3) -> Self { + Isometry2::new([tra.x, tra.y].into(), crate::one()) + } +} + +impl TryFrom for Isometry2 { + type Error = (); + + fn try_from(mat3: Mat3) -> Result, Self::Error> { + crate::try_convert(Matrix3::from(mat3)).ok_or(()) + } +} + +impl TryFrom for Isometry3 { + type Error = (); + + fn try_from(mat4: Mat4) -> Result, Self::Error> { + crate::try_convert(Matrix4::from(mat4)).ok_or(()) + } +} + +impl TryFrom for Isometry2 { + type Error = (); + + fn try_from(mat3: DMat3) -> Result, Self::Error> { + crate::try_convert(Matrix3::from(mat3)).ok_or(()) + } +} + +impl TryFrom for Isometry3 { + type Error = (); + + fn try_from(mat4: DMat4) -> Result, Self::Error> { + crate::try_convert(Matrix4::from(mat4)).ok_or(()) } } diff --git a/src/third_party/glam/common/glam_quaternion.rs b/src/third_party/glam/common/glam_quaternion.rs index a622bab7..e0432ead 100644 --- a/src/third_party/glam/common/glam_quaternion.rs +++ b/src/third_party/glam/common/glam_quaternion.rs @@ -43,22 +43,16 @@ impl From> for DQuat { } } -#[cfg(feature = "convert-glam-unchecked")] -mod unchecked { - use super::super::glam::{DQuat, Quat}; - use crate::{Quaternion, UnitQuaternion}; - - impl From for UnitQuaternion { - #[inline] - fn from(e: Quat) -> UnitQuaternion { - UnitQuaternion::new_unchecked(Quaternion::from(e)) - } - } - - impl From for UnitQuaternion { - #[inline] - fn from(e: DQuat) -> UnitQuaternion { - UnitQuaternion::new_unchecked(Quaternion::from(e)) - } +impl From for UnitQuaternion { + #[inline] + fn from(e: Quat) -> UnitQuaternion { + UnitQuaternion::new_normalize(Quaternion::from(e)) + } +} + +impl From for UnitQuaternion { + #[inline] + fn from(e: DQuat) -> UnitQuaternion { + UnitQuaternion::new_normalize(Quaternion::from(e)) } } diff --git a/src/third_party/glam/common/glam_rotation.rs b/src/third_party/glam/common/glam_rotation.rs index 6ae8d809..1e1fe8e1 100644 --- a/src/third_party/glam/common/glam_rotation.rs +++ b/src/third_party/glam/common/glam_rotation.rs @@ -1,5 +1,5 @@ use super::glam::{DMat2, DQuat, Mat2, Quat}; -use crate::{Rotation2, Rotation3, UnitQuaternion}; +use crate::{Rotation2, Rotation3, UnitComplex, UnitQuaternion}; impl From> for Mat2 { #[inline] @@ -29,36 +29,30 @@ impl From> for DQuat { } } -#[cfg(feature = "convert-glam-unchecked")] -mod unchecked { - use super::super::glam::{DMat2, DQuat, Mat2, Quat}; - use crate::{Rotation2, Rotation3, UnitQuaternion}; - - impl From for Rotation2 { - #[inline] - fn from(e: Mat2) -> Rotation2 { - Rotation2::from_matrix_unchecked(e.into()) - } - } - - impl From for Rotation2 { - #[inline] - fn from(e: DMat2) -> Rotation2 { - Rotation2::from_matrix_unchecked(e.into()) - } - } - - impl From for Rotation3 { - #[inline] - fn from(e: Quat) -> Rotation3 { - Rotation3::from(UnitQuaternion::from(e)) - } - } - - impl From for Rotation3 { - #[inline] - fn from(e: DQuat) -> Rotation3 { - Rotation3::from(UnitQuaternion::from(e)) - } +impl From for Rotation2 { + #[inline] + fn from(e: Mat2) -> Rotation2 { + UnitComplex::from(e).to_rotation_matrix() + } +} + +impl From for Rotation2 { + #[inline] + fn from(e: DMat2) -> Rotation2 { + UnitComplex::from(e).to_rotation_matrix() + } +} + +impl From for Rotation3 { + #[inline] + fn from(e: Quat) -> Rotation3 { + Rotation3::from(UnitQuaternion::from(e)) + } +} + +impl From for Rotation3 { + #[inline] + fn from(e: DQuat) -> Rotation3 { + Rotation3::from(UnitQuaternion::from(e)) } } diff --git a/src/third_party/glam/common/glam_similarity.rs b/src/third_party/glam/common/glam_similarity.rs index 12295502..f6679f08 100644 --- a/src/third_party/glam/common/glam_similarity.rs +++ b/src/third_party/glam/common/glam_similarity.rs @@ -1,5 +1,6 @@ use super::glam::{DMat3, DMat4, Mat3, Mat4}; -use crate::{Similarity2, Similarity3}; +use crate::{Matrix3, Matrix4, Similarity2, Similarity3}; +use std::convert::TryFrom; impl From> for Mat3 { fn from(iso: Similarity2) -> Mat3 { @@ -23,32 +24,30 @@ impl From> for DMat4 { } } -#[cfg(feature = "convert-glam-unchecked")] -mod unchecked { - use super::super::glam::{DMat3, DMat4, Mat3, Mat4}; - use crate::{Matrix3, Matrix4, Similarity2, Similarity3}; - - impl From for Similarity2 { - fn from(mat3: Mat3) -> Similarity2 { - crate::convert_unchecked(Matrix3::from(mat3)) - } - } - - impl From for Similarity3 { - fn from(mat4: Mat4) -> Similarity3 { - crate::convert_unchecked(Matrix4::from(mat4)) - } - } - - impl From for Similarity2 { - fn from(mat3: DMat3) -> Similarity2 { - crate::convert_unchecked(Matrix3::from(mat3)) - } - } - - impl From for Similarity3 { - fn from(mat4: DMat4) -> Similarity3 { - crate::convert_unchecked(Matrix4::from(mat4)) - } +impl TryFrom for Similarity2 { + type Error = (); + fn try_from(mat3: Mat3) -> Result, ()> { + crate::try_convert(Matrix3::from(mat3)).ok_or(()) + } +} + +impl TryFrom for Similarity3 { + type Error = (); + fn try_from(mat4: Mat4) -> Result, ()> { + crate::try_convert(Matrix4::from(mat4)).ok_or(()) + } +} + +impl TryFrom for Similarity2 { + type Error = (); + fn try_from(mat3: DMat3) -> Result, ()> { + crate::try_convert(Matrix3::from(mat3)).ok_or(()) + } +} + +impl TryFrom for Similarity3 { + type Error = (); + fn try_from(mat4: DMat4) -> Result, ()> { + crate::try_convert(Matrix4::from(mat4)).ok_or(()) } } diff --git a/src/third_party/glam/common/glam_unit_complex.rs b/src/third_party/glam/common/glam_unit_complex.rs index ac5e405c..67b6a040 100644 --- a/src/third_party/glam/common/glam_unit_complex.rs +++ b/src/third_party/glam/common/glam_unit_complex.rs @@ -1,5 +1,5 @@ use super::glam::{DMat2, Mat2}; -use crate::UnitComplex; +use crate::{Complex, Rotation2, UnitComplex}; impl From> for Mat2 { #[inline] @@ -15,22 +15,16 @@ impl From> for DMat2 { } } -#[cfg(feature = "convert-glam-unchecked")] -mod unchecked { - use super::super::glam::{DMat2, Mat2}; - use crate::{Rotation2, UnitComplex}; - - impl From for UnitComplex { - #[inline] - fn from(e: Mat2) -> UnitComplex { - Rotation2::from_matrix_unchecked(e.into()).into() - } - } - - impl From for UnitComplex { - #[inline] - fn from(e: DMat2) -> UnitComplex { - Rotation2::from_matrix_unchecked(e.into()).into() - } +impl From for UnitComplex { + #[inline] + fn from(e: Mat2) -> UnitComplex { + UnitComplex::new_normalize(Complex::new(e.x_axis.x, e.x_axis.y)) + } +} + +impl From for UnitComplex { + #[inline] + fn from(e: DMat2) -> UnitComplex { + UnitComplex::new_normalize(Complex::new(e.x_axis.x, e.x_axis.y)) } } From dfc8ad3d6ac7af455ef59a69eb5baa9a8e15f2a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Crozet=20S=C3=A9bastien?= Date: Wed, 2 Jun 2021 14:53:43 +0200 Subject: [PATCH 57/57] Release v0.27.0 --- CHANGELOG.md | 16 ++++++++++++++++ Cargo.toml | 10 +++++----- examples/cargo/Cargo.toml | 2 +- nalgebra-glm/Cargo.toml | 8 ++++---- nalgebra-lapack/Cargo.toml | 16 ++++++++-------- nalgebra-macros/Cargo.toml | 2 +- nalgebra-sparse/Cargo.toml | 6 +++--- src/third_party/glam/common/glam_unit_complex.rs | 2 +- 8 files changed, 39 insertions(+), 23 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 450ec596..2783416b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,22 @@ documented here. This project adheres to [Semantic Versioning](https://semver.org/). +## [0.27.0] +This removes the `convert-glam` and `convert-glam-unchecked` optional features. +Instead, this adds the `convert-glam013`, `convert-glam014`, and `convert-glam015` optional features for +conversions targeting the versions 0.13, 0.14, and 0.15 of `glam`. + +### Added +- Add macros `matrix!`, `dmatrix!`, `vector!`, `dvector!`, `point!` for constructing matrices/vectors/points in a + more convenient way. See [#886](https://github.com/dimforge/nalgebra/pull/886) and [#899](https://github.com/dimforge/nalgebra/pull/899). +- Add `CooMatrix::reserve` to `nalgebra-sparse`. +- Add basic support for serialization using `rkyv`. Can be enabled with the features `rkyv-serialize` or + `rkyv-serialize-no-std`. + + +### Fixed +- Fixed a potential unsoundness issue after deserializing an invalid `DVector` using `serde`. + ## [0.26.2] ### Added - Conversion from an array `[T; D]` to an isometry `Isometry` (as a translation). diff --git a/Cargo.toml b/Cargo.toml index 012b9c80..5c2ad286 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra" -version = "0.26.2" +version = "0.27.0" authors = [ "Sébastien Crozet " ] description = "General-purpose linear algebra library with transformations and statically-sized or dynamically-sized matrices." @@ -68,10 +68,10 @@ nalgebra-macros = { version = "0.1", path = "nalgebra-macros", optional = true } typenum = "1.12" rand-package = { package = "rand", version = "0.8", optional = true, default-features = false } num-traits = { version = "0.2", default-features = false } -num-complex = { version = "0.3", default-features = false } -num-rational = { version = "0.3", default-features = false } -approx = { version = "0.4", default-features = false } -simba = { version = "0.4", default-features = false } +num-complex = { version = "0.4", default-features = false } +num-rational = { version = "0.4", default-features = false } +approx = { version = "0.5", default-features = false } +simba = { version = "0.5", default-features = false } 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 } diff --git a/examples/cargo/Cargo.toml b/examples/cargo/Cargo.toml index 10bcf375..e0dd983c 100644 --- a/examples/cargo/Cargo.toml +++ b/examples/cargo/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" authors = [ "You" ] [dependencies] -nalgebra = "0.26.0" +nalgebra = "0.27.0" [[bin]] name = "example" diff --git a/nalgebra-glm/Cargo.toml b/nalgebra-glm/Cargo.toml index 0d8b5bd8..f97536d0 100644 --- a/nalgebra-glm/Cargo.toml +++ b/nalgebra-glm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-glm" -version = "0.12.0" +version = "0.13.0" authors = ["sebcrozet "] description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library." @@ -25,6 +25,6 @@ abomonation-serialize = [ "nalgebra/abomonation-serialize" ] [dependencies] num-traits = { version = "0.2", default-features = false } -approx = { version = "0.4", default-features = false } -simba = { version = "0.4", default-features = false } -nalgebra = { path = "..", version = "0.26", default-features = false } +approx = { version = "0.5", default-features = false } +simba = { version = "0.5", default-features = false } +nalgebra = { path = "..", version = "0.27", default-features = false } diff --git a/nalgebra-lapack/Cargo.toml b/nalgebra-lapack/Cargo.toml index 45a469ac..c368a3c6 100644 --- a/nalgebra-lapack/Cargo.toml +++ b/nalgebra-lapack/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-lapack" -version = "0.17.0" +version = "0.18.0" authors = [ "Sébastien Crozet ", "Andrew Straw " ] description = "Matrix decompositions using nalgebra matrices and Lapack bindings." @@ -29,18 +29,18 @@ accelerate = ["lapack-src/accelerate"] intel-mkl = ["lapack-src/intel-mkl"] [dependencies] -nalgebra = { version = "0.26", path = ".." } +nalgebra = { version = "0.27", path = ".." } num-traits = "0.2" -num-complex = { version = "0.3", default-features = false } -simba = "0.4" +num-complex = { version = "0.4", default-features = false } +simba = "0.5" serde = { version = "1.0", features = [ "derive" ], optional = true } -lapack = { version = "0.17", default-features = false } -lapack-src = { version = "0.6", default-features = false } +lapack = { version = "0.19", default-features = false } +lapack-src = { version = "0.8", default-features = false } # clippy = "*" [dev-dependencies] -nalgebra = { version = "0.26", features = [ "arbitrary", "rand" ], path = ".." } +nalgebra = { version = "0.27", features = [ "arbitrary", "rand" ], path = ".." } proptest = { version = "1", default-features = false, features = ["std"] } quickcheck = "1" -approx = "0.4" +approx = "0.5" rand = "0.8" diff --git a/nalgebra-macros/Cargo.toml b/nalgebra-macros/Cargo.toml index d95784e0..59eb5ba1 100644 --- a/nalgebra-macros/Cargo.toml +++ b/nalgebra-macros/Cargo.toml @@ -21,5 +21,5 @@ quote = "1.0" proc-macro2 = "1.0" [dev-dependencies] -nalgebra = { version = "0.26.1", path = ".." } +nalgebra = { version = "0.27.0", path = ".." } trybuild = "1.0.42" diff --git a/nalgebra-sparse/Cargo.toml b/nalgebra-sparse/Cargo.toml index 6666bfb9..4af053c2 100644 --- a/nalgebra-sparse/Cargo.toml +++ b/nalgebra-sparse/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-sparse" -version = "0.2.0" +version = "0.3.0" authors = [ "Andreas Longva", "Sébastien Crozet " ] edition = "2018" description = "Sparse matrix computation based on nalgebra." @@ -20,7 +20,7 @@ compare = [ "matrixcompare-core" ] slow-tests = [] [dependencies] -nalgebra = { version="0.26", path = "../" } +nalgebra = { version="0.27", path = "../" } num-traits = { version = "0.2", default-features = false } proptest = { version = "1.0", optional = true } matrixcompare-core = { version = "0.1.0", optional = true } @@ -28,7 +28,7 @@ matrixcompare-core = { version = "0.1.0", optional = true } [dev-dependencies] itertools = "0.10" matrixcompare = { version = "0.3.0", features = [ "proptest-support" ] } -nalgebra = { version="0.26", path = "../", features = ["compare"] } +nalgebra = { version="0.27", path = "../", features = ["compare"] } [package.metadata.docs.rs] # Enable certain features when building docs for docs.rs diff --git a/src/third_party/glam/common/glam_unit_complex.rs b/src/third_party/glam/common/glam_unit_complex.rs index 67b6a040..7ee6fc65 100644 --- a/src/third_party/glam/common/glam_unit_complex.rs +++ b/src/third_party/glam/common/glam_unit_complex.rs @@ -1,5 +1,5 @@ use super::glam::{DMat2, Mat2}; -use crate::{Complex, Rotation2, UnitComplex}; +use crate::{Complex, UnitComplex}; impl From> for Mat2 { #[inline]