From 3463417d14f084bdd13296f6683169daeebbdf5b Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sat, 10 Jan 2026 17:22:13 -0500 Subject: [PATCH 1/4] Add a trait to tie together compile-time and runtime number of dimensions --- src/dimension/dimension_trait.rs | 74 ++++++++---------- src/layout/mod.rs | 2 +- src/layout/ranked.rs | 124 +++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 46 deletions(-) create mode 100644 src/layout/ranked.rs diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index 36b538243..e7d561c66 100644 --- a/src/dimension/dimension_trait.rs +++ b/src/dimension/dimension_trait.rs @@ -17,8 +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::layout::ranked::Ranked; use crate::IntoDimension; use crate::RemoveAxis; use crate::{ArrayView1, ArrayViewMut1}; @@ -61,6 +61,7 @@ pub trait Dimension: + DimAdd + DimAdd::Larger> + DimAdd + + Ranked { /// For fixed-size dimension representations (e.g. `Ix2`), this should be /// `Some(ndim)`, and for variable-size dimension representations (e.g. @@ -78,12 +79,11 @@ pub trait Dimension: /// Next larger dimension type Larger: Dimension + RemoveAxis; - /// The dimensionality of the type, under the new, unstable API. - #[cfg(feature = "unstable")] - type Rank: Dimensionality; - /// Returns the number of dimensions (number of axes). - fn ndim(&self) -> usize; + fn ndim(&self) -> usize + { + self.rank() + } /// Convert the dimension into a pattern matching friendly value. fn into_pattern(self) -> Self::Pattern; @@ -420,21 +420,26 @@ macro_rules! impl_insert_axis_array( ); ); +impl Ranked for Dim<[Ix; N]> +where NDim: Dimensionality // Limit us to < 12, since Rank must impl Dimensionality +{ + type Rank = NDim; + + #[inline] + fn rank(&self) -> usize + { + N + } +} + impl Dimension for Dim<[Ix; 0]> { const NDIM: Option = Some(0); type Pattern = (); type Smaller = Self; type Larger = Ix1; - #[cfg(feature = "unstable")] - type Rank = D0; // empty product is 1 -> size is 1 #[inline] - fn ndim(&self) -> usize - { - 0 - } - #[inline] fn slice(&self) -> &[Ix] { &[] @@ -478,13 +483,6 @@ impl Dimension for Dim<[Ix; 1]> type Pattern = Ix; type Smaller = Ix0; type Larger = Ix2; - #[cfg(feature = "unstable")] - type Rank = D1; - #[inline] - fn ndim(&self) -> usize - { - 1 - } #[inline] fn slice(&self) -> &[Ix] { @@ -613,13 +611,6 @@ impl Dimension for Dim<[Ix; 2]> type Pattern = (Ix, Ix); type Smaller = Ix1; type Larger = Ix3; - #[cfg(feature = "unstable")] - type Rank = D2; - #[inline] - fn ndim(&self) -> usize - { - 2 - } #[inline] fn into_pattern(self) -> Self::Pattern { @@ -790,13 +781,6 @@ impl Dimension for Dim<[Ix; 3]> type Pattern = (Ix, Ix, Ix); type Smaller = Ix2; type Larger = Ix4; - #[cfg(feature = "unstable")] - type Rank = D3; - #[inline] - fn ndim(&self) -> usize - { - 3 - } #[inline] fn into_pattern(self) -> Self::Pattern { @@ -924,10 +908,6 @@ macro_rules! large_dim { type Pattern = $pattern; type Smaller = Dim<[Ix; $n - 1]>; type Larger = $larger; - #[cfg(feature = "unstable")] - type Rank = NDim<$n>; - #[inline] - fn ndim(&self) -> usize { $n } #[inline] fn into_pattern(self) -> Self::Pattern { self.ix().convert() @@ -968,6 +948,17 @@ large_dim!(6, Ix6, (Ix, Ix, Ix, Ix, Ix, Ix), IxDyn, { } }); +impl Ranked for IxDyn +{ + type Rank = DDyn; + + #[inline] + fn rank(&self) -> usize + { + self.ix().len() + } +} + /// IxDyn is a "dynamic" index, pretty hard to use when indexing, /// and memory wasteful, but it allows an arbitrary and dynamic number of axes. impl Dimension for IxDyn @@ -976,13 +967,6 @@ impl Dimension for IxDyn type Pattern = Self; type Smaller = Self; type Larger = Self; - #[cfg(feature = "unstable")] - type Rank = DDyn; - #[inline] - fn ndim(&self) -> usize - { - self.ix().len() - } #[inline] fn slice(&self) -> &[Ix] { diff --git a/src/layout/mod.rs b/src/layout/mod.rs index df936ac2c..96576fc05 100644 --- a/src/layout/mod.rs +++ b/src/layout/mod.rs @@ -9,8 +9,8 @@ //! flexible and expressive layout representations. mod bitset; -#[cfg(feature = "unstable")] pub mod dimensionality; +pub mod ranked; #[allow(deprecated)] pub use bitset::{Layout, LayoutBitset}; diff --git a/src/layout/ranked.rs b/src/layout/ranked.rs new file mode 100644 index 000000000..1f38de1f5 --- /dev/null +++ b/src/layout/ranked.rs @@ -0,0 +1,124 @@ +//! Unified trait for type- and runtime-level array rank. +//! +//! This module defines the [`Ranked`] trait, which bridges compile-time and runtime representations +//! of array dimensionality. It enables generic code to query the number of dimensions (rank) of an +//! array, whether known statically (via [`Dimensionality`]) or only at runtime. Blanket +//! implementations are provided for common pointer and container types. + +use crate::layout::dimensionality::{Dimensionality, D1}; + +/// A trait to unify type- and runtime-level number of dimensions. +/// +/// The [`Dimensionality`] trait captures array rank at the type level; however it +/// is limited at runtime. If the `Dimensionality` is dynamic (i.e., [`DDyn`][DDyn]) +/// then the dimensionality cannot be known at compile time. This trait unifies type- +/// and runtime-level dimensionality by providing: +/// 1. An associated type, [`Rank`][Rank], with type-level dimensionality +/// 2. A function, [`ndim`][ndim], that can give the dimensionality at runtime. +/// +/// [DDyn]: crate::layout::dimensionality::DDyn +/// [Rank]: Ranked::Rank +/// [ndim]: Ranked::ndim +/// [N]: Dimensionality::N +pub trait Ranked +{ + /// The compile-time rank of the type; can be [`DDyn`][DDyn] if unknown. + /// + /// [DDyn]: crate::layout::dimensionality::DDyn + type Rank: Dimensionality; + + /// The runtime number of dimensions of the type. + fn rank(&self) -> usize; +} + +mod blanket_impls +{ + use super::*; + use alloc::rc::Rc; + use alloc::sync::Arc; + + impl Ranked for &T + where T: Ranked + { + type Rank = T::Rank; + + fn rank(&self) -> usize + { + (*self).rank() + } + } + + impl Ranked for &mut T + where T: Ranked + { + type Rank = T::Rank; + + fn rank(&self) -> usize + { + (**self).rank() + } + } + + impl Ranked for Arc + where T: Ranked + { + type Rank = T::Rank; + + fn rank(&self) -> usize + { + (**self).rank() + } + } + + impl Ranked for Rc + where T: Ranked + { + type Rank = T::Rank; + + fn rank(&self) -> usize + { + (**self).rank() + } + } + + impl Ranked for Box + where T: Ranked + { + type Rank = T::Rank; + + fn rank(&self) -> usize + { + (**self).rank() + } + } +} + +impl Ranked for [T] +{ + type Rank = D1; + + fn rank(&self) -> usize + { + 1 + } +} + +impl Ranked for Vec +{ + type Rank = D1; + + fn rank(&self) -> usize + { + 1 + } +} + +impl Ranked for [T; N] +{ + type Rank = D1; + + fn rank(&self) -> usize + { + 1 + } +} From d0bb0b147569043aa1354ce94f92b8ddaeffce19 Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sat, 10 Jan 2026 19:48:46 -0500 Subject: [PATCH 2/4] Add Ranked impls for the main array types --- src/layout/ranked.rs | 67 +++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 66 insertions(+), 1 deletion(-) diff --git a/src/layout/ranked.rs b/src/layout/ranked.rs index 1f38de1f5..6fd9629d7 100644 --- a/src/layout/ranked.rs +++ b/src/layout/ranked.rs @@ -5,7 +5,15 @@ //! array, whether known statically (via [`Dimensionality`]) or only at runtime. Blanket //! implementations are provided for common pointer and container types. -use crate::layout::dimensionality::{Dimensionality, D1}; +use crate::{ + layout::dimensionality::{Dimensionality, D1}, + ArrayBase, + ArrayParts, + ArrayRef, + LayoutRef, + RawData, + RawRef, +}; /// A trait to unify type- and runtime-level number of dimensions. /// @@ -122,3 +130,60 @@ impl Ranked for [T; N] 1 } } + +impl Ranked for ArrayParts +where D: Ranked +{ + type Rank = D::Rank; + + fn rank(&self) -> usize + { + self.dim.rank() + } +} + +impl Ranked for ArrayBase +where + S: RawData, + D: Ranked, +{ + type Rank = D::Rank; + + fn rank(&self) -> usize + { + self.parts.rank() + } +} + +impl Ranked for LayoutRef +where D: Ranked +{ + type Rank = D::Rank; + + fn rank(&self) -> usize + { + self.0.rank() + } +} + +impl Ranked for ArrayRef +where D: Ranked +{ + type Rank = D::Rank; + + fn rank(&self) -> usize + { + self.0.rank() + } +} + +impl Ranked for RawRef +where D: Ranked +{ + type Rank = D::Rank; + + fn rank(&self) -> usize + { + self.0.rank() + } +} From 73e250a6deadddaeb783425d79df34ddc7362d3b Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sat, 10 Jan 2026 19:53:23 -0500 Subject: [PATCH 3/4] Forgot use alloc statements for no-std --- src/layout/ranked.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/layout/ranked.rs b/src/layout/ranked.rs index 6fd9629d7..fc7edf5d0 100644 --- a/src/layout/ranked.rs +++ b/src/layout/ranked.rs @@ -5,6 +5,9 @@ //! array, whether known statically (via [`Dimensionality`]) or only at runtime. Blanket //! implementations are provided for common pointer and container types. +use alloc::boxed::Box; +use alloc::vec::Vec; + use crate::{ layout::dimensionality::{Dimensionality, D1}, ArrayBase, From e4e4da3e9ed11a1631810a7879c8bbf82072f39a Mon Sep 17 00:00:00 2001 From: Adam Kern Date: Sat, 10 Jan 2026 22:02:07 -0500 Subject: [PATCH 4/4] Fix docs and make Arc work without atomic ptr --- src/layout/ranked.rs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/layout/ranked.rs b/src/layout/ranked.rs index fc7edf5d0..6891644ab 100644 --- a/src/layout/ranked.rs +++ b/src/layout/ranked.rs @@ -29,7 +29,7 @@ use crate::{ /// /// [DDyn]: crate::layout::dimensionality::DDyn /// [Rank]: Ranked::Rank -/// [ndim]: Ranked::ndim +/// [ndim]: Ranked::rank /// [N]: Dimensionality::N pub trait Ranked { @@ -46,7 +46,11 @@ mod blanket_impls { use super::*; use alloc::rc::Rc; + + #[cfg(target_has_atomic = "ptr")] use alloc::sync::Arc; + #[cfg(not(target_has_atomic = "ptr"))] + use portable_atomic_util::Arc; impl Ranked for &T where T: Ranked