minidx_core/shapes/
shape.rs1use super::{Axes, Axis, HasAxes};
2use super::{Axes2, Axes3, Axes4, Axes5, Axes6};
3use super::{Const, ConstDim, Dim};
4
5pub trait Array<T>: IntoIterator<Item = T> {
7 type Dim: Dim;
8 fn dim(&self) -> Self::Dim;
9}
10impl<T, const N: usize> Array<T> for [T; N] {
11 type Dim = Const<N>;
12 fn dim(&self) -> Self::Dim {
13 Const
14 }
15}
16impl<T> Array<T> for std::vec::Vec<T> {
17 type Dim = usize;
18 fn dim(&self) -> Self::Dim {
19 self.len()
20 }
21}
22
23pub trait Shape:
26 'static
27 + std::fmt::Debug
28 + Clone
29 + Copy
30 + Send
31 + Sync
32 + Eq
33 + PartialEq
34 + HasAxes<Self::AllAxes>
35 + HasAxes<Self::LastAxis> {
38 const NUM_DIMS: usize;
40
41 type Concrete: std::fmt::Debug
43 + Clone
44 + Copy
45 + Default
46 + Eq
47 + PartialEq
48 + std::ops::Index<usize, Output = usize>
49 + std::ops::IndexMut<usize>
50 + Send
51 + Sync
52 + IntoIterator<Item = usize>
53 + Into<std::vec::Vec<usize>>
54 + AsRef<[usize]>;
55
56 type AllAxes: Axes;
58
59 type LastAxis: Axes;
61
62 fn concrete(&self) -> Self::Concrete;
63 fn from_concrete(concrete: &Self::Concrete) -> Option<Self>;
64
65 #[inline(always)]
67 fn num_elements(&self) -> usize {
68 self.concrete().into_iter().product()
69 }
70
71 #[inline(always)]
73 fn strides(&self) -> Self::Concrete {
74 let sizes = self.concrete();
75 let mut strides: Self::Concrete = Default::default();
76 strides[Self::NUM_DIMS - 1] = 1;
77 for i in (0..(Self::NUM_DIMS - 1)).rev() {
78 strides[i] = strides[i + 1] * sizes[i + 1];
79 }
80 strides
81 }
82}
83
84pub trait ConstShape: Default + Shape {
86 const NUMEL: usize;
87}
88
89pub trait HasShape {
91 type WithShape<New: Shape>: HasShape<Shape = New>;
92 type Shape: Shape;
93 fn shape(&self) -> &Self::Shape;
94}
95
96impl<S: Shape> HasShape for S {
97 type WithShape<New: Shape> = New;
98 type Shape = Self;
99 fn shape(&self) -> &Self::Shape {
100 self
101 }
102}
103
104pub type Rank0 = ();
106pub type Rank1<const M: usize> = (Const<M>,);
108pub type Rank2<const M: usize, const N: usize> = (Const<M>, Const<N>);
110pub type Rank3<const M: usize, const N: usize, const O: usize> = (Const<M>, Const<N>, Const<O>);
112pub type Rank4<const M: usize, const N: usize, const O: usize, const P: usize> =
114 (Const<M>, Const<N>, Const<O>, Const<P>);
115pub type Rank5<const M: usize, const N: usize, const O: usize, const P: usize, const Q: usize> =
117 (Const<M>, Const<N>, Const<O>, Const<P>, Const<Q>);
118#[rustfmt::skip]
119pub type Rank6<const M: usize, const N: usize, const O: usize, const P: usize, const Q: usize, const R: usize> =
121 (Const<M>, Const<N>, Const<O>, Const<P>, Const<Q>, Const<R>);
122
123macro_rules! shape {
124 (($($D:tt $Idx:tt),*), rank=$Num:expr, all=$All:tt) => {
125 impl<$($D: Dim, )*> Shape for ($($D, )*) {
126 const NUM_DIMS: usize = $Num;
127 type Concrete = [usize; $Num];
128 type AllAxes = $All<$($Idx,)*>;
129 type LastAxis = Axis<{$Num - 1}>;
130 #[inline(always)]
131 fn concrete(&self) -> Self::Concrete {
132 [$(self.$Idx.size(), )*]
133 }
134 #[inline(always)]
135 fn from_concrete(concrete: &Self::Concrete) -> Option<Self> {
136 Some(($(Dim::from_size(concrete[$Idx])?, )*))
137 }
138 }
139 impl<$($D: ConstDim, )*> ConstShape for ($($D, )*) {
140 const NUMEL: usize = $($D::SIZE * )* 1;
141 }
142
143 impl Shape for [usize; $Num] {
144 const NUM_DIMS: usize = $Num;
145 type Concrete = Self;
146 type AllAxes = $All<$($Idx,)*>;
147 type LastAxis = Axis<{$Num - 1}>;
148
149 fn concrete(&self) -> Self::Concrete {
150 *self
151 }
152
153 fn from_concrete(concrete: &Self::Concrete) -> Option<Self> {
154 Some(*concrete)
155 }
156 }
157 };
158}
159
160impl Shape for () {
161 const NUM_DIMS: usize = 0;
162 type Concrete = [usize; 0];
163 type AllAxes = Axis<0>;
164 type LastAxis = Axis<0>;
165 #[inline(always)]
166 fn concrete(&self) -> Self::Concrete {
167 []
168 }
169 #[inline(always)]
170 fn strides(&self) -> Self::Concrete {
171 []
172 }
173 #[inline(always)]
174 fn from_concrete(_: &Self::Concrete) -> Option<Self> {
175 Some(())
176 }
177}
178impl ConstShape for () {
179 const NUMEL: usize = 1;
180}
181
182shape!((D1 0), rank=1, all=Axis);
183shape!((D1 0, D2 1), rank=2, all=Axes2);
184shape!((D1 0, D2 1, D3 2), rank=3, all=Axes3);
185shape!((D1 0, D2 1, D3 2, D4 3), rank=4, all=Axes4);
186shape!((D1 0, D2 1, D3 2, D4 3, D5 4), rank=5, all=Axes5);
187shape!((D1 0, D2 1, D3 2, D4 3, D5 4, D6 5), rank=6, all=Axes6);
188
189#[allow(dead_code)]
191pub trait AssertSameNumel<Dst: ConstShape>: ConstShape {
192 const TYPE_CHECK: ();
193 fn assert_same_numel() {
194 #[allow(clippy::let_unit_value)]
195 let _ = <Self as AssertSameNumel<Dst>>::TYPE_CHECK;
196 }
197}
198
199impl<Src: ConstShape, Dst: ConstShape> AssertSameNumel<Dst> for Src {
200 const TYPE_CHECK: () = assert!(Src::NUMEL == Dst::NUMEL);
201}