diff --git a/src/dimension/dimension_trait.rs b/src/dimension/dimension_trait.rs index 36b538243..c1bbfa86a 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::rank::*; +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,13 +79,6 @@ 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; - /// Convert the dimension into a pattern matching friendly value. fn into_pattern(self) -> Self::Pattern; @@ -420,21 +414,26 @@ macro_rules! impl_insert_axis_array( ); ); +impl Ranked for Dim<[Ix; N]> +where ConstRank: Rank // Limit us to < 12, since Rank must impl Dimensionality +{ + type NDim = ConstRank; + + #[inline] + fn ndim(&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 +477,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 +605,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 +775,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 +902,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 +942,17 @@ large_dim!(6, Ix6, (Ix, Ix, Ix, Ix, Ix, Ix), IxDyn, { } }); +impl Ranked for IxDyn +{ + type NDim = DynRank; + + #[inline] + fn ndim(&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 +961,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/dimension/dynindeximpl.rs b/src/dimension/dynindeximpl.rs index 60aeacd80..6f8ad1d49 100644 --- a/src/dimension/dynindeximpl.rs +++ b/src/dimension/dynindeximpl.rs @@ -1,4 +1,5 @@ use crate::imp_prelude::*; +use crate::layout::ranked::Ranked; #[cfg(not(feature = "std"))] use alloc::boxed::Box; use alloc::vec; diff --git a/src/dimension/ndindex.rs b/src/dimension/ndindex.rs index ca2a3ea69..4ed368c20 100644 --- a/src/dimension/ndindex.rs +++ b/src/dimension/ndindex.rs @@ -2,6 +2,7 @@ use std::fmt::Debug; use super::{stride_offset, stride_offset_checked}; use crate::itertools::zip; +use crate::layout::ranked::Ranked; use crate::{Dim, Dimension, IntoDimension, Ix, Ix0, Ix1, Ix2, Ix3, Ix4, Ix5, Ix6, IxDyn, IxDynImpl}; /// Tuple or fixed size arrays that can be used to index an array. diff --git a/src/dimension/remove_axis.rs b/src/dimension/remove_axis.rs index 7ba3b5330..5510c6d64 100644 --- a/src/dimension/remove_axis.rs +++ b/src/dimension/remove_axis.rs @@ -6,7 +6,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -use crate::{Axis, Dim, Dimension, Ix, Ix0, Ix1}; +use crate::{layout::ranked::Ranked, Axis, Dim, Dimension, Ix, Ix0, Ix1}; /// Array shape with a next smaller dimension. /// diff --git a/src/indexes.rs b/src/indexes.rs index a73c7fcb4..5b0346208 100644 --- a/src/indexes.rs +++ b/src/indexes.rs @@ -7,6 +7,7 @@ // except according to those terms. use super::Dimension; use crate::dimension::IntoDimension; +use crate::layout::ranked::Ranked; use crate::split_at::SplitAt; use crate::zip::Offset; use crate::Axis; diff --git a/src/layout/mod.rs b/src/layout/mod.rs index df936ac2c..9f5d1e4e1 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 rank; +pub mod ranked; #[allow(deprecated)] pub use bitset::{Layout, LayoutBitset}; diff --git a/src/layout/dimensionality.rs b/src/layout/rank.rs similarity index 60% rename from src/layout/dimensionality.rs rename to src/layout/rank.rs index ed62e5fe8..2881b593d 100644 --- a/src/layout/dimensionality.rs +++ b/src/layout/rank.rs @@ -1,8 +1,8 @@ //! 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 +//! This module defines the [`Rank`] trait and related types used to represent +//! the number of axes an array has, either at compile time ([`ConstRank`]) or dynamically +//! ([`DynRank`]). 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; @@ -15,31 +15,31 @@ use core::fmt::Debug; /// 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. +/// Any dimensionality above 12 must be represented with [`DynRank`], even if it is known at compile time. /// /// 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. -/// In dynamic cases, `DDyn` means that the dimensionality is not known at compile time. +/// A type implementing `Rank` does not expose its dimensionality as a runtime value. +/// In dynamic cases, `DynRank` 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: +pub trait Rank: Copy + Eq + Debug + Send + Sync - + DMax - + DMax - + DMax - + DMax - + DMax - + DAdd - + DAdd - + DAdd - + DAdd - + DAdd - + DAdd + + RMax + + RMax + + RMax + + RMax + + RMax + + RAdd + + RAdd + + RAdd + + RAdd + + RAdd + + RAdd { /// The dimensionality as a constant `usize`, or `None` if it is dynamic. const N: Option; @@ -47,16 +47,16 @@ pub trait Dimensionality: /// 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; + /// is of course no "smaller" dimensionality. Instead, `ConstRank::<0>::Smaller` just + /// refers back to `ConstRank<0>`; in other words, it uses a "base case" of 0-dimensionality. + type Smaller: Rank; /// 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; + /// is no "larger" compile-time dimensionality. Instead, `ConstRank::<12>::Larger` just + /// refers to `DynRank`; in other words, it "escapes" to a dynamically-determined dimensionality. + type Larger: Rank; } /// Adds two dimensionalities at compile time. @@ -70,19 +70,19 @@ pub trait Dimensionality: /// /// ## Example /// ``` -/// use ndarray::layout::dimensionality::*; +/// use ndarray::layout::rank::*; /// use core::any::TypeId; /// -/// type Added = >::Output; -/// assert_eq!(TypeId::of::(), TypeId::of::()); +/// type Added = >::Output; +/// assert_eq!(TypeId::of::(), TypeId::of::()); /// -/// type AddedDyn = >::Output; -/// assert_eq!(TypeId::of::(), TypeId::of::()); +/// type AddedDyn = >::Output; +/// assert_eq!(TypeId::of::(), TypeId::of::()); /// ``` -pub trait DAdd +pub trait RAdd { /// The result of the type-level addition of two dimensionalities. - type Output: Dimensionality; + type Output: Rank; } /// Takes the maximum of two dimensionalities at compile time. @@ -96,31 +96,31 @@ pub trait DAdd /// /// ## Example /// ``` -/// use ndarray::layout::dimensionality::*; +/// use ndarray::layout::rank::*; /// use core::any::TypeId; /// -/// type Added = >::Output; -/// assert_eq!(TypeId::of::(), TypeId::of::()); +/// type Added = >::Output; +/// assert_eq!(TypeId::of::(), TypeId::of::()); /// -/// type AddedDyn = >::Output; -/// assert_eq!(TypeId::of::(), TypeId::of::()); +/// type AddedDyn = >::Output; +/// assert_eq!(TypeId::of::(), TypeId::of::()); /// ``` -pub trait DMax +pub trait RMax { /// The result of the type-level maximum of two dimensionalities. - type Output: Dimensionality; + type Output: Rank; } /// The N-dimensional static dimensionality. /// /// This type captures dimensionalities that are known at compile-time. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -pub struct NDim; +pub struct ConstRank; /// The 0-dimensionality, for "dimensionless" arrays with a single value. /// -/// See [`Dimensionality`] and [`NDim`] for more information. -pub type D0 = NDim<0>; +/// See [`Rank`] and [`ConstRank`] for more information. +pub type R0 = ConstRank<0>; macro_rules! def_d_aliases { ($(($alias:ident, $N:literal)),*) => { @@ -129,25 +129,25 @@ macro_rules! def_d_aliases { #[doc = stringify!($N)] /// D. /// - /// See [`Dimensionality`] and [`NDim`] for more information. - pub type $alias = NDim<$N>; + /// See [`Rank`] and [`ConstRank`] for more information. + pub type $alias = ConstRank<$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) + (R1, 1), + (R2, 2), + (R3, 3), + (R4, 4), + (R5, 5), + (R6, 6), + (R7, 7), + (R8, 8), + (R9, 9), + (R10, 10), + (R11, 11), + (R12, 12) ); /// Implement addition for a given dimensionality. @@ -155,17 +155,17 @@ 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> + impl RAdd> for ConstRank<$left> { - type Output = NDim<{$left + $right}>; + type Output = ConstRank<{$left + $right}>; } )* // $left + $rightd gets you a dynamic dimensionality $( - impl DAdd> for NDim<$left> + impl RAdd> for ConstRank<$left> { - type Output = DDyn; + type Output = DynRank; } )* }; @@ -192,29 +192,29 @@ macro_rules! impl_max { // Base case, just a target with some lowers ($($lower:literal),+, target: $target:literal) => { $( - impl DMax> for NDim<$target> + impl RMax> for ConstRank<$target> { - type Output = NDim<$target>; + type Output = ConstRank<$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> + impl RMax> for ConstRank<$target> { - type Output = NDim<$target>; + type Output = ConstRank<$target>; } )+ - impl DMax> for NDim<$target> + impl RMax> for ConstRank<$target> { - type Output = NDim<$first_upper>; + type Output = ConstRank<$first_upper>; } $( $( - impl DMax> for NDim<$target> + impl RMax> for ConstRank<$target> { - type Output = NDim<$upper>; + type Output = ConstRank<$upper>; } )+ )? @@ -222,14 +222,14 @@ macro_rules! impl_max { }; // Helper syntax: zero lowers, target, at least one upper (target: $target:literal, $first_upper:literal, $($upper:literal),+) => { - impl DMax> for NDim<$target> + impl RMax> for ConstRank<$target> { - type Output = NDim<$first_upper>; + type Output = ConstRank<$first_upper>; } $( - impl DMax> for NDim<$target> + impl RMax> for ConstRank<$target> { - type Output = NDim<$upper>; + type Output = ConstRank<$upper>; } )+ impl_max!($target, target: $first_upper, $($upper),+); @@ -238,8 +238,8 @@ macro_rules! impl_max { impl_max!(target: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12); -impl DMax> for NDim -where NDim: Dimensionality +impl RMax> for ConstRank +where ConstRank: Rank { type Output = Self; } @@ -247,51 +247,51 @@ where NDim: Dimensionality macro_rules! impl_dimensionality { ($($d:literal),+) => { $( - impl Dimensionality for NDim<$d> + impl Rank for ConstRank<$d> { const N: Option = Some($d); - type Smaller = NDim<{$d - 1}>; + type Smaller = ConstRank<{$d - 1}>; - type Larger = NDim<{$d + 1}>; + type Larger = ConstRank<{$d + 1}>; } )+ }; } -impl Dimensionality for D0 +impl Rank for R0 { const N: Option = Some(0); type Smaller = Self; - type Larger = D1; + type Larger = R1; } impl_dimensionality!(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11); -impl Dimensionality for NDim<12> +impl Rank for ConstRank<12> { const N: Option = Some(12); - type Smaller = D11; + type Smaller = R11; - type Larger = DDyn; + type Larger = DynRank; } /// The dynamic dimensionality. /// /// This type captures dimensionalities that are unknown at compile-time. -/// See [`Dimensionality`] for more information. +/// See [`Rank`] 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; +pub struct DynRank; -impl Dimensionality for DDyn +impl Rank for DynRank { const N: Option = None; @@ -300,32 +300,32 @@ impl Dimensionality for DDyn type Larger = Self; } -impl DAdd for DDyn +impl RAdd for DynRank { - type Output = DDyn; + type Output = DynRank; } -impl DAdd> for DDyn +impl RAdd> for DynRank { - type Output = DDyn; + type Output = DynRank; } -impl DAdd for NDim +impl RAdd for ConstRank { - type Output = DDyn; + type Output = DynRank; } -impl DMax for DDyn +impl RMax for DynRank { - type Output = DDyn; + type Output = DynRank; } -impl DMax> for DDyn +impl RMax> for DynRank { - type Output = DDyn; + type Output = DynRank; } -impl DMax for NDim +impl RMax for ConstRank { - type Output = DDyn; + type Output = DynRank; } diff --git a/src/layout/ranked.rs b/src/layout/ranked.rs new file mode 100644 index 000000000..f71cce097 --- /dev/null +++ b/src/layout/ranked.rs @@ -0,0 +1,195 @@ +//! 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 [`Rank`]) 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::rank::{Rank, R1}, + ArrayBase, + ArrayParts, + ArrayRef, + LayoutRef, + RawData, + RawRef, +}; + +/// A trait to unify type- and runtime-level number of dimensions. +/// +/// The [`Rank`] trait captures array rank at the type level; however it +/// is limited at runtime. If the `Rank` is dynamic (i.e., [`DynRank`][DynRank]) +/// then the dimensionality cannot be known at compile time. This trait unifies type- +/// and runtime-level dimensionality by providing: +/// 1. An associated type, [`NDim`][NDim], with type-level dimensionality +/// 2. A function, [`ndim`][ndim], that can give the dimensionality at runtime. +/// +/// [DynRank]: crate::layout::rank::DynRank +/// [NDim]: Ranked::NDim +/// [ndim]: Ranked::ndim +pub trait Ranked +{ + /// The compile-time rank of the type; can be [`DynRank`][DynRank] if unknown. + /// + /// [DynRank]: crate::layout::rank::DynRank + type NDim: Rank; + + /// The runtime number of dimensions of the type. + fn ndim(&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 NDim = T::NDim; + + fn ndim(&self) -> usize + { + (*self).ndim() + } + } + + impl Ranked for &mut T + where T: Ranked + { + type NDim = T::NDim; + + fn ndim(&self) -> usize + { + (**self).ndim() + } + } + + impl Ranked for Arc + where T: Ranked + { + type NDim = T::NDim; + + fn ndim(&self) -> usize + { + (**self).ndim() + } + } + + impl Ranked for Rc + where T: Ranked + { + type NDim = T::NDim; + + fn ndim(&self) -> usize + { + (**self).ndim() + } + } + + impl Ranked for Box + where T: Ranked + { + type NDim = T::NDim; + + fn ndim(&self) -> usize + { + (**self).ndim() + } + } +} + +impl Ranked for [T] +{ + type NDim = R1; + + fn ndim(&self) -> usize + { + 1 + } +} + +impl Ranked for Vec +{ + type NDim = R1; + + fn ndim(&self) -> usize + { + 1 + } +} + +impl Ranked for [T; N] +{ + type NDim = R1; + + fn ndim(&self) -> usize + { + 1 + } +} + +impl Ranked for ArrayParts +where D: Ranked +{ + type NDim = D::NDim; + + fn ndim(&self) -> usize + { + self.dim.ndim() + } +} + +impl Ranked for ArrayBase +where + S: RawData, + D: Ranked, +{ + type NDim = D::NDim; + + fn ndim(&self) -> usize + { + self.parts.ndim() + } +} + +impl Ranked for LayoutRef +where D: Ranked +{ + type NDim = D::NDim; + + fn ndim(&self) -> usize + { + self.0.ndim() + } +} + +impl Ranked for ArrayRef +where D: Ranked +{ + type NDim = D::NDim; + + fn ndim(&self) -> usize + { + self.0.ndim() + } +} + +impl Ranked for RawRef +where D: Ranked +{ + type NDim = D::NDim; + + fn ndim(&self) -> usize + { + self.0.ndim() + } +}