diff --git a/CHANGELOG.md b/CHANGELOG.md index 78d5c374..04ea1c34 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,26 @@ documented here. This project adheres to [Semantic Versioning](https://semver.org/). +## [0.28.0] +### Added +- Implement `Hash` for `Transform`. +- Implement `Borrow` and `BorrowMut` for contiguous slices. + +### Modified +- The `OPoint` type has been added. It takes the dimension number as a type-level integer (e.g. `Const<3>`) instead + of a const-generic. The type `Point` is now an alias for `OPoint`. This changes doesn't affect any + of the existing code using `Point`. However, it will allow the use `OPoint` in a generic context where the dimension + cannot be easily expressed as a const-generic (because of the current limitation of const-generics in Rust). +- Several clippy warnings were fixed. This results in some method signature changes (e.g. taking `self` instead of `&self`) + but this should not have any practical infulances on existing codebase. +- The `Point::new` constructors are no longer const-fn. This is due to some limitations in const-fn + not allowing custom trait-bounds. Use the `point!` macro instead to build points in const environments. +- `Dynamic::new` and `Unit::new_unchecked` are now const-fn. +- Methods returning `Result<(), ()>` now return `bool` instead. + +### Fixed +- Fixed a potential unsoundess issue when converting a mutable slice to a `&mut[T]`. + ## [0.27.1] ### Fixed - Fixed a bug in the conversion from `glam::Vec2` or `glam::DVec2` to `Isometry2`. @@ -38,7 +58,7 @@ conversions targeting the versions 0.13, 0.14, and 0.15 of `glam`. 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 +This release integrates `min-const-generics` to nalgebra. See [our blog post](https://www.dimforge.com/blog/2021/04/12/integrating-const-generics-to-nalgebra) for details about this release. @@ -78,7 +98,7 @@ for details about this release. ## [0.25.3] ### Added -- The `Vector::simd_cap_magnitude` method to cap the magnitude of the a vector with +- The `Vector::simd_cap_magnitude` method to cap the magnitude of the vector with SIMD components. ## [0.25.2] @@ -109,7 +129,7 @@ This updates all the dependencies of nalgebra to their latest version, including ### New crate: nalgebra-sparse Alongside this release of `nalgebra`, we are releasing `nalgebra-sparse`: a crate dedicated to sparse matrix -computation with `nalgebra`. The `sparse` module of `nalgebra`itself still exists for backward compatibility +computation with `nalgebra`. The `sparse` module of `nalgebra`itself still exists for backward compatibility, but it will be deprecated soon in favor of the `nalgebra-sparse` crate. ### Added @@ -125,12 +145,12 @@ but it will be deprecated soon in favor of the `nalgebra-sparse` crate. ## [0.24.0] ### Added -* The `DualQuaternion` type. It is still work-in-progress but the basics are here: +* The `DualQuaternion` type. It is still work-in-progress, but the basics are here: creation from its real and dual part, multiplication of two dual quaternions, and normalization. ### Removed -* There is no blanket `impl PartialEq for Unit` any more. Instead, it is +* There is no blanket `impl PartialEq for Unit` anymore. Instead, it is implemented specifically for `UnitComplex`, `UnitQuaternion` and `Unit`. ## [0.23.2] @@ -157,7 +177,7 @@ In this release we improved the documentation of the matrix and vector types by: and `Vector.apply(f)`. * The `Quaternion::from([N; 4])` conversion to build a quaternion from an array of four elements. * The `Isometry::from(Translation)` conversion to build an isometry from a translation. - * The `Vector::ith_axis(i)` which build a unit vector, e.g., `Unit>` with its i-th component set to 1.0 and the + * The `Vector::ith_axis(i)` which build a unit vector, e.g., `Unit>` with its i-th component set to 1.0, and the others set to zero. * The `Isometry.lerp_slerp` and `Isometry.try_lerp_slerp` methods to interpolate between two isometries using linear interpolation for the translational part, and spherical interpolation for the rotational part. @@ -166,7 +186,7 @@ In this release we improved the documentation of the matrix and vector types by: ## [0.22.0] In this release, we are using the new version 0.2 of simba. One major change of that version is that the -use of `libm` is now opt-in when building targetting `no-std` environment. If you are using floating-point +use of `libm` is now opt-in when building targeting `no-std` environment. If you are using floating-point operations with nalgebra in a `no-std` environment, you will need to enable the new `libm` feature of nalgebra for your code to compile again. @@ -174,7 +194,7 @@ of nalgebra for your code to compile again. * The `libm` feature that enables `libm` when building for `no-std` environment. * The `libm-force` feature that enables `libm` even when building for a not `no-std` environment. * `Cholesky::new_unchecked` which build a Cholesky decomposition without checking that its input is - positive-definite. It can be use with SIMD types. + positive-definite. It can be used with SIMD types. * The `Default` trait is now implemented for matrices, and quaternions. They are all filled with zeros, except for `UnitQuaternion` which is initialized with the identity. * Matrix exponential `matrix.exp()`. @@ -345,7 +365,7 @@ library (i.e. it supports `#![no_std]`). See the corresponding [documentation](h * Add methods `.rotation_between_axis(...)` and `.scaled_rotation_between_axis(...)` to `UnitComplex` to compute the rotation matrix between two 2D **unit** vectors. * Add methods `.axis_angle()` to `UnitComplex` and `UnitQuaternion` in order to retrieve both the - unit rotation axis and the rotation angle simultaneously. + unit rotation axis, and the rotation angle simultaneously. * Add functions to construct a random matrix with a user-defined distribution: `::from_distribution(...)`. ## [0.14.0] @@ -366,7 +386,7 @@ library (i.e. it supports `#![no_std]`). See the corresponding [documentation](h the matrix `M` such that for all vector `v` we have `M * v == self.cross(&v)`. * `.iamin()` that returns the index of the vector entry with - smallest absolute value. + the smallest absolute value. * The `mint` feature that can be enabled in order to allow conversions from and to types of the [mint](https://crates.io/crates/mint) crate. * Aliases for matrix and vector slices. Their are named by adding `Slice` @@ -404,7 +424,7 @@ This adds support for serialization using the * The alias `MatrixNM` is now deprecated. Use `MatrixMN` instead (we reordered M and N to be in alphabetical order). * In-place componentwise multiplication and division - `.component_mul_mut(...)` and `.component_div_mut(...)` have bee deprecated + `.component_mul_mut(...)` and `.component_div_mut(...)` have been deprecated for a future renaming. Use `.component_mul_assign(...)` and `.component_div_assign(...)` instead. @@ -506,7 +526,7 @@ This version is a major rewrite of the library. Major changes are: All other mathematical traits, except `Axpy` have been removed from **nalgebra**. * Methods are now preferred to free functions because they do not require any - trait to be used any more. + trait to be used anymore. * Most algebraic entities can be parametrized by type-level integers to specify their dimensions. Using `Dynamic` instead of a type-level integer indicates that the dimension known at run-time only. @@ -582,7 +602,7 @@ only: * The free functions `::prepend_rotation`, `::append_rotation`, `::append_rotation_wrt_center`, `::append_rotation_wrt_point`, `::append_transformation`, and `::append_translation ` have been removed. - Instead create the rotation or translation object explicitly and use + Instead, create the rotation or translation object explicitly and use multiplication to compose it with anything else. * The free function `::outer` has been removed. Use column-vector × @@ -608,7 +628,7 @@ Binary operations are now allowed between references as well. For example ### Modified Removed unused parameters to methods from the `ApproxEq` trait. Those were -required before rust 1.0 to help type inference. The are not needed any more +required before rust 1.0 to help type inference. They are not needed any more since it now allowed to write for a type `T` that implements `ApproxEq`: `::approx_epsilon()`. This replaces the old form: `ApproxEq::approx_epsilon(None::)`. @@ -627,7 +647,7 @@ since it now allowed to write for a type `T` that implements `ApproxEq`: `UnitQuaternion::from_axisangle`. The new `::new` method now requires a not-normalized quaternion. -Methods names starting with `new_with_` now start with `from_`. This is more +Method names starting with `new_with_` now start with `from_`. This is more idiomatic in Rust. The `Norm` trait now uses an associated type instead of a type parameter. @@ -658,8 +678,8 @@ crate for vectors, rotations and points. To enable them, activate the ## [0.8.0] ### Modified - * Almost everything (types, methods, and traits) now use full names instead - of abbreviations (e.g. `Vec3` becomes `Vector3`). Most changes are abvious. + * Almost everything (types, methods, and traits) now use fulls names instead + of abbreviations (e.g. `Vec3` becomes `Vector3`). Most changes are obvious. Note however that: - `::sqnorm` becomes `::norm_squared`. - `::sqdist` becomes `::distance_squared`. @@ -693,11 +713,11 @@ you [there](https://users.nphysics.org)! ### Removed * Removed zero-sized elements `Vector0`, `Point0`. - * Removed 4-dimensional transformations `Rotation4` and `Isometry4` (which had an implementation to incomplete to be useful). + * Removed 4-dimensional transformations `Rotation4` and `Isometry4` (which had an implementation too incomplete to be useful). ### Modified * Vectors are now multipliable with isometries. This will result into a pure rotation (this is how - vectors differ from point semantically: they design directions so they are not translatable). + vectors differ from point semantically: they design directions, so they are not translatable). * `{Isometry3, Rotation3}::look_at` reimplemented and renamed to `::look_at_rh` and `::look_at_lh` to agree with the computer graphics community (in particular, the GLM library). Use the `::look_at_rh` variant to build a view matrix that diff --git a/Cargo.toml b/Cargo.toml index 5b25b640..8f4c7876 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra" -version = "0.27.1" +version = "0.28.0" authors = [ "Sébastien Crozet " ] description = "General-purpose linear algebra library with transformations and statically-sized or dynamically-sized matrices." diff --git a/examples/cargo/Cargo.toml b/examples/cargo/Cargo.toml index e0dd983c..9020b0ec 100644 --- a/examples/cargo/Cargo.toml +++ b/examples/cargo/Cargo.toml @@ -4,7 +4,7 @@ version = "0.0.0" authors = [ "You" ] [dependencies] -nalgebra = "0.27.0" +nalgebra = "0.28.0" [[bin]] name = "example" diff --git a/nalgebra-glm/Cargo.toml b/nalgebra-glm/Cargo.toml index f97536d0..bebacab8 100644 --- a/nalgebra-glm/Cargo.toml +++ b/nalgebra-glm/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-glm" -version = "0.13.0" +version = "0.14.0" authors = ["sebcrozet "] description = "A computer-graphics oriented API for nalgebra, inspired by the C++ GLM library." @@ -27,4 +27,4 @@ abomonation-serialize = [ "nalgebra/abomonation-serialize" ] num-traits = { version = "0.2", 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 } +nalgebra = { path = "..", version = "0.28", default-features = false } diff --git a/nalgebra-glm/src/lib.rs b/nalgebra-glm/src/lib.rs index df578a80..391391f4 100644 --- a/nalgebra-glm/src/lib.rs +++ b/nalgebra-glm/src/lib.rs @@ -21,7 +21,7 @@ **nalgebra-glm** using the module prefix `glm::`. For example you will write `glm::rotate(...)` instead of the more verbose `nalgebra_glm::rotate(...)`: - ```rust + ``` extern crate nalgebra_glm as glm; ``` diff --git a/nalgebra-lapack/Cargo.toml b/nalgebra-lapack/Cargo.toml index c368a3c6..86825a37 100644 --- a/nalgebra-lapack/Cargo.toml +++ b/nalgebra-lapack/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-lapack" -version = "0.18.0" +version = "0.19.0" authors = [ "Sébastien Crozet ", "Andrew Straw " ] description = "Matrix decompositions using nalgebra matrices and Lapack bindings." @@ -29,7 +29,7 @@ accelerate = ["lapack-src/accelerate"] intel-mkl = ["lapack-src/intel-mkl"] [dependencies] -nalgebra = { version = "0.27", path = ".." } +nalgebra = { version = "0.28", path = ".." } num-traits = "0.2" num-complex = { version = "0.4", default-features = false } simba = "0.5" @@ -39,7 +39,7 @@ lapack-src = { version = "0.8", default-features = false } # clippy = "*" [dev-dependencies] -nalgebra = { version = "0.27", features = [ "arbitrary", "rand" ], path = ".." } +nalgebra = { version = "0.28", features = [ "arbitrary", "rand" ], path = ".." } proptest = { version = "1", default-features = false, features = ["std"] } quickcheck = "1" approx = "0.5" diff --git a/nalgebra-lapack/src/lib.rs b/nalgebra-lapack/src/lib.rs index 39965a59..9a027772 100644 --- a/nalgebra-lapack/src/lib.rs +++ b/nalgebra-lapack/src/lib.rs @@ -30,7 +30,7 @@ //! the system installation of netlib without LAPACKE (note the E) or //! CBLAS: //! -//! ```.ignore +//! ```ignore //! sudo apt-get install gfortran libblas3gf liblapack3gf //! export CARGO_FEATURE_SYSTEM_NETLIB=1 //! export CARGO_FEATURE_EXCLUDE_LAPACKE=1 @@ -44,7 +44,7 @@ //! //! On macOS, do this to use Apple's Accelerate framework: //! -//! ```.ignore +//! ```ignore //! export CARGO_FEATURES="--no-default-features --features accelerate" //! cargo build ${CARGO_FEATURES} //! ``` diff --git a/nalgebra-macros/Cargo.toml b/nalgebra-macros/Cargo.toml index 59eb5ba1..490950bc 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.27.0", path = ".." } +nalgebra = { version = "0.28.0", path = ".." } trybuild = "1.0.42" diff --git a/nalgebra-sparse/Cargo.toml b/nalgebra-sparse/Cargo.toml index 4af053c2..09b6ad73 100644 --- a/nalgebra-sparse/Cargo.toml +++ b/nalgebra-sparse/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "nalgebra-sparse" -version = "0.3.0" +version = "0.4.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.27", path = "../" } +nalgebra = { version="0.28", 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.27", path = "../", features = ["compare"] } +nalgebra = { version="0.28", path = "../", features = ["compare"] } [package.metadata.docs.rs] # Enable certain features when building docs for docs.rs diff --git a/nalgebra-sparse/src/convert/mod.rs b/nalgebra-sparse/src/convert/mod.rs index 77388b22..93fa5a8b 100644 --- a/nalgebra-sparse/src/convert/mod.rs +++ b/nalgebra-sparse/src/convert/mod.rs @@ -7,7 +7,7 @@ //! The following example illustrates how to convert between matrix formats with the `From` //! implementations. //! -//! ```rust +//! ``` //! use nalgebra_sparse::{csr::CsrMatrix, csc::CscMatrix, coo::CooMatrix}; //! use nalgebra::DMatrix; //! diff --git a/nalgebra-sparse/src/coo.rs b/nalgebra-sparse/src/coo.rs index 3327ed27..679dbdb2 100644 --- a/nalgebra-sparse/src/coo.rs +++ b/nalgebra-sparse/src/coo.rs @@ -20,7 +20,7 @@ use crate::SparseFormatError; /// /// # Examples /// -/// ```rust +/// ``` /// use nalgebra_sparse::{coo::CooMatrix, csr::CsrMatrix, csc::CscMatrix}; /// /// // Initialize a matrix with all zeros (no explicitly stored entries). diff --git a/nalgebra-sparse/src/csc.rs b/nalgebra-sparse/src/csc.rs index a691e1d4..15e0746c 100644 --- a/nalgebra-sparse/src/csc.rs +++ b/nalgebra-sparse/src/csc.rs @@ -19,7 +19,7 @@ use std::slice::{Iter, IterMut}; /// /// # Usage /// -/// ```rust +/// ``` /// use nalgebra_sparse::csc::CscMatrix; /// use nalgebra::{DMatrix, Matrix3x4}; /// use matrixcompare::assert_matrix_eq; @@ -97,7 +97,7 @@ use std::slice::{Iter, IterMut}; /// represents the matrix in a column-by-column fashion. The entries associated with column `j` are /// determined as follows: /// -/// ```rust +/// ``` /// # let col_offsets: Vec = vec![0, 0]; /// # let row_indices: Vec = vec![]; /// # let values: Vec = vec![]; diff --git a/nalgebra-sparse/src/csr.rs b/nalgebra-sparse/src/csr.rs index c2f9b669..4c65908b 100644 --- a/nalgebra-sparse/src/csr.rs +++ b/nalgebra-sparse/src/csr.rs @@ -19,7 +19,7 @@ use std::slice::{Iter, IterMut}; /// /// # Usage /// -/// ```rust +/// ``` /// use nalgebra_sparse::csr::CsrMatrix; /// use nalgebra::{DMatrix, Matrix3x4}; /// use matrixcompare::assert_matrix_eq; @@ -97,7 +97,7 @@ use std::slice::{Iter, IterMut}; /// represents the matrix in a row-by-row fashion. The entries associated with row `i` are /// determined as follows: /// -/// ```rust +/// ``` /// # let row_offsets: Vec = vec![0, 0]; /// # let col_indices: Vec = vec![]; /// # let values: Vec = vec![]; diff --git a/nalgebra-sparse/src/lib.rs b/nalgebra-sparse/src/lib.rs index 80351c07..d50d8e15 100644 --- a/nalgebra-sparse/src/lib.rs +++ b/nalgebra-sparse/src/lib.rs @@ -73,7 +73,7 @@ //! //! # Example: COO -> CSR -> matrix-vector product //! -//! ```rust +//! ``` //! use nalgebra_sparse::{coo::CooMatrix, csr::CsrMatrix}; //! use nalgebra::{DMatrix, DVector}; //! use matrixcompare::assert_matrix_eq; diff --git a/nalgebra-sparse/src/ops/mod.rs b/nalgebra-sparse/src/ops/mod.rs index 50d25e63..d7e6d432 100644 --- a/nalgebra-sparse/src/ops/mod.rs +++ b/nalgebra-sparse/src/ops/mod.rs @@ -90,7 +90,7 @@ //! `C <- 3.0 * C + 2.0 * A^T * B`, where `A`, `B`, `C` are matrices and `A^T` is the transpose //! of `A`. The simplest way to write this is: //! -//! ```rust +//! ``` //! # use nalgebra_sparse::csr::CsrMatrix; //! # let a = CsrMatrix::identity(10); let b = CsrMatrix::identity(10); //! # let mut c = CsrMatrix::identity(10); @@ -109,7 +109,7 @@ //! //! An alternative way to implement this expression (here using CSR matrices) is: //! -//! ```rust +//! ``` //! # use nalgebra_sparse::csr::CsrMatrix; //! # let a = CsrMatrix::identity(10); let b = CsrMatrix::identity(10); //! # let mut c = CsrMatrix::identity(10); diff --git a/src/base/allocator.rs b/src/base/allocator.rs index 062ffbc2..64871635 100644 --- a/src/base/allocator.rs +++ b/src/base/allocator.rs @@ -40,6 +40,7 @@ pub trait Reallocator: /// Reallocates a buffer of shape `(RTo, CTo)`, possibly reusing a previously allocated buffer /// `buf`. Data stored by `buf` are linearly copied to the output: /// + /// # Safety /// * The copy is performed as if both were just arrays (without a matrix structure). /// * If `buf` is larger than the output size, then extra elements of `buf` are truncated. /// * If `buf` is smaller than the output size, then extra elements of the output are left diff --git a/src/base/array_storage.rs b/src/base/array_storage.rs index 00713fb4..643bc631 100644 --- a/src/base/array_storage.rs +++ b/src/base/array_storage.rs @@ -79,7 +79,7 @@ where } #[inline] - unsafe fn is_contiguous(&self) -> bool { + fn is_contiguous(&self) -> bool { true } @@ -286,11 +286,7 @@ where unsafe fn exhume<'a, 'b>(&'a mut self, mut bytes: &'b mut [u8]) -> Option<&'b mut [u8]> { for element in self.as_mut_slice() { let temp = bytes; - bytes = if let Some(remainder) = element.exhume(temp) { - remainder - } else { - return None; - } + bytes = element.exhume(temp)? } Some(bytes) } @@ -327,7 +323,7 @@ mod rkyv_impl { for ArrayStorage { fn serialize(&self, serializer: &mut S) -> Result { - Ok(self.0.serialize(serializer)?) + self.0.serialize(serializer) } } diff --git a/src/base/blas.rs b/src/base/blas.rs index a6a188bc..b705c6c1 100644 --- a/src/base/blas.rs +++ b/src/base/blas.rs @@ -1388,12 +1388,12 @@ where { work.gemv(T::one(), mid, &rhs.column(0), T::zero()); self.column_mut(0) - .gemv_tr(alpha.inlined_clone(), &rhs, work, beta.inlined_clone()); + .gemv_tr(alpha.inlined_clone(), rhs, work, beta.inlined_clone()); for j in 1..rhs.ncols() { work.gemv(T::one(), mid, &rhs.column(j), T::zero()); self.column_mut(j) - .gemv_tr(alpha.inlined_clone(), &rhs, work, beta.inlined_clone()); + .gemv_tr(alpha.inlined_clone(), rhs, work, beta.inlined_clone()); } } diff --git a/src/base/cg.rs b/src/base/cg.rs index 2b62524b..742824c7 100644 --- a/src/base/cg.rs +++ b/src/base/cg.rs @@ -386,7 +386,7 @@ impl, DimNameDiff::::name()), ) - .tr_dot(&shift); + .tr_dot(shift); let post_translation = self.generic_slice( (0, 0), (DimNameDiff::::name(), DimNameDiff::::name()), @@ -423,7 +423,7 @@ where (D::dim() - 1, 0), (Const::<1>, DimNameDiff::::name()), ); - let n = normalizer.tr_dot(&v); + let n = normalizer.tr_dot(v); if !n.is_zero() { return transform * (v / n); diff --git a/src/base/construction.rs b/src/base/construction.rs index ac9023ec..d5ecc7c1 100644 --- a/src/base/construction.rs +++ b/src/base/construction.rs @@ -53,7 +53,10 @@ impl OMatrix where DefaultAllocator: Allocator, { - /// Creates a new uninitialized matrix. If the matrix has a compile-time dimension, this panics + /// Creates a new uninitialized matrix. + /// + /// # Safety + /// If the matrix has a compile-time dimension, this panics /// if `nrows != R::to_usize()` or `ncols != C::to_usize()`. #[inline] pub unsafe fn new_uninitialized_generic(nrows: R, ncols: C) -> mem::MaybeUninit { @@ -827,7 +830,7 @@ where Standard: Distribution, { #[inline] - fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> OMatrix { + fn sample(&self, rng: &mut G) -> OMatrix { let nrows = R::try_to_usize().unwrap_or_else(|| rng.gen_range(0..10)); let ncols = C::try_to_usize().unwrap_or_else(|| rng.gen_range(0..10)); @@ -864,7 +867,7 @@ where { /// Generate a uniformly distributed random unit vector. #[inline] - fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> Unit> { + fn sample(&self, rng: &mut G) -> Unit> { Unit::new_normalize(OVector::from_distribution_generic( D::name(), Const::<1>, diff --git a/src/base/construction_slice.rs b/src/base/construction_slice.rs index 43f3692b..7094bdca 100644 --- a/src/base/construction_slice.rs +++ b/src/base/construction_slice.rs @@ -10,6 +10,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> { /// Creates, without bound-checking, a matrix slice from an array and with dimensions and strides specified by generic types instances. /// + /// # Safety /// This method is unsafe because the input data array is not checked to contain enough elements. /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`. #[inline] @@ -59,6 +60,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSlice<'a, T, R, C> { /// Creates, without bound-checking, a matrix slice from an array and with dimensions specified by generic types instances. /// + /// # Safety /// This method is unsafe because the input data array is not checked to contain enough elements. /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`. #[inline] @@ -146,6 +148,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> { /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions and strides specified by generic types instances. /// + /// # Safety /// This method is unsafe because the input data array is not checked to contain enough elements. /// The generic types `R`, `C`, `RStride`, `CStride` can either be type-level integers or integers wrapped with `Dynamic::new()`. #[inline] @@ -217,6 +220,7 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> impl<'a, T: Scalar, R: Dim, C: Dim> MatrixSliceMutMN<'a, T, R, C> { /// Creates, without bound-checking, a mutable matrix slice from an array and with dimensions specified by generic types instances. /// + /// # Safety /// This method is unsafe because the input data array is not checked to contain enough elements. /// The generic types `R` and `C` can either be type-level integers or integers wrapped with `Dynamic::new()`. #[inline] diff --git a/src/base/conversion.rs b/src/base/conversion.rs index 99639991..8ede11ca 100644 --- a/src/base/conversion.rs +++ b/src/base/conversion.rs @@ -1,6 +1,7 @@ #[cfg(all(feature = "alloc", not(feature = "std")))] use alloc::vec::Vec; use simba::scalar::{SubsetOf, SupersetOf}; +use std::borrow::{Borrow, BorrowMut}; use std::convert::{AsMut, AsRef, From, Into}; use simba::simd::{PrimitiveSimdValue, SimdValue}; @@ -192,32 +193,47 @@ impl From> for [[T; } } -macro_rules! impl_from_into_asref_2D( - ($(($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr));* $(;)*) => {$( - impl AsRef<[[T; $SZRows]; $SZCols]> for Matrix +macro_rules! impl_from_into_asref_borrow_2D( + + //does the impls on one case for either AsRef/AsMut and Borrow/BorrowMut + ( + ($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr); + $Ref:ident.$ref:ident(), $Mut:ident.$mut:ident() + ) => { + impl $Ref<[[T; $SZRows]; $SZCols]> for Matrix where S: ContiguousStorage { #[inline] - fn as_ref(&self) -> &[[T; $SZRows]; $SZCols] { + fn $ref(&self) -> &[[T; $SZRows]; $SZCols] { unsafe { &*(self.data.ptr() as *const [[T; $SZRows]; $SZCols]) } } } - impl AsMut<[[T; $SZRows]; $SZCols]> for Matrix + impl $Mut<[[T; $SZRows]; $SZCols]> for Matrix where S: ContiguousStorageMut { #[inline] - fn as_mut(&mut self) -> &mut [[T; $SZRows]; $SZCols] { + fn $mut(&mut self) -> &mut [[T; $SZRows]; $SZCols] { unsafe { &mut *(self.data.ptr_mut() as *mut [[T; $SZRows]; $SZCols]) } } } + }; + + //collects the mappings from typenum pairs to consts + ($(($NRows: ty, $NCols: ty) => ($SZRows: expr, $SZCols: expr));* $(;)*) => {$( + impl_from_into_asref_borrow_2D!( + ($NRows, $NCols) => ($SZRows, $SZCols); AsRef.as_ref(), AsMut.as_mut() + ); + impl_from_into_asref_borrow_2D!( + ($NRows, $NCols) => ($SZRows, $SZCols); Borrow.borrow(), BorrowMut.borrow_mut() + ); )*} ); // Implement for matrices with shape 2x2 .. 6x6. -impl_from_into_asref_2D!( +impl_from_into_asref_borrow_2D!( (U2, U2) => (2, 2); (U2, U3) => (2, 3); (U2, U4) => (2, 4); (U2, U5) => (2, 5); (U2, U6) => (2, 6); (U3, U2) => (3, 2); (U3, U3) => (3, 3); (U3, U4) => (3, 4); (U3, U5) => (3, 5); (U3, U6) => (3, 6); (U4, U2) => (4, 2); (U4, U3) => (4, 3); (U4, U4) => (4, 4); (U4, U5) => (4, 5); (U4, U6) => (4, 6); @@ -451,6 +467,12 @@ impl<'a, T: Scalar + Copy> From<&'a [T]> for DVectorSlice<'a, T> { } } +impl<'a, T: Scalar> From> for &'a [T] { + fn from(vec: DVectorSlice<'a, T>) -> &'a [T] { + vec.data.into_slice() + } +} + impl<'a, T: Scalar + Copy> From<&'a mut [T]> for DVectorSliceMut<'a, T> { #[inline] fn from(slice: &'a mut [T]) -> Self { @@ -458,6 +480,12 @@ impl<'a, T: Scalar + Copy> From<&'a mut [T]> for DVectorSliceMut<'a, T> { } } +impl<'a, T: Scalar> From> for &'a mut [T] { + fn from(vec: DVectorSliceMut<'a, T>) -> &'a mut [T] { + vec.data.into_slice_mut() + } +} + impl From<[OMatrix; 2]> for OMatrix where diff --git a/src/base/dimension.rs b/src/base/dimension.rs index 2b5ccec3..8573dd59 100644 --- a/src/base/dimension.rs +++ b/src/base/dimension.rs @@ -20,7 +20,7 @@ pub struct Dynamic { impl Dynamic { /// A dynamic size equal to `value`. #[inline] - pub fn new(value: usize) -> Self { + pub const fn new(value: usize) -> Self { Self { value } } } diff --git a/src/base/edition.rs b/src/base/edition.rs index e7ef00d2..f403f9d3 100644 --- a/src/base/edition.rs +++ b/src/base/edition.rs @@ -587,6 +587,7 @@ impl> Matrix { /// Inserts `ninsert.value()` columns starting at the `i-th` place of this matrix. /// + /// # Safety /// The added column values are not initialized. #[inline] pub unsafe fn insert_columns_generic_uninitialized( @@ -668,6 +669,7 @@ impl> Matrix { /// Inserts `ninsert.value()` rows at the `i-th` place of this matrix. /// + /// # Safety /// The added rows values are not initialized. /// This is the generic implementation of `.insert_rows(...)` and /// `.insert_fixed_rows(...)` which have nicer API interfaces. diff --git a/src/base/indexing.rs b/src/base/indexing.rs index 5bc06020..5107035c 100644 --- a/src/base/indexing.rs +++ b/src/base/indexing.rs @@ -44,7 +44,7 @@ impl DimRange for usize { #[test] fn dimrange_usize() { assert_eq!(DimRange::contained_by(&0, Const::<0>), false); - assert_eq!(DimRange::contained_by(&0, Const::<1>), true); + assert!(DimRange::contained_by(&0, Const::<1>)); } impl DimRange for ops::Range { @@ -68,24 +68,23 @@ impl DimRange for ops::Range { #[test] fn dimrange_range_usize() { - use std::usize::MAX; assert_eq!(DimRange::contained_by(&(0..0), Const::<0>), false); assert_eq!(DimRange::contained_by(&(0..1), Const::<0>), false); - assert_eq!(DimRange::contained_by(&(0..1), Const::<1>), true); + assert!(DimRange::contained_by(&(0..1), Const::<1>)); + assert!(DimRange::contained_by( + &((usize::MAX - 1)..usize::MAX), + Dynamic::new(usize::MAX) + )); assert_eq!( - DimRange::contained_by(&((MAX - 1)..MAX), Dynamic::new(MAX)), - true - ); - assert_eq!( - DimRange::length(&((MAX - 1)..MAX), Dynamic::new(MAX)), + DimRange::length(&((usize::MAX - 1)..usize::MAX), Dynamic::new(usize::MAX)), Dynamic::new(1) ); assert_eq!( - DimRange::length(&(MAX..(MAX - 1)), Dynamic::new(MAX)), + DimRange::length(&(usize::MAX..(usize::MAX - 1)), Dynamic::new(usize::MAX)), Dynamic::new(0) ); assert_eq!( - DimRange::length(&(MAX..MAX), Dynamic::new(MAX)), + DimRange::length(&(usize::MAX..usize::MAX), Dynamic::new(usize::MAX)), Dynamic::new(0) ); } @@ -111,20 +110,19 @@ impl DimRange for ops::RangeFrom { #[test] fn dimrange_rangefrom_usize() { - use std::usize::MAX; assert_eq!(DimRange::contained_by(&(0..), Const::<0>), false); assert_eq!(DimRange::contained_by(&(0..), Const::<0>), false); - assert_eq!(DimRange::contained_by(&(0..), Const::<1>), true); + assert!(DimRange::contained_by(&(0..), Const::<1>)); + assert!(DimRange::contained_by( + &((usize::MAX - 1)..), + Dynamic::new(usize::MAX) + )); assert_eq!( - DimRange::contained_by(&((MAX - 1)..), Dynamic::new(MAX)), - true - ); - assert_eq!( - DimRange::length(&((MAX - 1)..), Dynamic::new(MAX)), + DimRange::length(&((usize::MAX - 1)..), Dynamic::new(usize::MAX)), Dynamic::new(1) ); assert_eq!( - DimRange::length(&(MAX..), Dynamic::new(MAX)), + DimRange::length(&(usize::MAX..), Dynamic::new(usize::MAX)), Dynamic::new(0) ); } @@ -177,7 +175,7 @@ impl DimRange for ops::RangeFull { #[test] fn dimrange_rangefull() { - assert_eq!(DimRange::contained_by(&(..), Const::<0>), true); + assert!(DimRange::contained_by(&(..), Const::<0>)); assert_eq!(DimRange::length(&(..), Const::<1>), Const::<1>); } @@ -206,32 +204,31 @@ impl DimRange for ops::RangeInclusive { #[test] fn dimrange_rangeinclusive_usize() { - use std::usize::MAX; assert_eq!(DimRange::contained_by(&(0..=0), Const::<0>), false); - assert_eq!(DimRange::contained_by(&(0..=0), Const::<1>), true); + assert!(DimRange::contained_by(&(0..=0), Const::<1>)); assert_eq!( - DimRange::contained_by(&(MAX..=MAX), Dynamic::new(MAX)), + DimRange::contained_by(&(usize::MAX..=usize::MAX), Dynamic::new(usize::MAX)), false ); assert_eq!( - DimRange::contained_by(&((MAX - 1)..=MAX), Dynamic::new(MAX)), + DimRange::contained_by(&((usize::MAX - 1)..=usize::MAX), Dynamic::new(usize::MAX)), false ); - assert_eq!( - DimRange::contained_by(&((MAX - 1)..=(MAX - 1)), Dynamic::new(MAX)), - true - ); + assert!(DimRange::contained_by( + &((usize::MAX - 1)..=(usize::MAX - 1)), + Dynamic::new(usize::MAX) + )); assert_eq!(DimRange::length(&(0..=0), Const::<1>), Dynamic::new(1)); assert_eq!( - DimRange::length(&((MAX - 1)..=MAX), Dynamic::new(MAX)), + DimRange::length(&((usize::MAX - 1)..=usize::MAX), Dynamic::new(usize::MAX)), Dynamic::new(2) ); assert_eq!( - DimRange::length(&(MAX..=(MAX - 1)), Dynamic::new(MAX)), + DimRange::length(&(usize::MAX..=(usize::MAX - 1)), Dynamic::new(usize::MAX)), Dynamic::new(0) ); assert_eq!( - DimRange::length(&(MAX..=MAX), Dynamic::new(MAX)), + DimRange::length(&(usize::MAX..=usize::MAX), Dynamic::new(usize::MAX)), Dynamic::new(1) ); } @@ -257,21 +254,20 @@ impl DimRange for ops::RangeTo { #[test] fn dimrange_rangeto_usize() { - use std::usize::MAX; - assert_eq!(DimRange::contained_by(&(..0), Const::<0>), true); + assert!(DimRange::contained_by(&(..0), Const::<0>)); assert_eq!(DimRange::contained_by(&(..1), Const::<0>), false); - assert_eq!(DimRange::contained_by(&(..0), Const::<1>), true); + assert!(DimRange::contained_by(&(..0), Const::<1>)); + assert!(DimRange::contained_by( + &(..(usize::MAX - 1)), + Dynamic::new(usize::MAX) + )); assert_eq!( - DimRange::contained_by(&(..(MAX - 1)), Dynamic::new(MAX)), - true + DimRange::length(&(..(usize::MAX - 1)), Dynamic::new(usize::MAX)), + Dynamic::new(usize::MAX - 1) ); assert_eq!( - DimRange::length(&(..(MAX - 1)), Dynamic::new(MAX)), - Dynamic::new(MAX - 1) - ); - assert_eq!( - DimRange::length(&(..MAX), Dynamic::new(MAX)), - Dynamic::new(MAX) + DimRange::length(&(..usize::MAX), Dynamic::new(usize::MAX)), + Dynamic::new(usize::MAX) ); } @@ -296,21 +292,20 @@ impl DimRange for ops::RangeToInclusive { #[test] fn dimrange_rangetoinclusive_usize() { - use std::usize::MAX; assert_eq!(DimRange::contained_by(&(..=0), Const::<0>), false); assert_eq!(DimRange::contained_by(&(..=1), Const::<0>), false); - assert_eq!(DimRange::contained_by(&(..=0), Const::<1>), true); + assert!(DimRange::contained_by(&(..=0), Const::<1>)); assert_eq!( - DimRange::contained_by(&(..=(MAX)), Dynamic::new(MAX)), + DimRange::contained_by(&(..=(usize::MAX)), Dynamic::new(usize::MAX)), false ); + assert!(DimRange::contained_by( + &(..=(usize::MAX - 1)), + Dynamic::new(usize::MAX) + )); assert_eq!( - DimRange::contained_by(&(..=(MAX - 1)), Dynamic::new(MAX)), - true - ); - assert_eq!( - DimRange::length(&(..=(MAX - 1)), Dynamic::new(MAX)), - Dynamic::new(MAX) + DimRange::length(&(..=(usize::MAX - 1)), Dynamic::new(usize::MAX)), + Dynamic::new(usize::MAX) ); } diff --git a/src/base/matrix.rs b/src/base/matrix.rs index f2da8a8a..319e8eb9 100644 --- a/src/base/matrix.rs +++ b/src/base/matrix.rs @@ -336,7 +336,7 @@ mod rkyv_impl { for Matrix { fn serialize(&self, serializer: &mut _S) -> Result { - Ok(self.data.serialize(serializer)?) + self.data.serialize(serializer) } } @@ -1581,7 +1581,7 @@ impl + IsNotStaticOne, S: Storage let dim = DimSum::::from_usize(self.nrows() + 1); let mut res = OMatrix::identity_generic(dim, dim); res.generic_slice_mut::((0, 0), self.data.shape()) - .copy_from(&self); + .copy_from(self); res } } @@ -1819,7 +1819,6 @@ macro_rules! impl_fmt { where T: Scalar + $trait, S: Storage, - DefaultAllocator: Allocator, { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { #[cfg(feature = "std")] @@ -1837,20 +1836,17 @@ macro_rules! impl_fmt { 4 } - let (nrows, ncols) = self.data.shape(); + let (nrows, ncols) = self.shape(); - if nrows.value() == 0 || ncols.value() == 0 { + if nrows == 0 || ncols == 0 { return write!(f, "[ ]"); } let mut max_length = 0; - let mut lengths: OMatrix = Matrix::zeros_generic(nrows, ncols); - let (nrows, ncols) = self.shape(); for i in 0..nrows { for j in 0..ncols { - lengths[(i, j)] = val_width(&self[(i, j)], f); - max_length = crate::max(max_length, lengths[(i, j)]); + max_length = crate::max(max_length, val_width(&self[(i, j)], f)); } } @@ -1867,7 +1863,7 @@ macro_rules! impl_fmt { for i in 0..nrows { write!(f, " │")?; for j in 0..ncols { - let number_length = lengths[(i, j)] + 1; + let number_length = val_width(&self[(i, j)], f) + 1; let pad = max_length_with_space - number_length; write!(f, " {:>thepad$}", "", thepad = pad)?; match f.precision() { @@ -1900,19 +1896,29 @@ impl_fmt!(fmt::UpperHex, "{:X}", "{:1$X}"); impl_fmt!(fmt::Binary, "{:b}", "{:.1$b}"); impl_fmt!(fmt::Pointer, "{:p}", "{:.1$p}"); -#[test] -fn lower_exp() { - let test = crate::Matrix2::new(1e6, 2e5, 2e-5, 1.); - assert_eq!( - format!("{:e}", test), - r" +#[cfg(test)] +mod tests { + #[test] + fn empty_display() { + let vec: Vec = Vec::new(); + let dvector = crate::DVector::from_vec(vec); + assert_eq!(format!("{}", dvector), "[ ]") + } + + #[test] + fn lower_exp() { + let test = crate::Matrix2::new(1e6, 2e5, 2e-5, 1.); + assert_eq!( + format!("{:e}", test), + r" ┌ ┐ │ 1e6 2e5 │ │ 2e-5 1e0 │ └ ┘ " - ) + ) + } } /// # Cross product diff --git a/src/base/matrix_slice.rs b/src/base/matrix_slice.rs index 6cb713f1..96ebe59c 100644 --- a/src/base/matrix_slice.rs +++ b/src/base/matrix_slice.rs @@ -77,6 +77,23 @@ macro_rules! slice_storage_impl( $T::from_raw_parts(storage.$get_addr(start.0, start.1), shape, strides) } } + + impl <'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> + $T<'a, T, R, C, RStride, CStride> + where + Self: ContiguousStorage + { + /// Extracts the original slice from this storage + pub fn into_slice(self) -> &'a [T] { + let (nrows, ncols) = self.shape(); + if nrows.value() != 0 && ncols.value() != 0 { + let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); + unsafe { slice::from_raw_parts(self.ptr, sz + 1) } + } else { + unsafe { slice::from_raw_parts(self.ptr, 0) } + } + } + } } ); @@ -108,6 +125,23 @@ impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Clone } } +impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> + SliceStorageMut<'a, T, R, C, RStride, CStride> +where + Self: ContiguousStorageMut, +{ + /// Extracts the original slice from this storage + pub fn into_slice_mut(self) -> &'a mut [T] { + let (nrows, ncols) = self.shape(); + if nrows.value() != 0 && ncols.value() != 0 { + let sz = self.linear_index(nrows.value() - 1, ncols.value() - 1); + unsafe { slice::from_raw_parts_mut(self.ptr, sz + 1) } + } else { + unsafe { slice::from_raw_parts_mut(self.ptr, 0) } + } + } +} + macro_rules! storage_impl( ($($T: ident),* $(,)*) => {$( unsafe impl<'a, T: Scalar, R: Dim, C: Dim, RStride: Dim, CStride: Dim> Storage @@ -132,7 +166,7 @@ macro_rules! storage_impl( } #[inline] - unsafe fn is_contiguous(&self) -> bool { + fn is_contiguous(&self) -> bool { // Common cases that can be deduced at compile-time even if one of the dimensions // is Dynamic. if (RStride::is::() && C::is::()) || // Column vector. diff --git a/src/base/storage.rs b/src/base/storage.rs index 1eaa9b62..a750904f 100644 --- a/src/base/storage.rs +++ b/src/base/storage.rs @@ -58,7 +58,7 @@ pub unsafe trait Storage: Debug + Sized { /// Compute the index corresponding to the irow-th row and icol-th column of this matrix. The /// index must be such that the following holds: /// - /// ```.ignore + /// ```ignore /// let lindex = self.linear_index(irow, icol); /// assert!(*self.get_unchecked(irow, icol) == *self.get_unchecked_linear(lindex)) /// ``` @@ -70,24 +70,36 @@ pub unsafe trait Storage: Debug + Sized { } /// Gets the address of the i-th matrix component without performing bound-checking. + /// + /// # Safety + /// If the index is out of bounds, dereferencing the result will cause undefined behavior. #[inline] - unsafe fn get_address_unchecked_linear(&self, i: usize) -> *const T { + fn get_address_unchecked_linear(&self, i: usize) -> *const T { self.ptr().wrapping_add(i) } /// Gets the address of the i-th matrix component without performing bound-checking. + /// + /// # Safety + /// If the index is out of bounds, dereferencing the result will cause undefined behavior. #[inline] - unsafe fn get_address_unchecked(&self, irow: usize, icol: usize) -> *const T { + fn get_address_unchecked(&self, irow: usize, icol: usize) -> *const T { self.get_address_unchecked_linear(self.linear_index(irow, icol)) } /// Retrieves a reference to the i-th element without bound-checking. + /// + /// # Safety + /// If the index is out of bounds, the method will cause undefined behavior. #[inline] unsafe fn get_unchecked_linear(&self, i: usize) -> &T { &*self.get_address_unchecked_linear(i) } /// Retrieves a reference to the i-th element without bound-checking. + /// + /// # Safety + /// If the index is out of bounds, the method will cause undefined behavior. #[inline] unsafe fn get_unchecked(&self, irow: usize, icol: usize) -> &T { self.get_unchecked_linear(self.linear_index(irow, icol)) @@ -95,12 +107,14 @@ pub unsafe trait Storage: Debug + Sized { /// Indicates whether this data buffer stores its elements contiguously. /// - /// This method is unsafe because unsafe code relies on this properties to performe - /// some low-lever optimizations. - unsafe fn is_contiguous(&self) -> bool; + /// # Safety + /// This function must not return `true` if the underlying storage is not contiguous, + /// or undefined behaviour will occur. + fn is_contiguous(&self) -> bool; /// Retrieves the data buffer as a contiguous slice. /// + /// # Safety /// The matrix components may not be stored in a contiguous way, depending on the strides. /// This method is unsafe because this can yield to invalid aliasing when called on some pairs /// of matrix slices originating from the same matrix with strides. @@ -129,30 +143,45 @@ pub unsafe trait StorageMut: Storage { fn ptr_mut(&mut self) -> *mut T; /// Gets the mutable address of the i-th matrix component without performing bound-checking. + /// + /// # Safety + /// If the index is out of bounds, dereferencing the result will cause undefined behavior. #[inline] - unsafe fn get_address_unchecked_linear_mut(&mut self, i: usize) -> *mut T { + fn get_address_unchecked_linear_mut(&mut self, i: usize) -> *mut T { self.ptr_mut().wrapping_add(i) } /// Gets the mutable address of the i-th matrix component without performing bound-checking. + /// + /// # Safety + /// If the index is out of bounds, dereferencing the result will cause undefined behavior. #[inline] - unsafe fn get_address_unchecked_mut(&mut self, irow: usize, icol: usize) -> *mut T { + fn get_address_unchecked_mut(&mut self, irow: usize, icol: usize) -> *mut T { let lid = self.linear_index(irow, icol); self.get_address_unchecked_linear_mut(lid) } /// Retrieves a mutable reference to the i-th element without bound-checking. + /// + /// # Safety + /// If the index is out of bounds, the method will cause undefined behavior. unsafe fn get_unchecked_linear_mut(&mut self, i: usize) -> &mut T { &mut *self.get_address_unchecked_linear_mut(i) } /// Retrieves a mutable reference to the element at `(irow, icol)` without bound-checking. + /// + /// # Safety + /// If the index is out of bounds, the method will cause undefined behavior. #[inline] unsafe fn get_unchecked_mut(&mut self, irow: usize, icol: usize) -> &mut T { &mut *self.get_address_unchecked_mut(irow, icol) } /// Swaps two elements using their linear index without bound-checking. + /// + /// # Safety + /// If the indices are out of bounds, the method will cause undefined behavior. #[inline] unsafe fn swap_unchecked_linear(&mut self, i1: usize, i2: usize) { let a = self.get_address_unchecked_linear_mut(i1); @@ -162,6 +191,9 @@ pub unsafe trait StorageMut: Storage { } /// Swaps two elements without bound-checking. + /// + /// # Safety + /// If the indices are out of bounds, the method will cause undefined behavior. #[inline] unsafe fn swap_unchecked(&mut self, row_col1: (usize, usize), row_col2: (usize, usize)) { let lid1 = self.linear_index(row_col1.0, row_col1.1); @@ -174,6 +206,7 @@ pub unsafe trait StorageMut: Storage { /// /// Matrix components may not be contiguous, depending on its strides. /// + /// # Safety /// The matrix components may not be stored in a contiguous way, depending on the strides. /// This method is unsafe because this can yield to invalid aliasing when called on some pairs /// of matrix slices originating from the same matrix with strides. diff --git a/src/base/unit.rs b/src/base/unit.rs index 32eff82f..a6ca33f3 100644 --- a/src/base/unit.rs +++ b/src/base/unit.rs @@ -95,7 +95,7 @@ mod rkyv_impl { impl, S: Fallible + ?Sized> Serialize for Unit { fn serialize(&self, serializer: &mut S) -> Result { - Ok(self.value.serialize(serializer)?) + self.value.serialize(serializer) } } @@ -221,7 +221,7 @@ impl Unit { impl Unit { /// Wraps the given value, assuming it is already normalized. #[inline] - pub fn new_unchecked(value: T) -> Self { + pub const fn new_unchecked(value: T) -> Self { Unit { value } } diff --git a/src/base/vec_storage.rs b/src/base/vec_storage.rs index c312c048..be567094 100644 --- a/src/base/vec_storage.rs +++ b/src/base/vec_storage.rs @@ -102,6 +102,7 @@ impl VecStorage { /// The underlying mutable data storage. /// + /// # Safety /// This is unsafe because this may cause UB if the size of the vector is changed /// by the user. #[inline] @@ -111,6 +112,7 @@ impl VecStorage { /// Resizes the underlying mutable data storage and unwraps it. /// + /// # Safety /// If `sz` is larger than the current size, additional elements are uninitialized. /// If `sz` is smaller than the current size, additional elements are truncated. #[inline] @@ -178,7 +180,7 @@ where } #[inline] - unsafe fn is_contiguous(&self) -> bool { + fn is_contiguous(&self) -> bool { true } @@ -227,7 +229,7 @@ where } #[inline] - unsafe fn is_contiguous(&self) -> bool { + fn is_contiguous(&self) -> bool { true } diff --git a/src/geometry/dual_quaternion.rs b/src/geometry/dual_quaternion.rs index 376c5fbb..92f6e4a9 100644 --- a/src/geometry/dual_quaternion.rs +++ b/src/geometry/dual_quaternion.rs @@ -38,14 +38,23 @@ use simba::scalar::{ClosedNeg, RealField}; /// If a feature that you need is missing, feel free to open an issue or a PR. /// See https://github.com/dimforge/nalgebra/issues/487 #[repr(C)] -#[derive(Debug, Eq, PartialEq, Copy, Clone)] -pub struct DualQuaternion { +#[derive(Debug, Copy, Clone)] +pub struct DualQuaternion { /// The real component of the quaternion pub real: Quaternion, /// The dual component of the quaternion pub dual: Quaternion, } +impl Eq for DualQuaternion {} + +impl PartialEq for DualQuaternion { + #[inline] + fn eq(&self, right: &Self) -> bool { + self.real == right.real && self.dual == right.dual + } +} + impl Default for DualQuaternion { fn default() -> Self { Self { @@ -291,7 +300,7 @@ where } impl DualQuaternion { - fn to_vector(&self) -> OVector { + fn to_vector(self) -> OVector { (*self.as_ref()).into() } } @@ -740,7 +749,7 @@ where /// ``` #[inline] #[must_use] - pub fn to_isometry(&self) -> Isometry3 { + pub fn to_isometry(self) -> Isometry3 { Isometry3::from_parts(self.translation(), self.rotation()) } @@ -891,7 +900,7 @@ where /// ``` #[inline] #[must_use] - pub fn to_homogeneous(&self) -> Matrix4 { + pub fn to_homogeneous(self) -> Matrix4 { self.to_isometry().to_homogeneous() } } diff --git a/src/geometry/isometry.rs b/src/geometry/isometry.rs index 7d8c6e95..333468b3 100755 --- a/src/geometry/isometry.rs +++ b/src/geometry/isometry.rs @@ -60,15 +60,17 @@ use crate::geometry::{AbstractRotation, Point, Translation}; feature = "serde-serialize-no-std", serde(bound(serialize = "R: Serialize, DefaultAllocator: Allocator>, - Owned>: Serialize")) + Owned>: Serialize, + T: Scalar")) )] #[cfg_attr( feature = "serde-serialize-no-std", serde(bound(deserialize = "R: Deserialize<'de>, DefaultAllocator: Allocator>, - Owned>: Deserialize<'de>")) + Owned>: Deserialize<'de>, + T: Scalar")) )] -pub struct Isometry { +pub struct Isometry { /// The pure rotational part of this isometry. pub rotation: R, /// The pure translational part of this isometry. diff --git a/src/geometry/isometry_construction.rs b/src/geometry/isometry_construction.rs index e13bde29..39a1d763 100644 --- a/src/geometry/isometry_construction.rs +++ b/src/geometry/isometry_construction.rs @@ -86,7 +86,7 @@ where Standard: Distribution + Distribution, { #[inline] - fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> Isometry { + fn sample(&self, rng: &mut G) -> Isometry { Isometry::from_parts(rng.gen(), rng.gen()) } } diff --git a/src/geometry/orthographic.rs b/src/geometry/orthographic.rs index 4f7b909b..62e19949 100644 --- a/src/geometry/orthographic.rs +++ b/src/geometry/orthographic.rs @@ -19,7 +19,7 @@ use crate::geometry::{Point3, Projective3}; /// A 3D orthographic projection stored as a homogeneous 4x4 matrix. #[repr(C)] -pub struct Orthographic3 { +pub struct Orthographic3 { matrix: Matrix4, } @@ -239,7 +239,7 @@ impl Orthographic3 { /// ``` #[inline] #[must_use] - pub fn to_homogeneous(&self) -> Matrix4 { + pub fn to_homogeneous(self) -> Matrix4 { self.matrix } @@ -287,7 +287,7 @@ impl Orthographic3 { /// ``` #[inline] #[must_use] - pub fn to_projective(&self) -> Projective3 { + pub fn to_projective(self) -> Projective3 { Projective3::from_matrix_unchecked(self.matrix) } diff --git a/src/geometry/perspective.rs b/src/geometry/perspective.rs index 90cf95d8..330e7214 100644 --- a/src/geometry/perspective.rs +++ b/src/geometry/perspective.rs @@ -14,13 +14,13 @@ use simba::scalar::RealField; use crate::base::dimension::U3; use crate::base::storage::Storage; -use crate::base::{Matrix4, Scalar, Vector, Vector3}; +use crate::base::{Matrix4, Vector, Vector3}; use crate::geometry::{Point3, Projective3}; /// A 3D perspective projection stored as a homogeneous 4x4 matrix. #[repr(C)] -pub struct Perspective3 { +pub struct Perspective3 { matrix: Matrix4, } @@ -141,7 +141,7 @@ impl Perspective3 { /// Computes the corresponding homogeneous matrix. #[inline] #[must_use] - pub fn to_homogeneous(&self) -> Matrix4 { + pub fn to_homogeneous(self) -> Matrix4 { self.matrix.clone_owned() } @@ -162,7 +162,7 @@ impl Perspective3 { /// This transformation seen as a `Projective3`. #[inline] #[must_use] - pub fn to_projective(&self) -> Projective3 { + pub fn to_projective(self) -> Projective3 { Projective3::from_matrix_unchecked(self.matrix) } @@ -305,7 +305,7 @@ where Standard: Distribution, { /// Generate an arbitrary random variate for testing purposes. - fn sample<'a, R: Rng + ?Sized>(&self, r: &'a mut R) -> Perspective3 { + fn sample(&self, r: &mut R) -> Perspective3 { use crate::base::helper; let znear = r.gen(); let zfar = helper::reject_rand(r, |&x: &T| !(x - znear).is_zero()); diff --git a/src/geometry/point.rs b/src/geometry/point.rs index d25b4d7c..d4d9dbfc 100644 --- a/src/geometry/point.rs +++ b/src/geometry/point.rs @@ -17,7 +17,7 @@ use simba::simd::SimdPartialOrd; use crate::base::allocator::Allocator; use crate::base::dimension::{DimName, DimNameAdd, DimNameSum, U1}; use crate::base::iter::{MatrixIter, MatrixIterMut}; -use crate::base::{Const, DefaultAllocator, OVector, SVector, Scalar}; +use crate::base::{Const, DefaultAllocator, OVector, Scalar}; /// A point in an euclidean space. /// @@ -40,35 +40,53 @@ use crate::base::{Const, DefaultAllocator, OVector, SVector, Scalar}; /// of said transformations for details. #[repr(C)] #[derive(Debug, Clone)] -pub struct Point { +pub struct OPoint +where + DefaultAllocator: Allocator, +{ /// The coordinates of this point, i.e., the shift from the origin. - pub coords: SVector, + pub coords: OVector, } -impl hash::Hash for Point { +impl hash::Hash for OPoint +where + DefaultAllocator: Allocator, +{ fn hash(&self, state: &mut H) { self.coords.hash(state) } } -impl Copy for Point {} - -#[cfg(feature = "bytemuck")] -unsafe impl bytemuck::Zeroable for Point where - SVector: bytemuck::Zeroable +impl Copy for OPoint +where + DefaultAllocator: Allocator, + OVector: Copy, { } #[cfg(feature = "bytemuck")] -unsafe impl bytemuck::Pod for Point +unsafe impl bytemuck::Zeroable for OPoint +where + OVector: bytemuck::Zeroable, + DefaultAllocator: Allocator, +{ +} + +#[cfg(feature = "bytemuck")] +unsafe impl bytemuck::Pod for OPoint where T: Copy, - SVector: bytemuck::Pod, + OVector: bytemuck::Pod, + DefaultAllocator: Allocator, { } #[cfg(feature = "serde-serialize-no-std")] -impl Serialize for Point { +impl Serialize for OPoint +where + DefaultAllocator: Allocator, + >::Buffer: Serialize, +{ fn serialize(&self, serializer: S) -> Result where S: Serializer, @@ -78,22 +96,27 @@ impl Serialize for Point { } #[cfg(feature = "serde-serialize-no-std")] -impl<'a, T: Scalar + Deserialize<'a>, const D: usize> Deserialize<'a> for Point { +impl<'a, T: Scalar + Deserialize<'a>, D: DimName> Deserialize<'a> for OPoint +where + DefaultAllocator: Allocator, + >::Buffer: Deserialize<'a>, +{ fn deserialize(deserializer: Des) -> Result where Des: Deserializer<'a>, { - let coords = SVector::::deserialize(deserializer)?; + let coords = OVector::::deserialize(deserializer)?; Ok(Self::from(coords)) } } #[cfg(feature = "abomonation-serialize")] -impl Abomonation for Point +impl Abomonation for OPoint where T: Scalar, - SVector: Abomonation, + OVector: Abomonation, + DefaultAllocator: Allocator, { unsafe fn entomb(&self, writer: &mut W) -> IOResult<()> { self.coords.entomb(writer) @@ -108,7 +131,10 @@ where } } -impl Point { +impl OPoint +where + DefaultAllocator: Allocator, +{ /// Returns a point containing the result of `f` applied to each of its entries. /// /// # Example @@ -123,7 +149,10 @@ impl Point { /// ``` #[inline] #[must_use] - pub fn map T2>(&self, f: F) -> Point { + pub fn map T2>(&self, f: F) -> OPoint + where + DefaultAllocator: Allocator, + { self.coords.map(f).into() } @@ -163,20 +192,21 @@ impl Point { /// ``` #[inline] #[must_use] - pub fn to_homogeneous(&self) -> OVector, U1>> + pub fn to_homogeneous(&self) -> OVector> where T: One, - Const: DimNameAdd, - DefaultAllocator: Allocator, U1>>, + D: DimNameAdd, + DefaultAllocator: Allocator>, { let mut res = unsafe { crate::unimplemented_or_uninitialized_generic!( - , U1> as DimName>::name(), + as DimName>::name(), Const::<1> ) }; - res.fixed_slice_mut::(0, 0).copy_from(&self.coords); - res[(D, 0)] = T::one(); + res.generic_slice_mut((0, 0), (D::name(), Const::<1>)) + .copy_from(&self.coords); + res[(D::dim(), 0)] = T::one(); res } @@ -184,7 +214,7 @@ impl Point { /// Creates a new point with the given coordinates. #[deprecated(note = "Use Point::from(vector) instead.")] #[inline] - pub fn from_coordinates(coords: SVector) -> Self { + pub fn from_coordinates(coords: OVector) -> Self { Self { coords } } @@ -243,8 +273,7 @@ impl Point { #[inline] pub fn iter( &self, - ) -> MatrixIter, Const<1>, >>::Buffer> - { + ) -> MatrixIter, >::Buffer> { self.coords.iter() } @@ -270,8 +299,7 @@ impl Point { #[inline] pub fn iter_mut( &mut self, - ) -> MatrixIterMut, Const<1>, >>::Buffer> - { + ) -> MatrixIterMut, >::Buffer> { self.coords.iter_mut() } @@ -289,9 +317,10 @@ impl Point { } } -impl AbsDiffEq for Point +impl AbsDiffEq for OPoint where T::Epsilon: Copy, + DefaultAllocator: Allocator, { type Epsilon = T::Epsilon; @@ -306,9 +335,10 @@ where } } -impl RelativeEq for Point +impl RelativeEq for OPoint where T::Epsilon: Copy, + DefaultAllocator: Allocator, { #[inline] fn default_max_relative() -> Self::Epsilon { @@ -327,9 +357,10 @@ where } } -impl UlpsEq for Point +impl UlpsEq for OPoint where T::Epsilon: Copy, + DefaultAllocator: Allocator, { #[inline] fn default_max_ulps() -> u32 { @@ -342,16 +373,22 @@ where } } -impl Eq for Point {} +impl Eq for OPoint where DefaultAllocator: Allocator {} -impl PartialEq for Point { +impl PartialEq for OPoint +where + DefaultAllocator: Allocator, +{ #[inline] fn eq(&self, right: &Self) -> bool { self.coords == right.coords } } -impl PartialOrd for Point { +impl PartialOrd for OPoint +where + DefaultAllocator: Allocator, +{ #[inline] fn partial_cmp(&self, other: &Self) -> Option { self.coords.partial_cmp(&other.coords) @@ -381,25 +418,28 @@ impl PartialOrd for Point { /* * inf/sup */ -impl Point { +impl OPoint +where + DefaultAllocator: Allocator, +{ /// Computes the infimum (aka. componentwise min) of two points. #[inline] #[must_use] - pub fn inf(&self, other: &Self) -> Point { + pub fn inf(&self, other: &Self) -> OPoint { self.coords.inf(&other.coords).into() } /// Computes the supremum (aka. componentwise max) of two points. #[inline] #[must_use] - pub fn sup(&self, other: &Self) -> Point { + pub fn sup(&self, other: &Self) -> OPoint { self.coords.sup(&other.coords).into() } /// Computes the (infimum, supremum) of two points. #[inline] #[must_use] - pub fn inf_sup(&self, other: &Self) -> (Point, Point) { + pub fn inf_sup(&self, other: &Self) -> (OPoint, OPoint) { let (inf, sup) = self.coords.inf_sup(&other.coords); (inf.into(), sup.into()) } @@ -410,7 +450,10 @@ impl Point { * Display * */ -impl fmt::Display for Point { +impl fmt::Display for OPoint +where + DefaultAllocator: Allocator, +{ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{{")?; diff --git a/src/geometry/point_alias.rs b/src/geometry/point_alias.rs index 54441b09..f5f855c9 100644 --- a/src/geometry/point_alias.rs +++ b/src/geometry/point_alias.rs @@ -1,4 +1,8 @@ -use crate::geometry::Point; +use crate::geometry::OPoint; +use crate::Const; + +/// A point with `D` elements. +pub type Point = OPoint>; /// A statically sized 1-dimensional column point. /// diff --git a/src/geometry/point_construction.rs b/src/geometry/point_construction.rs index 7e34137c..0ffbf4d8 100644 --- a/src/geometry/point_construction.rs +++ b/src/geometry/point_construction.rs @@ -10,22 +10,26 @@ use rand::{ use crate::base::allocator::Allocator; use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; -use crate::base::{DefaultAllocator, SVector, Scalar}; +use crate::base::{DefaultAllocator, Scalar}; use crate::{ - Const, OVector, Point1, Point2, Point3, Point4, Point5, Point6, Vector1, Vector2, Vector3, - Vector4, Vector5, Vector6, + Const, DimName, OPoint, OVector, Point1, Point2, Point3, Point4, Point5, Point6, Vector1, + Vector2, Vector3, Vector4, Vector5, Vector6, }; use simba::scalar::{ClosedDiv, SupersetOf}; use crate::geometry::Point; /// # Other construction methods -impl Point { +impl OPoint +where + DefaultAllocator: Allocator, +{ /// Creates a new point with uninitialized coordinates. #[inline] pub unsafe fn new_uninitialized() -> Self { Self::from(crate::unimplemented_or_uninitialized_generic!( - Const::, Const::<1> + D::name(), + Const::<1> )) } @@ -49,7 +53,7 @@ impl Point { where T: Zero, { - Self::from(SVector::from_element(T::zero())) + Self::from(OVector::from_element(T::zero())) } /// Creates a new point from a slice. @@ -68,7 +72,7 @@ impl Point { /// ``` #[inline] pub fn from_slice(components: &[T]) -> Self { - Self::from(SVector::from_row_slice(components)) + Self::from(OVector::from_row_slice(components)) } /// Creates a new point from its homogeneous vector representation. @@ -102,14 +106,15 @@ impl Point { /// assert_eq!(pt, Some(Point2::new(1.0, 2.0))); /// ``` #[inline] - pub fn from_homogeneous(v: OVector, U1>>) -> Option + pub fn from_homogeneous(v: OVector>) -> Option where T: Scalar + Zero + One + ClosedDiv, - Const: DimNameAdd, - DefaultAllocator: Allocator, U1>>, + D: DimNameAdd, + DefaultAllocator: Allocator>, { - if !v[D].is_zero() { - let coords = v.fixed_slice::(0, 0) / v[D].inlined_clone(); + if !v[D::dim()].is_zero() { + let coords = + v.generic_slice((0, 0), (D::name(), Const::<1>)) / v[D::dim()].inlined_clone(); Some(Self::from(coords)) } else { None @@ -125,9 +130,10 @@ impl Point { /// let pt2 = pt.cast::(); /// assert_eq!(pt2, Point2::new(1.0f32, 2.0)); /// ``` - pub fn cast(self) -> Point + pub fn cast(self) -> OPoint where - Point: SupersetOf, + OPoint: SupersetOf, + DefaultAllocator: Allocator, { crate::convert(self) } @@ -138,38 +144,43 @@ impl Point { * Traits that build points. * */ -impl Bounded for Point { +impl Bounded for OPoint +where + DefaultAllocator: Allocator, +{ #[inline] fn max_value() -> Self { - Self::from(SVector::max_value()) + Self::from(OVector::max_value()) } #[inline] fn min_value() -> Self { - Self::from(SVector::min_value()) + Self::from(OVector::min_value()) } } #[cfg(feature = "rand-no-std")] -impl Distribution> for Standard +impl Distribution> for Standard where Standard: Distribution, + DefaultAllocator: Allocator, { /// Generate a `Point` where each coordinate is an independent variate from `[0, 1)`. #[inline] - fn sample<'a, G: Rng + ?Sized>(&self, rng: &mut G) -> Point { - Point::from(rng.gen::>()) + fn sample<'a, G: Rng + ?Sized>(&self, rng: &mut G) -> OPoint { + OPoint::from(rng.gen::>()) } } #[cfg(feature = "arbitrary")] -impl Arbitrary for Point +impl Arbitrary for OPoint where - >>::Buffer: Send, + >::Buffer: Send, + DefaultAllocator: Allocator, { #[inline] fn arbitrary(g: &mut Gen) -> Self { - Self::from(SVector::arbitrary(g)) + Self::from(OVector::arbitrary(g)) } } @@ -181,7 +192,7 @@ where // NOTE: the impl for Point1 is not with the others so that we // can add a section with the impl block comment. /// # Construction from individual components -impl Point1 { +impl Point1 { /// Initializes this point from its components. /// /// # Example @@ -192,7 +203,7 @@ impl Point1 { /// assert_eq!(p.x, 1.0); /// ``` #[inline] - pub const fn new(x: T) -> Self { + pub fn new(x: T) -> Self { Point { coords: Vector1::new(x), } @@ -200,13 +211,13 @@ impl Point1 { } macro_rules! componentwise_constructors_impl( ($($doc: expr; $Point: ident, $Vector: ident, $($args: ident:$irow: expr),*);* $(;)*) => {$( - impl $Point { + impl $Point { #[doc = "Initializes this point from its components."] #[doc = "# Example\n```"] #[doc = $doc] #[doc = "```"] #[inline] - pub const fn new($($args: T),*) -> Self { + pub fn new($($args: T),*) -> Self { Point { coords: $Vector::new($($args),*) } } } diff --git a/src/geometry/point_conversion.rs b/src/geometry/point_conversion.rs index e5ab8272..f35a9fc6 100644 --- a/src/geometry/point_conversion.rs +++ b/src/geometry/point_conversion.rs @@ -7,6 +7,7 @@ use crate::base::dimension::{DimNameAdd, DimNameSum, U1}; use crate::base::{Const, DefaultAllocator, Matrix, OVector, Scalar}; use crate::geometry::Point; +use crate::{DimName, OPoint}; /* * This file provides the following conversions: @@ -16,67 +17,69 @@ use crate::geometry::Point; * Point -> Vector (homogeneous) */ -impl SubsetOf> for Point +impl SubsetOf> for OPoint where T1: Scalar, T2: Scalar + SupersetOf, + DefaultAllocator: Allocator + Allocator, { #[inline] - fn to_superset(&self) -> Point { - Point::from(self.coords.to_superset()) + fn to_superset(&self) -> OPoint { + OPoint::from(self.coords.to_superset()) } #[inline] - fn is_in_subset(m: &Point) -> bool { + fn is_in_subset(m: &OPoint) -> bool { // TODO: is there a way to reuse the `.is_in_subset` from the matrix implementation of // SubsetOf? m.iter().all(|e| e.is_in_subset()) } #[inline] - fn from_superset_unchecked(m: &Point) -> Self { + fn from_superset_unchecked(m: &OPoint) -> Self { Self::from(Matrix::from_superset_unchecked(&m.coords)) } } -impl SubsetOf, U1>>> for Point +impl SubsetOf>> for OPoint where - Const: DimNameAdd, + D: DimNameAdd, T1: Scalar, T2: Scalar + Zero + One + ClosedDiv + SupersetOf, - DefaultAllocator: - Allocator, U1>> + Allocator, U1>>, + DefaultAllocator: Allocator + + Allocator + + Allocator> + + Allocator>, // + Allocator // + Allocator, { #[inline] - fn to_superset(&self) -> OVector, U1>> { - let p: Point = self.to_superset(); + fn to_superset(&self) -> OVector> { + let p: OPoint = self.to_superset(); p.to_homogeneous() } #[inline] - fn is_in_subset(v: &OVector, U1>>) -> bool { - crate::is_convertible::<_, OVector, U1>>>(v) && !v[D].is_zero() + fn is_in_subset(v: &OVector>) -> bool { + crate::is_convertible::<_, OVector>>(v) && !v[D::dim()].is_zero() } #[inline] - fn from_superset_unchecked(v: &OVector, U1>>) -> Self { - let coords = v.fixed_slice::(0, 0) / v[D].inlined_clone(); + fn from_superset_unchecked(v: &OVector>) -> Self { + let coords = v.generic_slice((0, 0), (D::name(), Const::<1>)) / v[D::dim()].inlined_clone(); Self { coords: crate::convert_unchecked(coords), } } } -impl From> - for OVector, U1>> +impl From> for OVector> where - Const: DimNameAdd, - DefaultAllocator: Allocator, U1>>, + D: DimNameAdd, + DefaultAllocator: Allocator> + Allocator, { #[inline] - fn from(t: Point) -> Self { + fn from(t: OPoint) -> Self { t.to_homogeneous() } } @@ -97,10 +100,13 @@ impl From> for [T; D] { } } -impl From>> for Point { +impl From> for OPoint +where + DefaultAllocator: Allocator, +{ #[inline] - fn from(coords: OVector>) -> Self { - Point { coords } + fn from(coords: OVector) -> Self { + OPoint { coords } } } diff --git a/src/geometry/point_coordinates.rs b/src/geometry/point_coordinates.rs index 8d9e9ccc..984a2fae 100644 --- a/src/geometry/point_coordinates.rs +++ b/src/geometry/point_coordinates.rs @@ -1,9 +1,9 @@ use std::ops::{Deref, DerefMut}; use crate::base::coordinates::{X, XY, XYZ, XYZW, XYZWA, XYZWAB}; -use crate::base::Scalar; +use crate::base::{Scalar, U1, U2, U3, U4, U5, U6}; -use crate::geometry::Point; +use crate::geometry::OPoint; /* * @@ -12,8 +12,8 @@ use crate::geometry::Point; */ macro_rules! deref_impl( - ($D: expr, $Target: ident $(, $comps: ident)*) => { - impl Deref for Point + ($D: ty, $Target: ident $(, $comps: ident)*) => { + impl Deref for OPoint { type Target = $Target; @@ -23,7 +23,7 @@ macro_rules! deref_impl( } } - impl DerefMut for Point + impl DerefMut for OPoint { #[inline] fn deref_mut(&mut self) -> &mut Self::Target { @@ -33,9 +33,9 @@ macro_rules! deref_impl( } ); -deref_impl!(1, X, x); -deref_impl!(2, XY, x, y); -deref_impl!(3, XYZ, x, y, z); -deref_impl!(4, XYZW, x, y, z, w); -deref_impl!(5, XYZWA, x, y, z, w, a); -deref_impl!(6, XYZWAB, x, y, z, w, a, b); +deref_impl!(U1, X, x); +deref_impl!(U2, XY, x, y); +deref_impl!(U3, XYZ, x, y, z); +deref_impl!(U4, XYZW, x, y, z, w); +deref_impl!(U5, XYZWA, x, y, z, w, a); +deref_impl!(U6, XYZWAB, x, y, z, w, a, b); diff --git a/src/geometry/point_ops.rs b/src/geometry/point_ops.rs index 576028cc..5b019a9d 100644 --- a/src/geometry/point_ops.rs +++ b/src/geometry/point_ops.rs @@ -8,18 +8,23 @@ use simba::scalar::{ClosedAdd, ClosedDiv, ClosedMul, ClosedNeg, ClosedSub}; use crate::base::constraint::{ AreMultipliable, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint, }; -use crate::base::dimension::{Dim, U1}; +use crate::base::dimension::{Dim, DimName, U1}; use crate::base::storage::Storage; -use crate::base::{Const, Matrix, SVector, Scalar, Vector}; +use crate::base::{Const, Matrix, OVector, Scalar, Vector}; -use crate::geometry::Point; +use crate::allocator::Allocator; +use crate::geometry::{OPoint, Point}; +use crate::DefaultAllocator; /* * * Indexing. * */ -impl Index for Point { +impl Index for OPoint +where + DefaultAllocator: Allocator, +{ type Output = T; #[inline] @@ -28,7 +33,10 @@ impl Index for Point { } } -impl IndexMut for Point { +impl IndexMut for OPoint +where + DefaultAllocator: Allocator, +{ #[inline] fn index_mut(&mut self, i: usize) -> &mut Self::Output { &mut self.coords[i] @@ -40,7 +48,10 @@ impl IndexMut for Point { * Neg. * */ -impl Neg for Point { +impl Neg for OPoint +where + DefaultAllocator: Allocator, +{ type Output = Self; #[inline] @@ -49,8 +60,11 @@ impl Neg for Point { } } -impl<'a, T: Scalar + ClosedNeg, const D: usize> Neg for &'a Point { - type Output = Point; +impl<'a, T: Scalar + ClosedNeg, D: DimName> Neg for &'a OPoint +where + DefaultAllocator: Allocator, +{ + type Output = OPoint; #[inline] fn neg(self) -> Self::Output { @@ -66,102 +80,103 @@ impl<'a, T: Scalar + ClosedNeg, const D: usize> Neg for &'a Point { // Point - Point add_sub_impl!(Sub, sub, ClosedSub; - (Const, U1), (Const, U1) -> (Const, U1) - const D; for; where; - self: &'a Point, right: &'b Point, Output = SVector; + (D, U1), (D, U1) -> (D, U1) + const; for D; where D: DimName, DefaultAllocator: Allocator; + self: &'a OPoint, right: &'b OPoint, Output = OVector; &self.coords - &right.coords; 'a, 'b); add_sub_impl!(Sub, sub, ClosedSub; - (Const, U1), (Const, U1) -> (Const, U1) - const D; for; where; - self: &'a Point, right: Point, Output = SVector; + (D, U1), (D, U1) -> (D, U1) + const; for D; where D: DimName, DefaultAllocator: Allocator; + self: &'a OPoint, right: OPoint, Output = OVector; &self.coords - right.coords; 'a); add_sub_impl!(Sub, sub, ClosedSub; - (Const, U1), (Const, U1) -> (Const, U1) - const D; for; where; - self: Point, right: &'b Point, Output = SVector; + (D, U1), (D, U1) -> (D, U1) + const; for D; where D: DimName, DefaultAllocator: Allocator; + self: OPoint, right: &'b OPoint, Output = OVector; self.coords - &right.coords; 'b); add_sub_impl!(Sub, sub, ClosedSub; - (Const, U1), (Const, U1) -> (Const, U1) - const D; for; where; - self: Point, right: Point, Output = SVector; + (D, U1), (D, U1) -> (D, U1) + const; for D; where D: DimName, DefaultAllocator: Allocator; + self: OPoint, right: OPoint, Output = OVector; self.coords - right.coords; ); // Point - Vector add_sub_impl!(Sub, sub, ClosedSub; - (Const, U1), (D2, U1) -> (Const, U1) - const D1; - for D2, SB; - where D2: Dim, SB: Storage; - self: &'a Point, right: &'b Vector, Output = Point; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: &'a OPoint, right: &'b Vector, Output = OPoint; Self::Output::from(&self.coords - right); 'a, 'b); add_sub_impl!(Sub, sub, ClosedSub; - (Const, U1), (D2, U1) -> (Const, U1) - const D1; - for D2, SB; - where D2: Dim, SB: Storage; - self: &'a Point, right: Vector, Output = Point; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: &'a OPoint, right: Vector, Output = OPoint; Self::Output::from(&self.coords - &right); 'a); // TODO: should not be a ref to `right`. add_sub_impl!(Sub, sub, ClosedSub; - (Const, U1), (D2, U1) -> (Const, U1) - const D1; - for D2, SB; - where D2: Dim, SB: Storage; - self: Point, right: &'b Vector, Output = Point; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: OPoint, right: &'b Vector, Output = OPoint; Self::Output::from(self.coords - right); 'b); add_sub_impl!(Sub, sub, ClosedSub; - (Const, U1), (D2, U1) -> (Const, U1) - const D1; - for D2, SB; - where D2: Dim, SB: Storage; - self: Point, right: Vector, Output = Point; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: OPoint, right: Vector, Output = OPoint; Self::Output::from(self.coords - right); ); // Point + Vector add_sub_impl!(Add, add, ClosedAdd; - (Const, U1), (D2, U1) -> (Const, U1) - const D1; - for D2, SB; - where D2: Dim, SB: Storage; - self: &'a Point, right: &'b Vector, Output = Point; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: &'a OPoint, right: &'b Vector, Output = OPoint; Self::Output::from(&self.coords + right); 'a, 'b); add_sub_impl!(Add, add, ClosedAdd; - (Const, U1), (D2, U1) -> (Const, U1) - const D1; - for D2, SB; - where D2: Dim, SB: Storage; - self: &'a Point, right: Vector, Output = Point; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: &'a OPoint, right: Vector, Output = OPoint; Self::Output::from(&self.coords + &right); 'a); // TODO: should not be a ref to `right`. add_sub_impl!(Add, add, ClosedAdd; - (Const, U1), (D2, U1) -> (Const, U1) - const D1; - for D2, SB; - where D2: Dim, SB: Storage; - self: Point, right: &'b Vector, Output = Point; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: OPoint, right: &'b Vector, Output = OPoint; Self::Output::from(self.coords + right); 'b); add_sub_impl!(Add, add, ClosedAdd; - (Const, U1), (D2, U1) -> (Const, U1) - const D1; - for D2, SB; - where D2: Dim, SB: Storage; - self: Point, right: Vector, Output = Point; + (D1, U1), (D2, U1) -> (D1, U1) + const; + for D1, D2, SB; + where D1: DimName, D2: Dim, SB: Storage, DefaultAllocator: Allocator; + self: OPoint, right: Vector, Output = OPoint; Self::Output::from(self.coords + right); ); // TODO: replace by the shared macro: add_sub_assign_impl? macro_rules! op_assign_impl( ($($TraitAssign: ident, $method_assign: ident, $bound: ident);* $(;)*) => {$( - impl<'b, T, D2: Dim, SB, const D1: usize> $TraitAssign<&'b Vector> for Point + impl<'b, T, D1: DimName, D2: Dim, SB> $TraitAssign<&'b Vector> for OPoint where T: Scalar + $bound, SB: Storage, - ShapeConstraint: SameNumberOfRows, D2> { + ShapeConstraint: SameNumberOfRows, + DefaultAllocator: Allocator { #[inline] fn $method_assign(&mut self, right: &'b Vector) { @@ -169,10 +184,11 @@ macro_rules! op_assign_impl( } } - impl $TraitAssign> for Point + impl $TraitAssign> for OPoint where T: Scalar + $bound, SB: Storage, - ShapeConstraint: SameNumberOfRows, D2> { + ShapeConstraint: SameNumberOfRows, + DefaultAllocator: Allocator { #[inline] fn $method_assign(&mut self, right: Vector) { @@ -214,28 +230,30 @@ md_impl_all!( macro_rules! componentwise_scalarop_impl( ($Trait: ident, $method: ident, $bound: ident; $TraitAssign: ident, $method_assign: ident) => { - impl $Trait for Point + impl $Trait for OPoint + where DefaultAllocator: Allocator { - type Output = Point; + type Output = OPoint; #[inline] fn $method(self, right: T) -> Self::Output { - Point::from(self.coords.$method(right)) + OPoint::from(self.coords.$method(right)) } } - impl<'a, T: Scalar + $bound, const D: usize> $Trait for &'a Point + impl<'a, T: Scalar + $bound, D: DimName> $Trait for &'a OPoint + where DefaultAllocator: Allocator { - type Output = Point; + type Output = OPoint; #[inline] fn $method(self, right: T) -> Self::Output { - Point::from((&self.coords).$method(right)) + OPoint::from((&self.coords).$method(right)) } } - impl $TraitAssign for Point - /* where DefaultAllocator: Allocator */ + impl $TraitAssign for OPoint + where DefaultAllocator: Allocator { #[inline] fn $method_assign(&mut self, right: T) { @@ -250,23 +268,25 @@ componentwise_scalarop_impl!(Div, div, ClosedDiv; DivAssign, div_assign); macro_rules! left_scalar_mul_impl( ($($T: ty),* $(,)*) => {$( - impl Mul> for $T + impl Mul> for $T + where DefaultAllocator: Allocator<$T, D> { - type Output = Point<$T, D>; + type Output = OPoint<$T, D>; #[inline] - fn mul(self, right: Point<$T, D>) -> Self::Output { - Point::from(self * right.coords) + fn mul(self, right: OPoint<$T, D>) -> Self::Output { + OPoint::from(self * right.coords) } } - impl<'b, const D: usize> Mul<&'b Point<$T, D>> for $T + impl<'b, D: DimName> Mul<&'b OPoint<$T, D>> for $T + where DefaultAllocator: Allocator<$T, D> { - type Output = Point<$T, D>; + type Output = OPoint<$T, D>; #[inline] - fn mul(self, right: &'b Point<$T, D>) -> Self::Output { - Point::from(self * &right.coords) + fn mul(self, right: &'b OPoint<$T, D>) -> Self::Output { + OPoint::from(self * &right.coords) } } )*} diff --git a/src/geometry/quaternion.rs b/src/geometry/quaternion.rs index 79fda90a..3449f1ae 100755 --- a/src/geometry/quaternion.rs +++ b/src/geometry/quaternion.rs @@ -139,7 +139,7 @@ mod rkyv_impl { impl, S: Fallible + ?Sized> Serialize for Quaternion { fn serialize(&self, serializer: &mut S) -> Result { - Ok(self.coords.serialize(serializer)?) + self.coords.serialize(serializer) } } @@ -1478,7 +1478,7 @@ where /// ``` #[inline] #[must_use] - pub fn to_rotation_matrix(&self) -> Rotation { + pub fn to_rotation_matrix(self) -> Rotation { let i = self.as_ref()[0]; let j = self.as_ref()[1]; let k = self.as_ref()[2]; @@ -1513,7 +1513,7 @@ where /// The angles are produced in the form (roll, pitch, yaw). #[inline] #[deprecated(note = "This is renamed to use `.euler_angles()`.")] - pub fn to_euler_angles(&self) -> (T, T, T) + pub fn to_euler_angles(self) -> (T, T, T) where T: RealField, { @@ -1561,7 +1561,7 @@ where /// ``` #[inline] #[must_use] - pub fn to_homogeneous(&self) -> Matrix4 { + pub fn to_homogeneous(self) -> Matrix4 { self.to_rotation_matrix().to_homogeneous() } diff --git a/src/geometry/quaternion_construction.rs b/src/geometry/quaternion_construction.rs index f110e3dd..7a681bb2 100644 --- a/src/geometry/quaternion_construction.rs +++ b/src/geometry/quaternion_construction.rs @@ -171,7 +171,7 @@ where Standard: Distribution, { #[inline] - fn sample<'a, R: Rng + ?Sized>(&self, rng: &'a mut R) -> Quaternion { + fn sample(&self, rng: &mut R) -> Quaternion { Quaternion::new(rng.gen(), rng.gen(), rng.gen(), rng.gen()) } } @@ -535,10 +535,10 @@ where SC: Storage, { // TODO: code duplication with Rotation. - let c = na.cross(&nb); + let c = na.cross(nb); if let Some(axis) = Unit::try_new(c, T::default_epsilon()) { - let cos = na.dot(&nb); + let cos = na.dot(nb); // The cosinus may be out of [-1, 1] because of inaccuracies. if cos <= -T::one() { @@ -548,7 +548,7 @@ where } else { Some(Self::from_axis_angle(&axis, cos.acos() * s)) } - } else if na.dot(&nb) < T::zero() { + } else if na.dot(nb) < T::zero() { // PI // // The rotation axis is undefined but the angle not zero. This is not a @@ -860,7 +860,7 @@ where { /// Generate a uniformly distributed random rotation quaternion. #[inline] - fn sample<'a, R: Rng + ?Sized>(&self, rng: &'a mut R) -> UnitQuaternion { + fn sample(&self, rng: &mut R) -> UnitQuaternion { // Ken Shoemake's Subgroup Algorithm // Uniform random rotations. // In D. Kirk, editor, Graphics Gems III, pages 124-132. Academic, New York, 1992. diff --git a/src/geometry/reflection.rs b/src/geometry/reflection.rs index dcc754c2..87166b81 100644 --- a/src/geometry/reflection.rs +++ b/src/geometry/reflection.rs @@ -1,5 +1,5 @@ use crate::base::constraint::{AreMultipliable, DimEq, SameNumberOfRows, ShapeConstraint}; -use crate::base::{Const, Matrix, Scalar, Unit, Vector}; +use crate::base::{Const, Matrix, Unit, Vector}; use crate::dimension::{Dim, U1}; use crate::storage::{Storage, StorageMut}; use simba::scalar::ComplexField; @@ -7,7 +7,7 @@ use simba::scalar::ComplexField; use crate::geometry::Point; /// A reflection wrt. a plane. -pub struct Reflection> { +pub struct Reflection { axis: Vector, bias: T, } @@ -90,7 +90,7 @@ impl> Reflection { } let m_two: T = crate::convert(-2.0f64); - lhs.gerc(m_two, &work, &self.axis, T::one()); + lhs.gerc(m_two, work, &self.axis, T::one()); } /// Applies the reflection to the rows of `lhs`. @@ -111,6 +111,6 @@ impl> Reflection { } let m_two = sign.scale(crate::convert(-2.0f64)); - lhs.gerc(m_two, &work, &self.axis, sign); + lhs.gerc(m_two, work, &self.axis, sign); } } diff --git a/src/geometry/rotation.rs b/src/geometry/rotation.rs index 6fd9e803..4e27c0aa 100755 --- a/src/geometry/rotation.rs +++ b/src/geometry/rotation.rs @@ -55,7 +55,7 @@ use crate::geometry::Point; /// #[repr(C)] #[derive(Debug)] -pub struct Rotation { +pub struct Rotation { matrix: SMatrix, } @@ -215,9 +215,9 @@ impl Rotation { /// A mutable reference to the underlying matrix representation of this rotation. /// - /// This is suffixed by "_unchecked" because this allows the user to replace the matrix by another one that is - /// non-square, non-inversible, or non-orthonormal. If one of those properties is broken, - /// subsequent method calls may be UB. + /// This is suffixed by "_unchecked" because this allows the user to replace the + /// matrix by another one that is non-inversible or non-orthonormal. If one of + /// those properties is broken, subsequent method calls may return bogus results. #[inline] pub fn matrix_mut_unchecked(&mut self) -> &mut SMatrix { &mut self.matrix diff --git a/src/geometry/rotation_specialization.rs b/src/geometry/rotation_specialization.rs index 6c9ecf21..2ad73c69 100644 --- a/src/geometry/rotation_specialization.rs +++ b/src/geometry/rotation_specialization.rs @@ -274,7 +274,7 @@ where { /// Generate a uniformly distributed random rotation. #[inline] - fn sample<'a, R: Rng + ?Sized>(&self, rng: &'a mut R) -> Rotation2 { + fn sample(&self, rng: &mut R) -> Rotation2 { let twopi = Uniform::new(T::zero(), T::simd_two_pi()); Rotation2::new(rng.sample(twopi)) } @@ -883,7 +883,7 @@ impl Rotation3 { /// /// The angles are produced in the form (roll, pitch, yaw). #[deprecated(note = "This is renamed to use `.euler_angles()`.")] - pub fn to_euler_angles(&self) -> (T, T, T) + pub fn to_euler_angles(self) -> (T, T, T) where T: RealField, { diff --git a/src/geometry/similarity.rs b/src/geometry/similarity.rs index 48ce6a85..19164439 100755 --- a/src/geometry/similarity.rs +++ b/src/geometry/similarity.rs @@ -27,19 +27,19 @@ use crate::geometry::{AbstractRotation, Isometry, Point, Translation}; #[cfg_attr(feature = "serde-serialize-no-std", derive(Serialize, Deserialize))] #[cfg_attr( feature = "serde-serialize-no-std", - serde(bound(serialize = "T: Serialize, + serde(bound(serialize = "T: Scalar + Serialize, R: Serialize, DefaultAllocator: Allocator>, Owned>: Serialize")) )] #[cfg_attr( feature = "serde-serialize-no-std", - serde(bound(deserialize = "T: Deserialize<'de>, + serde(bound(deserialize = "T: Scalar + Deserialize<'de>, R: Deserialize<'de>, DefaultAllocator: Allocator>, Owned>: Deserialize<'de>")) )] -pub struct Similarity { +pub struct Similarity { /// The part of this similarity that does not include the scaling factor. pub isometry: Isometry, scaling: T, diff --git a/src/geometry/transform.rs b/src/geometry/transform.rs index 51a8f64d..435bac59 100755 --- a/src/geometry/transform.rs +++ b/src/geometry/transform.rs @@ -1,6 +1,7 @@ use approx::{AbsDiffEq, RelativeEq, UlpsEq}; use std::any::Any; use std::fmt::Debug; +use std::hash; use std::marker::PhantomData; #[cfg(feature = "serde-serialize-no-std")] @@ -166,14 +167,16 @@ where _phantom: PhantomData, } -// TODO -// impl + hash::Hash, C: TCategory> hash::Hash for Transform -// where DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, -// Owned, U1>, DimNameSum, U1>>: hash::Hash { -// fn hash(&self, state: &mut H) { -// self.matrix.hash(state); -// } -// } +impl hash::Hash for Transform +where + Const: DimNameAdd, + DefaultAllocator: Allocator, U1>, DimNameSum, U1>>, + Owned, U1>, DimNameSum, U1>>: hash::Hash, +{ + fn hash(&self, state: &mut H) { + self.matrix.hash(state); + } +} impl Copy for Transform where diff --git a/src/geometry/transform_ops.rs b/src/geometry/transform_ops.rs index efbfa67b..c4ec5cfc 100644 --- a/src/geometry/transform_ops.rs +++ b/src/geometry/transform_ops.rs @@ -124,7 +124,7 @@ md_impl_all!( if C::has_normalizer() { let normalizer = self.matrix().fixed_slice::<1, D>(D, 0); - let n = normalizer.tr_dot(&rhs); + let n = normalizer.tr_dot(rhs); if !n.is_zero() { return transform * (rhs / n); diff --git a/src/geometry/translation.rs b/src/geometry/translation.rs index 7de9bb04..f1ff88db 100755 --- a/src/geometry/translation.rs +++ b/src/geometry/translation.rs @@ -139,7 +139,7 @@ mod rkyv_impl { impl, S: Fallible + ?Sized, const D: usize> Serialize for Translation { fn serialize(&self, serializer: &mut S) -> Result { - Ok(self.vector.serialize(serializer)?) + self.vector.serialize(serializer) } } diff --git a/src/geometry/translation_construction.rs b/src/geometry/translation_construction.rs index c6e9d7d3..5371b648 100644 --- a/src/geometry/translation_construction.rs +++ b/src/geometry/translation_construction.rs @@ -69,7 +69,7 @@ where { /// Generate an arbitrary random variate for testing purposes. #[inline] - fn sample<'a, G: Rng + ?Sized>(&self, rng: &'a mut G) -> Translation { + fn sample(&self, rng: &mut G) -> Translation { Translation::from(rng.gen::>()) } } diff --git a/src/geometry/unit_complex.rs b/src/geometry/unit_complex.rs index be0c8980..d6a7316c 100755 --- a/src/geometry/unit_complex.rs +++ b/src/geometry/unit_complex.rs @@ -261,7 +261,7 @@ where /// ``` #[inline] #[must_use] - pub fn to_rotation_matrix(&self) -> Rotation2 { + pub fn to_rotation_matrix(self) -> Rotation2 { let r = self.re; let i = self.im; @@ -282,7 +282,7 @@ where /// ``` #[inline] #[must_use] - pub fn to_homogeneous(&self) -> Matrix3 { + pub fn to_homogeneous(self) -> Matrix3 { self.to_rotation_matrix().to_homogeneous() } } diff --git a/src/geometry/unit_complex_construction.rs b/src/geometry/unit_complex_construction.rs index 16e605f2..a86b2277 100644 --- a/src/geometry/unit_complex_construction.rs +++ b/src/geometry/unit_complex_construction.rs @@ -383,8 +383,8 @@ where SB: Storage, SC: Storage, { - let sang = na.perp(&nb); - let cang = na.dot(&nb); + let sang = na.perp(nb); + let cang = na.dot(nb); Self::from_angle(sang.simd_atan2(cang) * s) } diff --git a/src/lib.rs b/src/lib.rs index 04bc4002..c5c4dcd8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,7 +14,7 @@ and the official package manager: [cargo](https://github.com/rust-lang/cargo). Simply add the following to your `Cargo.toml` file: -```.ignore +```ignore [dependencies] // TODO: replace the * by the latest version. nalgebra = "*" @@ -26,7 +26,7 @@ Most useful functionalities of **nalgebra** are grouped in the root module `nalg However, the recommended way to use **nalgebra** is to import types and traits explicitly, and call free-functions using the `na::` prefix: -```.rust +``` #[macro_use] extern crate approx; // For the macro relative_eq! extern crate nalgebra as na; @@ -87,7 +87,6 @@ an optimized set of tools for computer graphics and physics. Those features incl html_root_url = "https://docs.rs/nalgebra/0.25.0" )] #![cfg_attr(not(feature = "std"), no_std)] -#![cfg_attr(all(feature = "alloc", not(feature = "std")), feature(alloc))] #![cfg_attr(feature = "no_unsound_assume_init", allow(unreachable_code))] #[cfg(feature = "rand-no-std")] @@ -102,6 +101,7 @@ extern crate approx; extern crate num_traits as num; #[cfg(all(feature = "alloc", not(feature = "std")))] +#[cfg_attr(test, macro_use)] extern crate alloc; #[cfg(not(feature = "std"))] diff --git a/src/linalg/householder.rs b/src/linalg/householder.rs index fbb24e77..9314ee45 100644 --- a/src/linalg/householder.rs +++ b/src/linalg/householder.rs @@ -98,7 +98,7 @@ pub fn clear_row_unchecked( reflection_norm.signum().conjugate(), ); top.columns_range_mut(irow + shift..) - .tr_copy_from(&refl.axis()); + .tr_copy_from(refl.axis()); } else { top.columns_range_mut(irow + shift..).tr_copy_from(&axis); } diff --git a/src/proptest/mod.rs b/src/proptest/mod.rs index d85cd6a2..794080fe 100644 --- a/src/proptest/mod.rs +++ b/src/proptest/mod.rs @@ -27,7 +27,7 @@ //! In `proptest`, it is usually preferable to have free functions that generate *strategies*. //! Currently, the [matrix](fn.matrix.html) function fills this role. The analogous function for //! column vectors is [vector](fn.vector.html). Let's take a quick look at how it may be used: -//! ```rust +//! ``` //! use nalgebra::proptest::matrix; //! use proptest::prelude::*; //! @@ -52,7 +52,7 @@ //! number of columns to vary. One way to do this is to use `proptest` combinators in combination //! with [matrix](fn.matrix.html) as follows: //! -//! ```rust +//! ``` //! use nalgebra::{Dynamic, OMatrix, Const}; //! use nalgebra::proptest::matrix; //! use proptest::prelude::*; @@ -92,7 +92,7 @@ //! //! If you don't care about the dimensions of matrices, you can write tests like these: //! -//! ```rust +//! ``` //! use nalgebra::{DMatrix, DVector, Dynamic, Matrix3, OMatrix, Vector3, U3}; //! use proptest::prelude::*; //! diff --git a/src/sparse/cs_matrix.rs b/src/sparse/cs_matrix.rs index 74e13719..cdacd044 100644 --- a/src/sparse/cs_matrix.rs +++ b/src/sparse/cs_matrix.rs @@ -31,11 +31,9 @@ impl<'a, T: Clone> Iterator for ColumnEntries<'a, T> { if self.curr >= self.i.len() { None } else { - let res = Some( - (unsafe { self.i.get_unchecked(self.curr).clone() }, unsafe { - self.v.get_unchecked(self.curr).clone() - }), - ); + let res = Some((unsafe { *self.i.get_unchecked(self.curr) }, unsafe { + self.v.get_unchecked(self.curr).clone() + })); self.curr += 1; res } @@ -80,10 +78,12 @@ pub trait CsStorage: for<'a> CsStorageIter<'a, T, R, C> { fn shape(&self) -> (R, C); /// Retrieve the i-th row index of the underlying row index buffer. /// + /// # Safety /// No bound-checking is performed. unsafe fn row_index_unchecked(&self, i: usize) -> usize; /// The i-th value on the contiguous value buffer of this storage. /// + /// # Safety /// No bound-checking is performed. unsafe fn get_value_unchecked(&self, i: usize) -> &T; /// The i-th value on the contiguous value buffer of this storage. @@ -155,7 +155,7 @@ where #[inline] fn column_row_indices(&'a self, j: usize) -> Self::ColumnRowIndices { let rng = self.column_range(j); - self.i[rng.clone()].iter().cloned() + self.i[rng].iter().cloned() } } @@ -489,7 +489,7 @@ where // Sort the index vector. let range = self.data.column_range(j); - self.data.i[range.clone()].sort(); + self.data.i[range.clone()].sort_unstable(); // Permute the values too. for (i, irow) in range.clone().zip(self.data.i[range].iter().cloned()) { diff --git a/src/sparse/cs_matrix_ops.rs b/src/sparse/cs_matrix_ops.rs index e9daa4ae..e03b12a5 100644 --- a/src/sparse/cs_matrix_ops.rs +++ b/src/sparse/cs_matrix_ops.rs @@ -271,7 +271,7 @@ where // Keep the output sorted. let range = res.data.p[j]..nz; - res.data.i[range.clone()].sort(); + res.data.i[range.clone()].sort_unstable(); for p in range { res.data.vals[p] = workspace[res.data.i[p]].inlined_clone() diff --git a/src/sparse/cs_matrix_solve.rs b/src/sparse/cs_matrix_solve.rs index 43c5c2c7..235fcef3 100644 --- a/src/sparse/cs_matrix_solve.rs +++ b/src/sparse/cs_matrix_solve.rs @@ -63,7 +63,7 @@ impl> CsMatrix { let mut column = self.data.column_entries(j); let mut diag_found = false; - while let Some((i, val)) = column.next() { + for (i, val) in &mut column { if i == j { if val.is_zero() { return false; @@ -109,7 +109,7 @@ impl> CsMatrix { let mut column = self.data.column_entries(j); let mut diag = None; - while let Some((i, val)) = column.next() { + for (i, val) in &mut column { if i == j { if val.is_zero() { return false; @@ -151,7 +151,7 @@ impl> CsMatrix { // We don't compute a postordered reach here because it will be sorted after anyway. self.lower_triangular_reach(b, &mut reach); // We sort the reach so the result matrix has sorted indices. - reach.sort(); + reach.sort_unstable(); let mut workspace = unsafe { crate::unimplemented_or_uninitialized_generic!(b.data.shape().0, Const::<1>) }; @@ -167,7 +167,7 @@ impl> CsMatrix { let mut column = self.data.column_entries(j); let mut diag_found = false; - while let Some((i, val)) = column.next() { + for (i, val) in &mut column { if i == j { if val.is_zero() { break; diff --git a/src/third_party/alga/alga_dual_quaternion.rs b/src/third_party/alga/alga_dual_quaternion.rs index d6a5861e..bc07cfa4 100644 --- a/src/third_party/alga/alga_dual_quaternion.rs +++ b/src/third_party/alga/alga_dual_quaternion.rs @@ -267,12 +267,12 @@ impl AffineTransformation> #[inline] fn append_translation(&self, translation: &Self::Translation) -> Self { - self * Self::from_parts(translation.clone(), UnitQuaternion::identity()) + self * Self::from_parts(*translation, UnitQuaternion::identity()) } #[inline] fn prepend_translation(&self, translation: &Self::Translation) -> Self { - Self::from_parts(translation.clone(), UnitQuaternion::identity()) * self + Self::from_parts(*translation, UnitQuaternion::identity()) * self } #[inline] @@ -287,12 +287,12 @@ impl AffineTransformation> #[inline] fn append_scaling(&self, _: &Self::NonUniformScaling) -> Self { - self.clone() + *self } #[inline] fn prepend_scaling(&self, _: &Self::NonUniformScaling) -> Self { - self.clone() + *self } } diff --git a/src/third_party/alga/alga_matrix.rs b/src/third_party/alga/alga_matrix.rs index 0ddd4fdf..e55ba49e 100644 --- a/src/third_party/alga/alga_matrix.rs +++ b/src/third_party/alga/alga_matrix.rs @@ -272,12 +272,12 @@ where match Self::dimension() { 1 => { - if vs.len() == 0 { + if vs.is_empty() { let _ = f(&Self::canonical_basis_element(0)); } } 2 => { - if vs.len() == 0 { + if vs.is_empty() { let _ = f(&Self::canonical_basis_element(0)) && f(&Self::canonical_basis_element(1)); } else if vs.len() == 1 { @@ -290,7 +290,7 @@ where // Otherwise, nothing. } 3 => { - if vs.len() == 0 { + if vs.is_empty() { let _ = f(&Self::canonical_basis_element(0)) && f(&Self::canonical_basis_element(1)) && f(&Self::canonical_basis_element(2)); diff --git a/src/third_party/alga/alga_point.rs b/src/third_party/alga/alga_point.rs index f1365af4..b1919bb6 100644 --- a/src/third_party/alga/alga_point.rs +++ b/src/third_party/alga/alga_point.rs @@ -23,7 +23,7 @@ impl EuclideanSpace for #[inline] fn coordinates(&self) -> Self::Coordinates { - self.coords.clone() + self.coords } #[inline] diff --git a/src/third_party/alga/alga_quaternion.rs b/src/third_party/alga/alga_quaternion.rs index 0885f44f..7282e0f1 100755 --- a/src/third_party/alga/alga_quaternion.rs +++ b/src/third_party/alga/alga_quaternion.rs @@ -144,11 +144,7 @@ impl NormedSpace for Quaternion { #[inline] fn try_normalize(&self, min_norm: T) -> Option { - if let Some(v) = self.coords.try_normalize(min_norm) { - Some(Self::from(v)) - } else { - None - } + self.coords.try_normalize(min_norm).map(Self::from) } #[inline] @@ -234,17 +230,17 @@ impl AffineTransformation> #[inline] fn decompose(&self) -> (Id, Self, Id, Self) { - (Id::new(), self.clone(), Id::new(), Self::identity()) + (Id::new(), *self, Id::new(), Self::identity()) } #[inline] fn append_translation(&self, _: &Self::Translation) -> Self { - self.clone() + *self } #[inline] fn prepend_translation(&self, _: &Self::Translation) -> Self { - self.clone() + *self } #[inline] @@ -259,12 +255,12 @@ impl AffineTransformation> #[inline] fn append_scaling(&self, _: &Self::NonUniformScaling) -> Self { - self.clone() + *self } #[inline] fn prepend_scaling(&self, _: &Self::NonUniformScaling) -> Self { - self.clone() + *self } } @@ -278,7 +274,7 @@ impl Similarity> for UnitQuat #[inline] fn rotation(&self) -> Self { - self.clone() + *self } #[inline] diff --git a/src/third_party/alga/alga_translation.rs b/src/third_party/alga/alga_translation.rs index bca6d13f..76a68355 100755 --- a/src/third_party/alga/alga_translation.rs +++ b/src/third_party/alga/alga_translation.rs @@ -79,7 +79,7 @@ impl Transformation) -> SVector { - v.clone() + *v } } @@ -93,7 +93,7 @@ impl ProjectiveTransfor #[inline] fn inverse_transform_vector(&self, v: &SVector) -> SVector { - v.clone() + *v } } @@ -176,7 +176,7 @@ impl AlgaTranslation SVector { - self.vector.clone() + self.vector } #[inline] @@ -186,7 +186,7 @@ impl AlgaTranslation Option { - Some(Self::from(&self.vector * n)) + Some(Self::from(self.vector * n)) } #[inline] diff --git a/src/third_party/alga/alga_unit_complex.rs b/src/third_party/alga/alga_unit_complex.rs index 44dadb42..ca55691b 100755 --- a/src/third_party/alga/alga_unit_complex.rs +++ b/src/third_party/alga/alga_unit_complex.rs @@ -90,17 +90,17 @@ impl AffineTransformation> fo #[inline] fn decompose(&self) -> (Id, Self, Id, Self) { - (Id::new(), self.clone(), Id::new(), Self::identity()) + (Id::new(), *self, Id::new(), Self::identity()) } #[inline] fn append_translation(&self, _: &Self::Translation) -> Self { - self.clone() + *self } #[inline] fn prepend_translation(&self, _: &Self::Translation) -> Self { - self.clone() + *self } #[inline] @@ -115,12 +115,12 @@ impl AffineTransformation> fo #[inline] fn append_scaling(&self, _: &Self::NonUniformScaling) -> Self { - self.clone() + *self } #[inline] fn prepend_scaling(&self, _: &Self::NonUniformScaling) -> Self { - self.clone() + *self } } @@ -134,7 +134,7 @@ impl Similarity> for UnitComp #[inline] fn rotation(&self) -> Self { - self.clone() + *self } #[inline] diff --git a/tests/core/matrix.rs b/tests/core/matrix.rs index 7befd351..eaa252db 100644 --- a/tests/core/matrix.rs +++ b/tests/core/matrix.rs @@ -1108,3 +1108,31 @@ fn partial_eq_different_types() { // assert_ne!(static_mat, typenum_static_mat); //assert_ne!(typenum_static_mat, static_mat); } + +fn generic_omatrix_to_string( + vector: &nalgebra::OVector, + matrix: &nalgebra::OMatrix, +) -> (String, String) +where + D: nalgebra::Dim, + nalgebra::DefaultAllocator: nalgebra::base::allocator::Allocator, + nalgebra::DefaultAllocator: nalgebra::base::allocator::Allocator, +{ + (vector.to_string(), matrix.to_string()) +} + +#[test] +fn omatrix_to_string() { + let dvec: nalgebra::DVector = nalgebra::dvector![1.0, 2.0]; + let dmatr: nalgebra::DMatrix = nalgebra::dmatrix![1.0, 2.0; 3.0, 4.0]; + let svec: nalgebra::SVector = nalgebra::vector![1.0, 2.0]; + let smatr: nalgebra::SMatrix = nalgebra::matrix![1.0, 2.0; 3.0, 4.0]; + assert_eq!( + generic_omatrix_to_string(&dvec, &dmatr), + (dvec.to_string(), dmatr.to_string()) + ); + assert_eq!( + generic_omatrix_to_string(&svec, &smatr), + (svec.to_string(), smatr.to_string()) + ); +}