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..6891644ab --- /dev/null +++ b/src/layout/ranked.rs @@ -0,0 +1,196 @@ +//! 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 alloc::boxed::Box; +use alloc::vec::Vec; + +use crate::{ + layout::dimensionality::{Dimensionality, D1}, + ArrayBase, + ArrayParts, + ArrayRef, + LayoutRef, + RawData, + RawRef, +}; + +/// 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::rank +/// [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; + + #[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 + { + 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 + } +} + +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() + } +}