Thanks to visit codestin.com
Credit goes to docs.rs

ndarray/
shape_builder.rs

1use crate::dimension::IntoDimension;
2use crate::order::Order;
3use crate::Dimension;
4
5/// A contiguous array shape of n dimensions.
6///
7/// Either c- or f- memory ordered (*c* a.k.a *row major* is the default).
8#[derive(Copy, Clone, Debug)]
9pub struct Shape<D>
10{
11    /// Shape (axis lengths)
12    pub(crate) dim: D,
13    /// Strides can only be C or F here
14    pub(crate) strides: Strides<Contiguous>,
15}
16
17#[derive(Copy, Clone, Debug)]
18pub(crate) enum Contiguous {}
19
20impl<D> Shape<D>
21{
22    pub(crate) fn is_c(&self) -> bool
23    {
24        matches!(self.strides, Strides::C)
25    }
26}
27
28/// An array shape of n dimensions in c-order, f-order or custom strides.
29#[derive(Copy, Clone, Debug)]
30pub struct StrideShape<D>
31{
32    pub(crate) dim: D,
33    pub(crate) strides: Strides<D>,
34}
35
36impl<D> StrideShape<D>
37where D: Dimension
38{
39    /// Return a reference to the dimension
40    pub fn raw_dim(&self) -> &D
41    {
42        &self.dim
43    }
44    /// Return the size of the shape in number of elements
45    pub fn size(&self) -> usize
46    {
47        self.dim.size()
48    }
49}
50
51/// Stride description
52#[derive(Copy, Clone, Debug)]
53pub(crate) enum Strides<D>
54{
55    /// Row-major ("C"-order)
56    C,
57    /// Column-major ("F"-order)
58    F,
59    /// Custom strides
60    Custom(D),
61}
62
63impl<D> Strides<D>
64{
65    /// Return strides for `dim` (computed from dimension if c/f, else return the custom stride)
66    pub(crate) fn strides_for_dim(self, dim: &D) -> D
67    where D: Dimension
68    {
69        match self {
70            Strides::C => dim.default_strides(),
71            Strides::F => dim.fortran_strides(),
72            Strides::Custom(c) => {
73                debug_assert_eq!(
74                    c.ndim(),
75                    dim.ndim(),
76                    "Custom strides given with {} dimensions, expected {}",
77                    c.ndim(),
78                    dim.ndim()
79                );
80                c
81            }
82        }
83    }
84
85    #[inline]
86    pub(crate) fn is_custom(&self) -> bool
87    {
88        matches!(*self, Strides::Custom(_))
89    }
90}
91
92/// A trait for `Shape` and `D where D: Dimension` that allows
93/// customizing the memory layout (strides) of an array shape.
94///
95/// This trait is used together with array constructor methods like
96/// `Array::from_shape_vec`.
97pub trait ShapeBuilder
98{
99    /// The type that captures the built shape's dimensionality.
100    type Dim: Dimension;
101
102    /// The type that captures the built shape's stride pattern.
103    type Strides;
104
105    /// Turn into a contiguous-element [`Shape`].
106    fn into_shape_with_order(self) -> Shape<Self::Dim>;
107
108    /// Convert into a Fortran-order (a.k.a., column-order) [`Shape`].
109    fn f(self) -> Shape<Self::Dim>;
110
111    /// Set the order of the shape to either Fortran or non-Fortran.
112    fn set_f(self, is_f: bool) -> Shape<Self::Dim>;
113
114    /// Set the strides of the shape.
115    fn strides(self, strides: Self::Strides) -> StrideShape<Self::Dim>;
116}
117
118impl<D> From<D> for Shape<D>
119where D: Dimension
120{
121    /// Create a `Shape` from `dimension`, using the default memory layout.
122    fn from(dimension: D) -> Shape<D>
123    {
124        dimension.into_shape_with_order()
125    }
126}
127
128impl<T, D> From<T> for StrideShape<D>
129where
130    D: Dimension,
131    T: ShapeBuilder<Dim = D>,
132{
133    fn from(value: T) -> Self
134    {
135        let shape = value.into_shape_with_order();
136        let st = if shape.is_c() { Strides::C } else { Strides::F };
137        StrideShape {
138            strides: st,
139            dim: shape.dim,
140        }
141    }
142}
143
144impl<T> ShapeBuilder for T
145where T: IntoDimension
146{
147    type Dim = T::Dim;
148    type Strides = T;
149    fn into_shape_with_order(self) -> Shape<Self::Dim>
150    {
151        Shape {
152            dim: self.into_dimension(),
153            strides: Strides::C,
154        }
155    }
156    fn f(self) -> Shape<Self::Dim>
157    {
158        self.set_f(true)
159    }
160    fn set_f(self, is_f: bool) -> Shape<Self::Dim>
161    {
162        self.into_shape_with_order().set_f(is_f)
163    }
164    fn strides(self, st: T) -> StrideShape<Self::Dim>
165    {
166        self.into_shape_with_order().strides(st.into_dimension())
167    }
168}
169
170impl<D> ShapeBuilder for Shape<D>
171where D: Dimension
172{
173    type Dim = D;
174    type Strides = D;
175
176    fn into_shape_with_order(self) -> Shape<D>
177    {
178        self
179    }
180
181    fn f(self) -> Self
182    {
183        self.set_f(true)
184    }
185
186    fn set_f(mut self, is_f: bool) -> Self
187    {
188        self.strides = if !is_f { Strides::C } else { Strides::F };
189        self
190    }
191
192    fn strides(self, st: D) -> StrideShape<D>
193    {
194        StrideShape {
195            dim: self.dim,
196            strides: Strides::Custom(st),
197        }
198    }
199}
200
201impl<D> Shape<D>
202where D: Dimension
203{
204    /// Return a reference to the dimension
205    pub fn raw_dim(&self) -> &D
206    {
207        &self.dim
208    }
209    /// Return the size of the shape in number of elements
210    pub fn size(&self) -> usize
211    {
212        self.dim.size()
213    }
214}
215
216/// Array shape argument with optional order parameter
217///
218/// Shape or array dimension argument, with optional [`Order`] parameter.
219///
220/// This is an argument conversion trait that is used to accept an array shape and
221/// (optionally) an ordering argument.
222///
223/// See for example [`.to_shape()`](crate::ArrayRef::to_shape).
224pub trait ShapeArg
225{
226    /// The type that captures the shape's dimensionality.
227    type Dim: Dimension;
228
229    /// Convert the argument into a shape and an [`Order`].
230    fn into_shape_and_order(self) -> (Self::Dim, Option<Order>);
231}
232
233impl<T> ShapeArg for T
234where T: IntoDimension
235{
236    type Dim = T::Dim;
237
238    fn into_shape_and_order(self) -> (Self::Dim, Option<Order>)
239    {
240        (self.into_dimension(), None)
241    }
242}
243
244impl<T> ShapeArg for (T, Order)
245where T: IntoDimension
246{
247    type Dim = T::Dim;
248
249    fn into_shape_and_order(self) -> (Self::Dim, Option<Order>)
250    {
251        (self.0.into_dimension(), Some(self.1))
252    }
253}