1+ //! Type-level representations of array dimensionality.
2+ //!
3+ //! This module defines the [`Dimensionality`] trait and related types used to represent
4+ //! the number of axes an array has, either at compile time ([`NDim`]) or dynamically
5+ //! ([`DDyn`]). These types support basic type-level operations such as addition and
6+ //! maximum, which are used to model array operations like concatenation and broadcasting.
7+
18use core:: fmt:: Debug ;
29
310/// 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;
916///
1017/// Compile-time dimensionalities are currently supported for values from 0 to 12, inclusive.
1118/// Any dimensionality above 12 must be represented with [`DDyn`], even if it is known at compile time.
12- /// See [`NDim`] and [`DDyn`] for guidance on choosing between static and dynamic dimensionalities.
19+ ///
20+ /// The `Smaller` and `Larger` associated types allow users to move to adjacent dimensionalities at the type level.
1321///
1422/// ## Dynamic dimensionalities
1523/// A type implementing `Dimensionality` does not expose its dimensionality as a runtime value.
@@ -21,55 +29,128 @@ pub trait Dimensionality:
2129 + Debug
2230 + Send
2331 + Sync
24- + DMax < D1 , Output = Self >
32+ + DMax < D0 , Output = Self >
2533 + DMax < Self , Output = Self >
2634 + DMax < DDyn , Output = DDyn >
2735 + DMax < Self :: Smaller , Output = Self >
2836 + DMax < Self :: Larger , Output = Self :: Larger >
2937 + DAdd < Self >
3038 + DAdd < Self :: Smaller >
3139 + DAdd < Self :: Larger >
40+ + DAdd < D0 , Output = Self >
3241 + DAdd < D1 , Output = Self :: Larger >
3342 + DAdd < DDyn , Output = DDyn >
3443{
35- /// The dimensionality as a constant usize, if it's not dynamic.
44+ /// The dimensionality as a constant ` usize`, or `None` if it is dynamic.
3645 const N : Option < usize > ;
3746
47+ /// The next-smaller possible dimensionality.
48+ ///
49+ /// For the smallest possible dimensionality (currently 0-dimensional), there
50+ /// is of course no "smaller" dimensionality. Instead, `NDim::<0>::Smaller` just
51+ /// refers back to `NDim<0>`; in other words, it uses a "base case" of 0-dimensionality.
3852 type Smaller : Dimensionality ;
3953
40- type Larger : Dimensionality ; // And more
54+ /// The next-larger dimensionality.
55+ ///
56+ /// For the largest compile-time dimensionality (currently 12-dimensional), there
57+ /// is no "larger" compile-time dimensionality. Instead, `NDim::<12>::Larger` just
58+ /// refers to `DDyn`; in other words, it "escapes" to a dynamically-determined dimensionality.
59+ type Larger : Dimensionality ;
4160}
4261
62+ /// Adds two dimensionalities at compile time.
63+ ///
64+ /// The addition of a constant dimensionality with a dynamic dimensionality
65+ /// will always result in a dynamic dimensionality, effectively "erasing"
66+ /// the compile-time knowledge.
67+ ///
68+ /// This type is analogous to the existing [`crate::DimAdd`], but specifically
69+ /// for dimensionality instead of `Dimension` types.
70+ ///
71+ /// ## Example
72+ /// ```
73+ /// use ndarray::layout::dimensionality::*;
74+ /// use core::any::TypeId;
75+ ///
76+ /// type Added = <D1 as DAdd<D2>>::Output;
77+ /// assert_eq!(TypeId::of::<Added>(), TypeId::of::<D3>());
78+ ///
79+ /// type AddedDyn = <D1 as DAdd<DDyn>>::Output;
80+ /// assert_eq!(TypeId::of::<AddedDyn>(), TypeId::of::<DDyn>());
81+ /// ```
4382pub trait DAdd < D >
4483{
84+ /// The result of the type-level addition of two dimensionalities.
4585 type Output : Dimensionality ;
4686}
4787
88+ /// Takes the maximum of two dimensionalities at compile time.
89+ ///
90+ /// The maximum of a constant dimensionality and a dynamic dimensionality
91+ /// will always result in a dynamic dimensionality, effectively "erasing"
92+ /// the compile-time knowledge.
93+ ///
94+ /// This type is analogous to the existing [`crate::DimMax`], but specifically
95+ /// for dimensionality instead of `Dimension` types.
96+ ///
97+ /// ## Example
98+ /// ```
99+ /// use ndarray::layout::dimensionality::*;
100+ /// use core::any::TypeId;
101+ ///
102+ /// type Added = <D1 as DMax<D2>>::Output;
103+ /// assert_eq!(TypeId::of::<Added>(), TypeId::of::<D2>());
104+ ///
105+ /// type AddedDyn = <D1 as DMax<DDyn>>::Output;
106+ /// assert_eq!(TypeId::of::<AddedDyn>(), TypeId::of::<DDyn>());
107+ /// ```
48108pub trait DMax < D >
49109{
110+ /// The result of the type-level maximum of two dimensionalities.
50111 type Output : Dimensionality ;
51112}
52113
53114/// The N-dimensional static dimensionality.
54115///
55- /// This type indicates dimensionalities that are known at compile-time.
116+ /// This type captures dimensionalities that are known at compile-time.
56117#[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
57118pub struct NDim < const N : usize > ;
58119
120+ /// The 0-dimensionality, for "dimensionless" arrays with a single value.
121+ ///
122+ /// See [`Dimensionality`] and [`NDim`] for more information.
59123pub type D0 = NDim < 0 > ;
60- pub type D1 = NDim < 1 > ;
61- pub type D2 = NDim < 2 > ;
62- pub type D3 = NDim < 3 > ;
63- pub type D4 = NDim < 4 > ;
64- pub type D5 = NDim < 5 > ;
65- pub type D6 = NDim < 6 > ;
66- pub type D7 = NDim < 7 > ;
67- pub type D8 = NDim < 8 > ;
68- pub type D9 = NDim < 9 > ;
69- pub type D10 = NDim < 10 > ;
70- pub type D11 = NDim < 11 > ;
71- pub type D12 = NDim < 12 > ;
72124
125+ macro_rules! def_d_aliases {
126+ ( $( ( $alias: ident, $N: literal) ) ,* ) => {
127+ $(
128+ /// A dimensionality for arrays that are
129+ #[ doc = stringify!( $N) ]
130+ /// D.
131+ ///
132+ /// See [`Dimensionality`] and [`NDim`] for more information.
133+ pub type $alias = NDim <$N>;
134+ ) +
135+ } ;
136+ }
137+
138+ def_d_aliases ! (
139+ ( D1 , 1 ) ,
140+ ( D2 , 2 ) ,
141+ ( D3 , 3 ) ,
142+ ( D4 , 4 ) ,
143+ ( D5 , 5 ) ,
144+ ( D6 , 6 ) ,
145+ ( D7 , 7 ) ,
146+ ( D8 , 8 ) ,
147+ ( D9 , 9 ) ,
148+ ( D10 , 10 ) ,
149+ ( D11 , 11 ) ,
150+ ( D12 , 12 )
151+ ) ;
152+
153+ /// Implement addition for a given dimensionality.
73154macro_rules! impl_add {
74155 ( $left: literal, ( $( $right: literal) ,* ) , ddyn: ( $( $rightd: literal) ,* ) ) => {
75156 $(
@@ -91,19 +172,19 @@ macro_rules! impl_add {
91172// There's got to be a macro way to do this in one line to help with
92173// any future additions of extra dimenions, although it might
93174// also slow down compile times.
94- impl_add ! ( 0 , ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) , ddyn: ( ) ) ;
95- impl_add ! ( 1 , ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 ) , ddyn: ( 12 ) ) ;
96- impl_add ! ( 2 , ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ) , ddyn: ( 11 , 12 ) ) ;
97- impl_add ! ( 3 , ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ) , ddyn: ( 10 , 11 , 12 ) ) ;
98- impl_add ! ( 4 , ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ) , ddyn: ( 9 , 10 , 11 , 12 ) ) ;
99- impl_add ! ( 5 , ( 1 , 2 , 3 , 4 , 5 , 6 , 7 ) , ddyn: ( 8 , 9 , 10 , 11 , 12 ) ) ;
100- impl_add ! ( 6 , ( 1 , 2 , 3 , 4 , 5 , 6 ) , ddyn: ( 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
101- impl_add ! ( 7 , ( 1 , 2 , 3 , 4 , 5 ) , ddyn: ( 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
102- impl_add ! ( 8 , ( 1 , 2 , 3 , 4 ) , ddyn: ( 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
103- impl_add ! ( 9 , ( 1 , 2 , 3 ) , ddyn: ( 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
104- impl_add ! ( 10 , ( 1 , 2 ) , ddyn: ( 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
105- impl_add ! ( 11 , ( 1 ) , ddyn: ( 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
106- impl_add ! ( 12 , ( ) , ddyn: ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
175+ impl_add ! ( 0 , ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) , ddyn: ( ) ) ;
176+ impl_add ! ( 1 , ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 ) , ddyn: ( 12 ) ) ;
177+ impl_add ! ( 2 , ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 ) , ddyn: ( 11 , 12 ) ) ;
178+ impl_add ! ( 3 , ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 ) , ddyn: ( 10 , 11 , 12 ) ) ;
179+ impl_add ! ( 4 , ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 ) , ddyn: ( 9 , 10 , 11 , 12 ) ) ;
180+ impl_add ! ( 5 , ( 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 ) , ddyn: ( 8 , 9 , 10 , 11 , 12 ) ) ;
181+ impl_add ! ( 6 , ( 0 , 1 , 2 , 3 , 4 , 5 , 6 ) , ddyn: ( 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
182+ impl_add ! ( 7 , ( 0 , 1 , 2 , 3 , 4 , 5 ) , ddyn: ( 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
183+ impl_add ! ( 8 , ( 0 , 1 , 2 , 3 , 4 ) , ddyn: ( 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
184+ impl_add ! ( 9 , ( 0 , 1 , 2 , 3 ) , ddyn: ( 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
185+ impl_add ! ( 10 , ( 0 , 1 , 2 ) , ddyn: ( 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
186+ impl_add ! ( 11 , ( 0 , 1 ) , ddyn: ( 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
187+ impl_add ! ( 12 , ( 0 ) , ddyn: ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ) ;
107188
108189macro_rules! impl_max {
109190 // Base case, just a target with some lowers
@@ -153,7 +234,7 @@ macro_rules! impl_max {
153234 } ;
154235}
155236
156- impl_max ! ( target: 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ;
237+ impl_max ! ( target: 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 , 12 ) ;
157238
158239impl < const N : usize > DMax < NDim < N > > for NDim < N >
159240where NDim < N > : Dimensionality
@@ -176,16 +257,16 @@ macro_rules! impl_dimensionality {
176257 } ;
177258}
178259
179- impl Dimensionality for D1
260+ impl Dimensionality for D0
180261{
181- const N : Option < usize > = Some ( 1 ) ;
262+ const N : Option < usize > = Some ( 0 ) ;
182263
183264 type Smaller = Self ;
184265
185- type Larger = D2 ;
266+ type Larger = D1 ;
186267}
187268
188- impl_dimensionality ! ( 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 ) ;
269+ impl_dimensionality ! ( 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 , 9 , 10 , 11 ) ;
189270
190271impl Dimensionality for NDim < 12 >
191272{
@@ -198,8 +279,13 @@ impl Dimensionality for NDim<12>
198279
199280/// The dynamic dimensionality.
200281///
201- /// This type indicates dimensionalities that can only be known at runtime .
282+ /// This type captures dimensionalities that are unknown at compile-time .
202283/// See [`Dimensionality`] for more information.
284+ ///
285+ /// This type does not carry any information about runtime dimensionality,
286+ /// it just indicate that dimensionality is not known at compile-time.
287+ /// This is done to avoid multiple sources of truth for runtime array
288+ /// dimensionality.
203289#[ derive( Debug , Clone , Copy , PartialEq , Eq , PartialOrd , Ord ) ]
204290pub struct DDyn ;
205291
0 commit comments