From 465fc2625dbc1ccbaa44de7f5e88503325893085 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 4 Jan 2026 13:43:19 -0500 Subject: [PATCH 1/6] Add a `Dimensionality` trait behind `unstable` feature flag --- Cargo.toml | 2 + src/layout/dimensionality.rs | 243 +++++++++++++++++++++++++++++++++++ src/layout/mod.rs | 2 + 3 files changed, 247 insertions(+) create mode 100644 src/layout/dimensionality.rs diff --git a/Cargo.toml b/Cargo.toml index efc035f00..12560040f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -74,6 +74,8 @@ matrixmultiply-threading = ["matrixmultiply/threading"] portable-atomic-critical-section = ["portable-atomic/critical-section"] +unstable = [] + [target.'cfg(not(target_has_atomic = "ptr"))'.dependencies] portable-atomic = { version = "1.6.0" } diff --git a/src/layout/dimensionality.rs b/src/layout/dimensionality.rs new file mode 100644 index 000000000..3e34aa99b --- /dev/null +++ b/src/layout/dimensionality.rs @@ -0,0 +1,243 @@ +use core::fmt::Debug; + +/// A trait representing a dimensionality, i.e., an unsigned integer indicating how many axes an array has. +/// +/// `ndarray` encodes an array’s dimensionality in the type system when possible, which is useful for +/// debugging and for writing generic array code. However, some operations produce arrays whose +/// dimensionality cannot be known at compile time. This trait provides a common abstraction for both +/// statically known and dynamic dimensionalities. +/// +/// Compile-time dimensionalities are currently supported for values from 0 to 12, inclusive. +/// Any dimensionality above 12 must be represented with [`DDyn`], even if it is known at compile time. +/// See [`NDim`] and [`DDyn`] for guidance on choosing between static and dynamic dimensionalities. +/// +/// ## Dynamic dimensionalities +/// A type implementing `Dimensionality` does not expose its dimensionality as a runtime value. +/// In dynamic cases, `DDyn` means that the dimensionality is not known at compile time. +/// The actual number of axes is taken directly from the array’s shape. +pub trait Dimensionality: + Copy + + Eq + + Debug + + Send + + Sync + + DMax + + DMax + + DMax + + DMax + + DMax + + DAdd + + DAdd + + DAdd + + DAdd + + DAdd +{ + /// The dimensionality as a constant usize, if it's not dynamic. + const N: Option; + + type Smaller: Dimensionality; + + type Larger: Dimensionality; // And more +} + +pub trait DAdd +{ + type Output: Dimensionality; +} + +pub trait DMax +{ + type Output: Dimensionality; +} + +/// The N-dimensional static dimensionality. +/// +/// This type indicates dimensionalities that are known at compile-time. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct NDim; + +pub type D0 = NDim<0>; +pub type D1 = NDim<1>; +pub type D2 = NDim<2>; +pub type D3 = NDim<3>; +pub type D4 = NDim<4>; +pub type D5 = NDim<5>; +pub type D6 = NDim<6>; +pub type D7 = NDim<7>; +pub type D8 = NDim<8>; +pub type D9 = NDim<9>; +pub type D10 = NDim<10>; +pub type D11 = NDim<11>; +pub type D12 = NDim<12>; + +macro_rules! impl_add { + ($left:literal, ($($right:literal),*), ddyn: ($($rightd:literal),*)) => { + $( + impl DAdd> for NDim<$left> + { + type Output = NDim<{$left + $right}>; + } + )* + + $( + impl DAdd> for NDim<$left> + { + type Output = DDyn; + } + )* + }; +} + +// There's got to be a macro way to do this in one line to help with +// any future additions of extra dimenions, although it might +// also slow down compile times. +impl_add!(0, (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), ddyn: ()); +impl_add!(1, (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), ddyn: (12)); +impl_add!(2, (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), ddyn: (11, 12)); +impl_add!(3, (1, 2, 3, 4, 5, 6, 7, 8, 9), ddyn: (10, 11, 12)); +impl_add!(4, (1, 2, 3, 4, 5, 6, 7, 8), ddyn: (9, 10, 11, 12)); +impl_add!(5, (1, 2, 3, 4, 5, 6, 7), ddyn: (8, 9, 10, 11, 12)); +impl_add!(6, (1, 2, 3, 4, 5, 6), ddyn: (7, 8, 9, 10, 11, 12)); +impl_add!(7, (1, 2, 3, 4, 5), ddyn: (6, 7, 8, 9, 10, 11, 12)); +impl_add!(8, (1, 2, 3, 4), ddyn: (5, 6, 7, 8, 9, 10, 11, 12)); +impl_add!(9, (1, 2, 3), ddyn: (4, 5, 6, 7, 8, 9, 10, 11, 12)); +impl_add!(10, (1, 2), ddyn: (3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); +impl_add!(11, (1), ddyn: (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); +impl_add!(12, (), ddyn: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); + +macro_rules! impl_max { + // Base case, just a target with some lowers + ($($lower:literal),+, target: $target:literal) => { + $( + impl DMax> for NDim<$target> + { + type Output = NDim<$target>; + } + )+ + }; + // General case: at least one lower, at least one upper + ($($lower:literal),+$(,)? target: $target:literal, $first_upper:literal$(, $($upper:literal),+)?) => { + $( + impl DMax> for NDim<$target> + { + type Output = NDim<$target>; + } + )+ + impl DMax> for NDim<$target> + { + type Output = NDim<$first_upper>; + } + $( + $( + impl DMax> for NDim<$target> + { + type Output = NDim<$upper>; + } + )+ + )? + impl_max!($($lower),+, $target, target: $first_upper$(, $($upper),+)?); + }; + // Helper syntax: zero lowers, target, at least one upper + (target: $target:literal, $first_upper:literal, $($upper:literal),+) => { + impl DMax> for NDim<$target> + { + type Output = NDim<$first_upper>; + } + $( + impl DMax> for NDim<$target> + { + type Output = NDim<$upper>; + } + )+ + impl_max!($target, target: $first_upper, $($upper),+); + }; +} + +impl_max!(target: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); + +impl DMax> for NDim +where NDim: Dimensionality +{ + type Output = Self; +} + +macro_rules! impl_dimensionality { + ($($d:literal),+) => { + $( + impl Dimensionality for NDim<$d> + { + const N: Option = Some($d); + + type Smaller = NDim<{$d - 1}>; + + type Larger = NDim<{$d + 1}>; + } + )+ + }; +} + +impl Dimensionality for D1 +{ + const N: Option = Some(1); + + type Smaller = Self; + + type Larger = D2; +} + +impl_dimensionality!(2, 3, 4, 5, 6, 7, 8, 9, 10, 11); + +impl Dimensionality for NDim<12> +{ + const N: Option = Some(12); + + type Smaller = D11; + + type Larger = DDyn; +} + +/// The dynamic dimensionality. +/// +/// This type indicates dimensionalities that can only be known at runtime. +/// See [`Dimensionality`] for more information. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +pub struct DDyn; + +impl Dimensionality for DDyn +{ + const N: Option = None; + + type Smaller = Self; + + type Larger = Self; +} + +impl DAdd for DDyn +{ + type Output = DDyn; +} + +impl DAdd> for DDyn +{ + type Output = DDyn; +} + +impl DAdd for NDim +{ + type Output = DDyn; +} + +impl DMax for DDyn +{ + type Output = DDyn; +} + +impl DMax> for DDyn +{ + type Output = DDyn; +} + +impl DMax for NDim +{ + type Output = DDyn; +} diff --git a/src/layout/mod.rs b/src/layout/mod.rs index 7f549ebb2..c126d388a 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1,4 +1,6 @@ mod bitset; +#[cfg(feature = "unstable")] +mod dimensionality; #[allow(deprecated)] pub use bitset::{Layout, LayoutBitset}; From 55e0e94f2290da43e61823969965e241e27269a1 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 4 Jan 2026 16:08:51 -0500 Subject: [PATCH 2/6] Add docs and reintroduce the zero-dimensional type --- src/layout/dimensionality.rs | 158 +++++++++++++++++++++++++++-------- src/layout/mod.rs | 12 ++- src/lib.rs | 2 +- 3 files changed, 134 insertions(+), 38 deletions(-) diff --git a/src/layout/dimensionality.rs b/src/layout/dimensionality.rs index 3e34aa99b..2cfa7e286 100644 --- a/src/layout/dimensionality.rs +++ b/src/layout/dimensionality.rs @@ -1,3 +1,10 @@ +//! Type-level representations of array dimensionality. +//! +//! This module defines the [`Dimensionality`] trait and related types used to represent +//! the number of axes an array has, either at compile time ([`NDim`]) or dynamically +//! ([`DDyn`]). These types support basic type-level operations such as addition and +//! maximum, which are used to model array operations like concatenation and broadcasting. + use core::fmt::Debug; /// A trait representing a dimensionality, i.e., an unsigned integer indicating how many axes an array has. @@ -9,7 +16,8 @@ use core::fmt::Debug; /// /// Compile-time dimensionalities are currently supported for values from 0 to 12, inclusive. /// Any dimensionality above 12 must be represented with [`DDyn`], even if it is known at compile time. -/// See [`NDim`] and [`DDyn`] for guidance on choosing between static and dynamic dimensionalities. +/// +/// The `Smaller` and `Larger` associated types allow users to move to adjacent dimensionalities at the type level. /// /// ## Dynamic dimensionalities /// A type implementing `Dimensionality` does not expose its dimensionality as a runtime value. @@ -21,7 +29,7 @@ pub trait Dimensionality: + Debug + Send + Sync - + DMax + + DMax + DMax + DMax + DMax @@ -29,47 +37,120 @@ pub trait Dimensionality: + DAdd + DAdd + DAdd + + DAdd + DAdd + DAdd { - /// The dimensionality as a constant usize, if it's not dynamic. + /// The dimensionality as a constant `usize`, or `None` if it is dynamic. const N: Option; + /// The next-smaller possible dimensionality. + /// + /// For the smallest possible dimensionality (currently 0-dimensional), there + /// is of course no "smaller" dimensionality. Instead, `NDim::<0>::Smaller` just + /// refers back to `NDim<0>`; in other words, it uses a "base case" of 0-dimensionality. type Smaller: Dimensionality; - type Larger: Dimensionality; // And more + /// The next-larger dimensionality. + /// + /// For the largest compile-time dimensionality (currently 12-dimensional), there + /// is no "larger" compile-time dimensionality. Instead, `NDim::<12>::Larger` just + /// refers to `DDyn`; in other words, it "escapes" to a dynamically-determined dimensionality. + type Larger: Dimensionality; } +/// Adds two dimensionalities at compile time. +/// +/// The addition of a constant dimensionality with a dynamic dimensionality +/// will always result in a dynamic dimensionality, effectively "erasing" +/// the compile-time knowledge. +/// +/// This type is analogous to the existing [`crate::DimAdd`], but specifically +/// for dimensionality instead of `Dimension` types. +/// +/// ## Example +/// ``` +/// use ndarray::layout::dimensionality::*; +/// use core::any::TypeId; +/// +/// type Added = >::Output; +/// assert_eq!(TypeId::of::(), TypeId::of::()); +/// +/// type AddedDyn = >::Output; +/// assert_eq!(TypeId::of::(), TypeId::of::()); +/// ``` pub trait DAdd { + /// The result of the type-level addition of two dimensionalities. type Output: Dimensionality; } +/// Takes the maximum of two dimensionalities at compile time. +/// +/// The maximum of a constant dimensionality and a dynamic dimensionality +/// will always result in a dynamic dimensionality, effectively "erasing" +/// the compile-time knowledge. +/// +/// This type is analogous to the existing [`crate::DimMax`], but specifically +/// for dimensionality instead of `Dimension` types. +/// +/// ## Example +/// ``` +/// use ndarray::layout::dimensionality::*; +/// use core::any::TypeId; +/// +/// type Added = >::Output; +/// assert_eq!(TypeId::of::(), TypeId::of::()); +/// +/// type AddedDyn = >::Output; +/// assert_eq!(TypeId::of::(), TypeId::of::()); +/// ``` pub trait DMax { + /// The result of the type-level maximum of two dimensionalities. type Output: Dimensionality; } /// The N-dimensional static dimensionality. /// -/// This type indicates dimensionalities that are known at compile-time. +/// This type captures dimensionalities that are known at compile-time. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct NDim; +/// The 0-dimensionality, for "dimensionless" arrays with a single value. +/// +/// See [`Dimensionality`] and [`NDim`] for more information. pub type D0 = NDim<0>; -pub type D1 = NDim<1>; -pub type D2 = NDim<2>; -pub type D3 = NDim<3>; -pub type D4 = NDim<4>; -pub type D5 = NDim<5>; -pub type D6 = NDim<6>; -pub type D7 = NDim<7>; -pub type D8 = NDim<8>; -pub type D9 = NDim<9>; -pub type D10 = NDim<10>; -pub type D11 = NDim<11>; -pub type D12 = NDim<12>; +macro_rules! def_d_aliases { + ($(($alias:ident, $N:literal)),*) => { + $( + /// A dimensionality for arrays that are + #[doc = stringify!($N)] + /// D. + /// + /// See [`Dimensionality`] and [`NDim`] for more information. + pub type $alias = NDim<$N>; + )+ + }; +} + +def_d_aliases!( + (D1, 1), + (D2, 2), + (D3, 3), + (D4, 4), + (D5, 5), + (D6, 6), + (D7, 7), + (D8, 8), + (D9, 9), + (D10, 10), + (D11, 11), + (D12, 12) +); + +/// Implement addition for a given dimensionality. macro_rules! impl_add { ($left:literal, ($($right:literal),*), ddyn: ($($rightd:literal),*)) => { $( @@ -91,19 +172,19 @@ macro_rules! impl_add { // There's got to be a macro way to do this in one line to help with // any future additions of extra dimenions, although it might // also slow down compile times. -impl_add!(0, (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), ddyn: ()); -impl_add!(1, (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), ddyn: (12)); -impl_add!(2, (1, 2, 3, 4, 5, 6, 7, 8, 9, 10), ddyn: (11, 12)); -impl_add!(3, (1, 2, 3, 4, 5, 6, 7, 8, 9), ddyn: (10, 11, 12)); -impl_add!(4, (1, 2, 3, 4, 5, 6, 7, 8), ddyn: (9, 10, 11, 12)); -impl_add!(5, (1, 2, 3, 4, 5, 6, 7), ddyn: (8, 9, 10, 11, 12)); -impl_add!(6, (1, 2, 3, 4, 5, 6), ddyn: (7, 8, 9, 10, 11, 12)); -impl_add!(7, (1, 2, 3, 4, 5), ddyn: (6, 7, 8, 9, 10, 11, 12)); -impl_add!(8, (1, 2, 3, 4), ddyn: (5, 6, 7, 8, 9, 10, 11, 12)); -impl_add!(9, (1, 2, 3), ddyn: (4, 5, 6, 7, 8, 9, 10, 11, 12)); -impl_add!(10, (1, 2), ddyn: (3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); -impl_add!(11, (1), ddyn: (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); -impl_add!(12, (), ddyn: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); +impl_add!(0, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12), ddyn: ()); +impl_add!(1, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11), ddyn: (12)); +impl_add!(2, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10), ddyn: (11, 12)); +impl_add!(3, (0, 1, 2, 3, 4, 5, 6, 7, 8, 9), ddyn: (10, 11, 12)); +impl_add!(4, (0, 1, 2, 3, 4, 5, 6, 7, 8), ddyn: (9, 10, 11, 12)); +impl_add!(5, (0, 1, 2, 3, 4, 5, 6, 7), ddyn: (8, 9, 10, 11, 12)); +impl_add!(6, (0, 1, 2, 3, 4, 5, 6), ddyn: (7, 8, 9, 10, 11, 12)); +impl_add!(7, (0, 1, 2, 3, 4, 5), ddyn: (6, 7, 8, 9, 10, 11, 12)); +impl_add!(8, (0, 1, 2, 3, 4), ddyn: (5, 6, 7, 8, 9, 10, 11, 12)); +impl_add!(9, (0, 1, 2, 3), ddyn: (4, 5, 6, 7, 8, 9, 10, 11, 12)); +impl_add!(10, (0, 1, 2), ddyn: (3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); +impl_add!(11, (0, 1), ddyn: (2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); +impl_add!(12, (0), ddyn: (1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); macro_rules! impl_max { // Base case, just a target with some lowers @@ -153,7 +234,7 @@ macro_rules! impl_max { }; } -impl_max!(target: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); +impl_max!(target: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); impl DMax> for NDim where NDim: Dimensionality @@ -176,16 +257,16 @@ macro_rules! impl_dimensionality { }; } -impl Dimensionality for D1 +impl Dimensionality for D0 { - const N: Option = Some(1); + const N: Option = Some(0); type Smaller = Self; - type Larger = D2; + type Larger = D1; } -impl_dimensionality!(2, 3, 4, 5, 6, 7, 8, 9, 10, 11); +impl_dimensionality!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); impl Dimensionality for NDim<12> { @@ -198,8 +279,13 @@ impl Dimensionality for NDim<12> /// The dynamic dimensionality. /// -/// This type indicates dimensionalities that can only be known at runtime. +/// This type captures dimensionalities that are unknown at compile-time. /// See [`Dimensionality`] for more information. +/// +/// This type does not carry any information about runtime dimensionality, +/// it just indicate that dimensionality is not known at compile-time. +/// This is done to avoid multiple sources of truth for runtime array +/// dimensionality. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub struct DDyn; diff --git a/src/layout/mod.rs b/src/layout/mod.rs index c126d388a..df936ac2c 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -1,6 +1,16 @@ +//! Building blocks for describing array layout. +//! +//! This module contains types and traits used to describe how an array is structured in memory. +//! At present, it includes utilities for compactly encoding layout information +//! and abstractions for representing an array’s dimensionality. +//! +//! Over time, this module will also define traits and types for shapes, strides, and complete +//! array layouts, providing a clearer separation between these concerns and enabling more +//! flexible and expressive layout representations. + mod bitset; #[cfg(feature = "unstable")] -mod dimensionality; +pub mod dimensionality; #[allow(deprecated)] pub use bitset::{Layout, LayoutBitset}; diff --git a/src/lib.rs b/src/lib.rs index 2b9b656e3..f12417ce7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -197,7 +197,7 @@ mod extension; mod geomspace; mod indexes; mod iterators; -mod layout; +pub mod layout; mod linalg_traits; mod linspace; #[cfg(feature = "std")] From e8b20ed1ad71d1414cea8b8cc863d804f6ddac15 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 4 Jan 2026 16:21:44 -0500 Subject: [PATCH 3/6] Add associated type as unstable for Dimension --- src/dimension/dimension_trait.rs | 25 +++++++++++++++++++++---- 1 file changed, 21 insertions(+), 4 deletions(-) diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index 3544a7f3c..5305fe426 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -17,6 +17,8 @@ use super::conversion::Convert; use super::ops::DimAdd; use super::{stride_offset, stride_offset_checked}; use crate::itertools::{enumerate, zip}; +#[cfg(feature = "unstable")] +use crate::layout::dimensionality::*; use crate::IntoDimension; use crate::RemoveAxis; use crate::{ArrayView1, ArrayViewMut1}; @@ -76,6 +78,10 @@ pub trait Dimension: /// Next larger dimension type Larger: Dimension + RemoveAxis; + /// The dimensionality of the type, under the new, unstable API. + #[cfg(feature = "unstable")] + type Dimality: Dimensionality; + /// Returns the number of dimensions (number of axes). fn ndim(&self) -> usize; @@ -420,6 +426,7 @@ impl Dimension for Dim<[Ix; 0]> type Pattern = (); type Smaller = Self; type Larger = Ix1; + type Dimality = D0; // empty product is 1 -> size is 1 #[inline] fn ndim(&self) -> usize @@ -470,6 +477,8 @@ impl Dimension for Dim<[Ix; 1]> type Pattern = Ix; type Smaller = Ix0; type Larger = Ix2; + #[cfg(feature = "unstable")] + type Dimality = D1; #[inline] fn ndim(&self) -> usize { @@ -603,6 +612,8 @@ impl Dimension for Dim<[Ix; 2]> type Pattern = (Ix, Ix); type Smaller = Ix1; type Larger = Ix3; + #[cfg(feature = "unstable")] + type Dimality = D2; #[inline] fn ndim(&self) -> usize { @@ -778,6 +789,8 @@ impl Dimension for Dim<[Ix; 3]> type Pattern = (Ix, Ix, Ix); type Smaller = Ix2; type Larger = Ix4; + #[cfg(feature = "unstable")] + type Dimality = D3; #[inline] fn ndim(&self) -> usize { @@ -904,12 +917,14 @@ impl Dimension for Dim<[Ix; 3]> } macro_rules! large_dim { - ($n:expr, $name:ident, $pattern:ty, $larger:ty, { $($insert_axis:tt)* }) => ( + ($n:expr, $name:ident, $pattern:ty, $larger:ty, $dimality:ty, { $($insert_axis:tt)* }) => ( impl Dimension for Dim<[Ix; $n]> { const NDIM: Option = Some($n); type Pattern = $pattern; type Smaller = Dim<[Ix; $n - 1]>; type Larger = $larger; + #[cfg(feature = "unstable")] + type Dimality = $dimality; #[inline] fn ndim(&self) -> usize { $n } #[inline] @@ -935,13 +950,13 @@ macro_rules! large_dim { ); } -large_dim!(4, Ix4, (Ix, Ix, Ix, Ix), Ix5, { +large_dim!(4, Ix4, (Ix, Ix, Ix, Ix), Ix5, D4, { impl_insert_axis_array!(4); }); -large_dim!(5, Ix5, (Ix, Ix, Ix, Ix, Ix), Ix6, { +large_dim!(5, Ix5, (Ix, Ix, Ix, Ix, Ix), Ix6, D5, { impl_insert_axis_array!(5); }); -large_dim!(6, Ix6, (Ix, Ix, Ix, Ix, Ix, Ix), IxDyn, { +large_dim!(6, Ix6, (Ix, Ix, Ix, Ix, Ix, Ix), IxDyn, D6, { fn insert_axis(&self, axis: Axis) -> Self::Larger { debug_assert!(axis.index() <= self.ndim()); let mut out = Vec::with_capacity(self.ndim() + 1); @@ -960,6 +975,8 @@ impl Dimension for IxDyn type Pattern = Self; type Smaller = Self; type Larger = Self; + #[cfg(feature = "unstable")] + type Dimality = DDyn; #[inline] fn ndim(&self) -> usize { From 3c38785ae270d4c7d0be2b9599de182bc9c5dc86 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sun, 4 Jan 2026 16:54:05 -0500 Subject: [PATCH 4/6] Forgot unstable feature gate --- src/dimension/dimension_trait.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index 5305fe426..6848bc9e5 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -426,6 +426,7 @@ impl Dimension for Dim<[Ix; 0]> type Pattern = (); type Smaller = Self; type Larger = Ix1; + #[cfg(feature = "unstable")] type Dimality = D0; // empty product is 1 -> size is 1 #[inline] From eef102f9023c50bf47bfa69f05ea534962d949d0 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Mon, 5 Jan 2026 18:31:49 -0500 Subject: [PATCH 5/6] Change associated type name and simplify `large_dim` macro --- src/dimension/dimension_trait.rs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index 6848bc9e5..36b538243 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -80,7 +80,7 @@ pub trait Dimension: /// The dimensionality of the type, under the new, unstable API. #[cfg(feature = "unstable")] - type Dimality: Dimensionality; + type Rank: Dimensionality; /// Returns the number of dimensions (number of axes). fn ndim(&self) -> usize; @@ -427,7 +427,7 @@ impl Dimension for Dim<[Ix; 0]> type Smaller = Self; type Larger = Ix1; #[cfg(feature = "unstable")] - type Dimality = D0; + type Rank = D0; // empty product is 1 -> size is 1 #[inline] fn ndim(&self) -> usize @@ -479,7 +479,7 @@ impl Dimension for Dim<[Ix; 1]> type Smaller = Ix0; type Larger = Ix2; #[cfg(feature = "unstable")] - type Dimality = D1; + type Rank = D1; #[inline] fn ndim(&self) -> usize { @@ -614,7 +614,7 @@ impl Dimension for Dim<[Ix; 2]> type Smaller = Ix1; type Larger = Ix3; #[cfg(feature = "unstable")] - type Dimality = D2; + type Rank = D2; #[inline] fn ndim(&self) -> usize { @@ -791,7 +791,7 @@ impl Dimension for Dim<[Ix; 3]> type Smaller = Ix2; type Larger = Ix4; #[cfg(feature = "unstable")] - type Dimality = D3; + type Rank = D3; #[inline] fn ndim(&self) -> usize { @@ -918,14 +918,14 @@ impl Dimension for Dim<[Ix; 3]> } macro_rules! large_dim { - ($n:expr, $name:ident, $pattern:ty, $larger:ty, $dimality:ty, { $($insert_axis:tt)* }) => ( + ($n:expr, $name:ident, $pattern:ty, $larger:ty, { $($insert_axis:tt)* }) => ( impl Dimension for Dim<[Ix; $n]> { const NDIM: Option = Some($n); type Pattern = $pattern; type Smaller = Dim<[Ix; $n - 1]>; type Larger = $larger; #[cfg(feature = "unstable")] - type Dimality = $dimality; + type Rank = NDim<$n>; #[inline] fn ndim(&self) -> usize { $n } #[inline] @@ -951,13 +951,13 @@ macro_rules! large_dim { ); } -large_dim!(4, Ix4, (Ix, Ix, Ix, Ix), Ix5, D4, { +large_dim!(4, Ix4, (Ix, Ix, Ix, Ix), Ix5, { impl_insert_axis_array!(4); }); -large_dim!(5, Ix5, (Ix, Ix, Ix, Ix, Ix), Ix6, D5, { +large_dim!(5, Ix5, (Ix, Ix, Ix, Ix, Ix), Ix6, { impl_insert_axis_array!(5); }); -large_dim!(6, Ix6, (Ix, Ix, Ix, Ix, Ix, Ix), IxDyn, D6, { +large_dim!(6, Ix6, (Ix, Ix, Ix, Ix, Ix, Ix), IxDyn, { fn insert_axis(&self, axis: Axis) -> Self::Larger { debug_assert!(axis.index() <= self.ndim()); let mut out = Vec::with_capacity(self.ndim() + 1); @@ -977,7 +977,7 @@ impl Dimension for IxDyn type Smaller = Self; type Larger = Self; #[cfg(feature = "unstable")] - type Dimality = DDyn; + type Rank = DDyn; #[inline] fn ndim(&self) -> usize { From 312c744ce02aed4eb20274b9fd3d40d74e831b12 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sat, 10 Jan 2026 11:53:24 -0500 Subject: [PATCH 6/6] Add two comments on `impl_add` macro --- src/layout/dimensionality.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/layout/dimensionality.rs b/src/layout/dimensionality.rs index 2cfa7e286..ed62e5fe8 100644 --- a/src/layout/dimensionality.rs +++ b/src/layout/dimensionality.rs @@ -153,6 +153,7 @@ def_d_aliases!( /// Implement addition for a given dimensionality. macro_rules! impl_add { ($left:literal, ($($right:literal),*), ddyn: ($($rightd:literal),*)) => { + // $left + $right still gets you a compile-time dimension $( impl DAdd> for NDim<$left> { @@ -160,6 +161,7 @@ macro_rules! impl_add { } )* + // $left + $rightd gets you a dynamic dimensionality $( impl DAdd> for NDim<$left> {