Skip to content

Commit 55e0e94

Browse files
committed
Add docs and reintroduce the zero-dimensional type
1 parent 465fc26 commit 55e0e94

File tree

3 files changed

+134
-38
lines changed

3 files changed

+134
-38
lines changed

src/layout/dimensionality.rs

Lines changed: 122 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
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+
18
use 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+
/// ```
4382
pub 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+
/// ```
48108
pub 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)]
57118
pub 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.
59123
pub 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.
73154
macro_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

108189
macro_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

158239
impl<const N: usize> DMax<NDim<N>> for NDim<N>
159240
where 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

190271
impl 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)]
204290
pub struct DDyn;
205291

src/layout/mod.rs

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,16 @@
1+
//! Building blocks for describing array layout.
2+
//!
3+
//! This module contains types and traits used to describe how an array is structured in memory.
4+
//! At present, it includes utilities for compactly encoding layout information
5+
//! and abstractions for representing an array’s dimensionality.
6+
//!
7+
//! Over time, this module will also define traits and types for shapes, strides, and complete
8+
//! array layouts, providing a clearer separation between these concerns and enabling more
9+
//! flexible and expressive layout representations.
10+
111
mod bitset;
212
#[cfg(feature = "unstable")]
3-
mod dimensionality;
13+
pub mod dimensionality;
414

515
#[allow(deprecated)]
616
pub use bitset::{Layout, LayoutBitset};

src/lib.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -197,7 +197,7 @@ mod extension;
197197
mod geomspace;
198198
mod indexes;
199199
mod iterators;
200-
mod layout;
200+
pub mod layout;
201201
mod linalg_traits;
202202
mod linspace;
203203
#[cfg(feature = "std")]

0 commit comments

Comments
 (0)