Skip to main content

mdarray/
view.rs

1use core::borrow::{Borrow, BorrowMut};
2use core::fmt::{self, Debug, Formatter};
3use core::hash::{Hash, Hasher};
4use core::marker::PhantomData;
5use core::ops::{Deref, DerefMut, Index, IndexMut};
6use core::slice;
7
8use crate::dim::{Const, Dim, Dyn};
9use crate::expr::{Apply, Expression, IntoExpression, Iter, Map, Zip};
10use crate::index::{self, Axis, DimIndex, Permutation, SliceIndex, Split, ViewIndex};
11use crate::layout::{Dense, Layout, Strided};
12use crate::mapping::{DenseMapping, Mapping, StridedMapping};
13use crate::raw_slice::RawSlice;
14use crate::shape::{DynRank, IntoShape, Rank, Shape};
15use crate::slice::Slice;
16
17/// Multidimensional array view.
18pub struct View<'a, T, S: Shape = DynRank, L: Layout = Dense> {
19    slice: RawSlice<T, S, L>,
20    phantom: PhantomData<&'a T>,
21}
22
23/// Mutable multidimensional array view.
24pub struct ViewMut<'a, T, S: Shape = DynRank, L: Layout = Dense> {
25    slice: RawSlice<T, S, L>,
26    phantom: PhantomData<&'a mut T>,
27}
28
29/// Multidimensional array view with dynamically-sized dimensions.
30pub type DView<'a, T, const N: usize, L = Dense> = View<'a, T, Rank<N>, L>;
31
32/// Mutable multidimensional array view with dynamically-sized dimensions.
33pub type DViewMut<'a, T, const N: usize, L = Dense> = ViewMut<'a, T, Rank<N>, L>;
34
35macro_rules! impl_view {
36    ($name:tt, $as_ptr:tt, $from_raw_parts:tt, $raw_mut:tt, {$($mut:tt)?}, $repeatable:tt) => {
37        impl<'a, T, S: Shape, L: Layout> $name<'a, T, S, L> {
38            /// Converts the array view into a new array view indexing the first dimension.
39            ///
40            /// # Panics
41            ///
42            /// Panics if the index is out of bounds, or if the rank is not at least 1.
43            #[inline]
44            pub fn into_at(
45                self,
46                index: usize,
47            ) -> $name<'a, T, S::Tail, L> {
48                self.into_axis_at(Const::<0>, index)
49            }
50
51            /// Converts the array view into a new array view indexing the specified dimension.
52            ///
53            /// If the dimension to be indexed is know at compile time, the resulting array shape
54            /// will maintain constant-sized dimensions. Furthermore, if it is the first dimension
55            /// the resulting array view has the same layout as the input.
56            ///
57            /// # Panics
58            ///
59            /// Panics if the dimension or the index is out of bounds.
60            #[inline]
61            pub fn into_axis_at<A: Axis>(
62                $($mut)? self,
63                axis: A,
64                index: usize,
65            ) -> $name<'a, T, A::Remove<S>, Split<A, S, L>> {
66                unsafe { Self::axis_at(self.$as_ptr(), self.mapping(), axis, index) }
67            }
68
69            /// Converts the array view into a new array view for the specified column.
70            ///
71            /// # Panics
72            ///
73            /// Panics if the rank is not equal to 2, or if the index is out of bounds.
74            #[inline]
75            pub fn into_col(self, index: usize) -> $name<'a, T, (S::Head,), Strided> {
76                let shape = self.shape().with_dims(<(_, <S::Tail as Shape>::Head)>::from_dims);
77
78                self.into_shape(shape).into_view(.., index)
79            }
80
81            /// Converts the array view into a new array view for the given diagonal,
82            /// where `index` > 0 is above and `index` < 0 is below the main diagonal.
83            ///
84            /// # Panics
85            ///
86            /// Panics if the rank is not equal to 2, or if the absolute index is larger
87            /// than the number of columns or rows.
88            #[inline]
89            pub fn into_diag($($mut)? self, index: isize) -> $name<'a, T, (Dyn,), Strided> {
90                assert!(self.rank() == 2, "invalid rank");
91
92                let (offset, len) = if index >= 0 {
93                    assert!(index as usize <= self.dim(1), "invalid diagonal");
94
95                    (index * self.stride(1), self.dim(0).min(self.dim(1) - (index as usize)))
96                } else {
97                    assert!(-index as usize <= self.dim(0), "invalid diagonal");
98
99                    (-index * self.stride(0), self.dim(1).min(self.dim(0) - (-index as usize)))
100                };
101
102                let count = if len > 0 { offset } else { 0 }; // Offset pointer if non-empty.
103                let mapping = StridedMapping::new((len,), &[self.stride(0) + self.stride(1)]);
104
105                unsafe { $name::new_unchecked(self.$as_ptr().offset(count), mapping) }
106            }
107
108            /// Converts the array view into an array view with dynamic rank.
109            #[inline]
110            pub fn into_dyn(self) -> $name<'a, T, DynRank, L> {
111                self.into_mapping()
112            }
113
114            /// Converts the array view into a one-dimensional array view.
115            ///
116            /// # Panics
117            ///
118            /// Panics if the array layout is not uniformly strided.
119            #[inline]
120            pub fn into_flat(self) -> $name<'a, T, (Dyn,), L> {
121                let len = self.len();
122
123                self.into_shape([len])
124            }
125
126            /// Converts the array view into a remapped array view.
127            ///
128            /// # Panics
129            ///
130            /// Panics if the shape is not matching static rank or constant-sized dimensions,
131            /// or if the memory layout is not compatible with the new array layout.
132            #[inline]
133            pub fn into_mapping<R: Shape, K: Layout>($($mut)? self) -> $name<'a, T, R, K> {
134                let mapping = Mapping::remap(self.mapping());
135
136                unsafe { $name::new_unchecked(self.$as_ptr(), mapping) }
137            }
138
139            /// Converts the array view into a new array view with the dimensions permuted.
140            ///
141            /// If the permutation is an identity permutation and known at compile time, the
142            /// resulting array view has the same layout as the input. For example, permuting
143            /// with `(Const::<0>, Const::<1>)` will maintain the layout while permuting with
144            /// `[0, 1]` gives strided layout.
145            ///
146            /// # Panics
147            ///
148            /// Panics if the permutation is not valid.
149            #[inline]
150            pub fn into_permuted<I: IntoShape<IntoShape: Permutation>>(
151                $($mut)? self,
152                perm: I,
153            ) -> $name<
154                'a,
155                T,
156                <I::IntoShape as Permutation>::Shape<S>,
157                <I::IntoShape as Permutation>::Layout<L>,
158            > {
159                let mapping = perm.into_dims(|dims| Mapping::permute(self.mapping(), dims));
160
161                unsafe { $name::new_unchecked(self.$as_ptr(), mapping) }
162            }
163
164            /// Converts the array view into a reordered array view.
165            ///
166            /// This method is deprecated, use `into_transposed` instead.
167            #[deprecated]
168            #[inline]
169            pub fn into_reordered(
170                $($mut)? self
171            ) -> $name<'a, T, S::Reverse, <S::Tail as Shape>::Layout<L>> {
172                let mapping = Mapping::transpose(self.mapping());
173
174                unsafe { $name::new_unchecked(self.$as_ptr(), mapping) }
175            }
176
177            /// Converts the array view into a new array view for the specified row.
178            ///
179            /// # Panics
180            ///
181            /// Panics if the rank is not equal to 2, or if the index is out of bounds.
182            #[inline]
183            pub fn into_row(self, index: usize) -> $name<'a, T, (<S::Tail as Shape>::Head,), L> {
184                let shape = self.shape().with_dims(<(S::Head, _)>::from_dims);
185
186                self.into_shape(shape).into_view(index, ..)
187            }
188
189            /// Converts the array view into a reshaped array view.
190            ///
191            /// At most one dimension can have dynamic size `usize::MAX`, and is then inferred
192            /// from the other dimensions and the array length.
193            ///
194            /// # Examples
195            ///
196            /// ```
197            /// use mdarray::view;
198            ///
199            /// let v = view![[1, 2, 3], [4, 5, 6]];
200            ///
201            /// assert_eq!(v.into_shape([!0, 2]), view![[1, 2], [3, 4], [5, 6]]);
202            /// ```
203            ///
204            /// # Panics
205            ///
206            /// Panics if the array length is changed, or if the memory layout is not compatible.
207            #[inline]
208            pub fn into_shape<I: IntoShape>(
209                $($mut)? self,
210                shape: I
211            ) -> $name<'a, T, I::IntoShape, L> {
212                let mapping = self.mapping().reshape(shape.into_shape());
213
214                unsafe { $name::new_unchecked(self.$as_ptr(), mapping) }
215            }
216
217            /// Divides the array view into two at an index along the first dimension.
218            ///
219            /// # Panics
220            ///
221            /// Panics if the split point is larger than the number of elements in that dimension,
222            /// or if the rank is not at least 1.
223            #[inline]
224            pub fn into_split_at(
225                self,
226                mid: usize,
227            ) -> (
228                $name<'a, T, <S::Tail as Shape>::Prepend<Dyn>, L>,
229                $name<'a, T, <S::Tail as Shape>::Prepend<Dyn>, L>,
230            ) {
231                self.into_split_axis_at(Const::<0>, mid)
232            }
233
234            /// Divides the array view into two at an index along the specified dimension.
235            ///
236            /// If the dimension to be divided is know at compile time, the resulting array
237            /// shape will maintain constant-sized dimensions. Furthermore, if it is the first
238            /// dimension the resulting array views have the same layout as the input.
239            ///
240            /// # Panics
241            ///
242            /// Panics if the split point is larger than the number of elements in that dimension,
243            /// or if the dimension is out of bounds.
244            #[inline]
245            pub fn into_split_axis_at<A: Axis>(
246                $($mut)? self,
247                axis: A,
248                mid: usize,
249            ) -> (
250                $name<'a, T, A::Resize<Dyn, S>, Split<A, S, L>>,
251                $name<'a, T, A::Resize<Dyn, S>, Split<A, S, L>>,
252            ) {
253                unsafe { Self::split_axis_at(self.$as_ptr(), self.mapping(), axis, mid) }
254            }
255
256            /// Converts the array view into a transposed array view, where the dimensions
257            /// are reversed.
258            #[inline]
259            pub fn into_transposed(
260                $($mut)? self
261            ) -> $name<'a, T, S::Reverse, <S::Tail as Shape>::Layout<L>> {
262                let mapping = Mapping::transpose(self.mapping());
263
264                unsafe { $name::new_unchecked(self.$as_ptr(), mapping) }
265            }
266
267            /// Creates an array view from a raw pointer and layout.
268            ///
269            /// # Safety
270            ///
271            /// The pointer must be non-null and a valid array view for the given layout.
272            #[inline]
273            pub unsafe fn new_unchecked(ptr: *$raw_mut T, mapping: L::Mapping<S>) -> Self {
274                let slice = unsafe { RawSlice::new_unchecked(ptr as *mut T, mapping) };
275
276                Self { slice, phantom: PhantomData }
277            }
278
279            #[inline]
280            pub(crate) unsafe fn axis_at<A: Axis>(
281                ptr: *$raw_mut T,
282                mapping: &L::Mapping<S>,
283                axis: A,
284                index: usize,
285            ) -> $name<'a, T, A::Remove<S>, Split<A, S, L>> {
286                let size = mapping.dim(axis.index(mapping.rank()));
287
288                if index >= size {
289                    index::panic_bounds_check(index, size);
290                }
291
292                let new_mapping = axis.remove(mapping);
293
294                // Calculate offset for the new view if non-empty.
295                let offset = mapping.stride(axis.index(mapping.rank())) * index as isize;
296                let count = if new_mapping.is_empty() { 0 } else { offset };
297
298                unsafe { $name::new_unchecked(ptr.offset(count), new_mapping) }
299            }
300
301            #[inline]
302            pub(crate) unsafe fn split_axis_at<A: Axis>(
303                ptr: *$raw_mut T,
304                mapping: &L::Mapping<S>,
305                axis: A,
306                mid: usize,
307            ) -> (
308                $name<'a, T, A::Resize<Dyn, S>, Split<A, S, L>>,
309                $name<'a, T, A::Resize<Dyn, S>, Split<A, S, L>>,
310            ) {
311                let index = axis.index(mapping.rank());
312                let size = mapping.dim(index);
313
314                if mid > size {
315                    index::panic_bounds_check(mid, size);
316                }
317
318                let first_mapping = axis.resize(mapping, mid);
319                let second_mapping = axis.resize(mapping, size - mid);
320
321                // Calculate offset for the second view if non-empty.
322                let offset = mapping.stride(index) * mid as isize;
323                let count = if second_mapping.is_empty() { 0 } else { offset };
324
325                unsafe {
326                    let first = $name::new_unchecked(ptr, first_mapping);
327                    let second = $name::new_unchecked(ptr.offset(count), second_mapping);
328
329                    (first, second)
330                }
331            }
332        }
333
334        impl<'a, T, U, S: Shape, L: Layout> Apply<U> for &'a $name<'_, T, S, L> {
335            type Output<F: FnMut(&'a T) -> U> = Map<Self::IntoExpr, F>;
336            type ZippedWith<I: IntoExpression, F: FnMut((&'a T, I::Item)) -> U> =
337                Map<Zip<Self::IntoExpr, I::IntoExpr>, F>;
338
339            #[inline]
340            fn apply<F: FnMut(&'a T) -> U>(self, f: F) -> Self::Output<F> {
341                self.expr().map(f)
342            }
343
344            #[inline]
345            fn zip_with<I: IntoExpression, F>(self, expr: I, f: F) -> Self::ZippedWith<I, F>
346            where
347                F: FnMut((&'a T, I::Item)) -> U,
348            {
349                self.expr().zip(expr).map(f)
350            }
351        }
352
353        impl<T, U: ?Sized, S: Shape, L: Layout> AsRef<U> for $name<'_, T, S, L>
354        where
355            Slice<T, S, L>: AsRef<U>,
356        {
357            #[inline]
358            fn as_ref(&self) -> &U {
359                (**self).as_ref()
360            }
361        }
362
363        impl<T, S: Shape, L: Layout> Borrow<Slice<T, S, L>> for $name<'_, T, S, L> {
364            #[inline]
365            fn borrow(&self) -> &Slice<T, S, L> {
366                self
367            }
368        }
369
370        impl<T: Debug, S: Shape, L: Layout> Debug for $name<'_, T, S, L> {
371            fn fmt(&self, f: &mut Formatter) -> fmt::Result {
372                (**self).fmt(f)
373            }
374        }
375
376        impl<T, S: Shape, L: Layout> Deref for $name<'_, T, S, L> {
377            type Target = Slice<T, S, L>;
378
379            #[inline]
380            fn deref(&self) -> &Self::Target {
381                self.slice.as_slice()
382            }
383        }
384
385        impl<'a, T, S: Shape, L: Layout> Expression for $name<'a, T, S, L> {
386            type Shape = S;
387
388            const IS_REPEATABLE: bool = $repeatable;
389
390            #[inline]
391            fn shape(&self) -> &S {
392                (**self).shape()
393            }
394
395            #[inline]
396            unsafe fn get_unchecked(&mut self, index: usize) -> &'a $($mut)? T {
397                let count = self.slice.mapping().inner_stride() * index as isize;
398
399                unsafe { &$($mut)? *self.slice.$as_ptr().offset(count) }
400            }
401
402            #[inline]
403            fn inner_rank(&self) -> usize {
404                if L::IS_DENSE {
405                    // For static rank 0, the inner stride is 0 so we allow inner rank >0.
406                    if S::RANK == Some(0) { usize::MAX } else { self.rank() }
407                } else {
408                    // For rank 0, the inner stride is always 0 so we can allow inner rank >0.
409                    if self.rank() > 0 { 1 } else { usize::MAX }
410                }
411            }
412
413            #[inline]
414            unsafe fn reset_dim(&mut self, index: usize, count: usize) {
415                let count = -self.stride(index) * count as isize;
416                let ptr = self.slice.as_mut_ptr();
417
418                unsafe {
419                    self.slice.set_ptr(ptr.offset(count));
420                }
421            }
422
423            #[inline]
424            unsafe fn step_dim(&mut self, index: usize) {
425                let ptr = self.slice.as_mut_ptr();
426
427                unsafe {
428                    self.slice.set_ptr(ptr.offset(self.stride(index)));
429                }
430            }
431        }
432
433        impl<'a, T, S: Shape, L: Layout, I> From<&'a $($mut)? I> for $name<'a, T, S, L>
434        where
435            &'a $($mut)? I: IntoExpression<IntoExpr = $name<'a, T, S, L>>
436        {
437            #[inline]
438            fn from(value: &'a $($mut)? I) -> Self {
439                value.into_expr()
440            }
441        }
442
443        impl<'a, T> From<&'a $($mut)? [T]> for $name<'a, T, (Dyn,)> {
444            #[inline]
445            fn from(value: &'a $($mut)? [T]) -> Self {
446                let mapping = DenseMapping::new((value.len(),));
447
448                unsafe { Self::new_unchecked(value.$as_ptr(), mapping) }
449            }
450        }
451
452        impl<'a, T, D: Dim> From<$name<'a, T, (D,)>> for &'a $($mut)? [T] {
453            #[inline]
454            fn from($($mut)? value: $name<T, (D,)>) -> Self {
455                unsafe { slice::$from_raw_parts(value.$as_ptr(), value.len()) }
456            }
457        }
458
459        impl<T: Hash, S: Shape, L: Layout> Hash for $name<'_, T, S, L> {
460            #[inline]
461            fn hash<H: Hasher>(&self, state: &mut H) {
462                (**self).hash(state)
463            }
464        }
465
466        impl<T, S: Shape, L: Layout, I: SliceIndex<T, S, L>> Index<I> for $name<'_, T, S, L> {
467            type Output = I::Output;
468
469            #[inline]
470            fn index(&self, index: I) -> &I::Output {
471                index.index(self)
472            }
473        }
474
475        impl<'a, T, S: Shape, L: Layout> IntoExpression for &'a $name<'_, T, S, L> {
476            type Shape = S;
477            type IntoExpr = View<'a, T, S, L>;
478
479            #[inline]
480            fn into_expr(self) -> Self::IntoExpr {
481                self.expr()
482            }
483        }
484
485        impl<'a, T, S: Shape, L: Layout> IntoIterator for &'a $name<'_, T, S, L> {
486            type Item = &'a T;
487            type IntoIter = Iter<View<'a, T, S, L>>;
488
489            #[inline]
490            fn into_iter(self) -> Self::IntoIter {
491                self.expr().into_iter()
492            }
493        }
494
495        impl<'a, T, S: Shape, L: Layout> IntoIterator for $name<'a, T, S, L> {
496            type Item = &'a $($mut)? T;
497            type IntoIter = Iter<Self>;
498
499            #[inline]
500            fn into_iter(self) -> Iter<Self> {
501                Iter::new(self)
502            }
503        }
504    };
505}
506
507impl_view!(View, as_ptr, from_raw_parts, const, {}, true);
508impl_view!(ViewMut, as_mut_ptr, from_raw_parts_mut, mut, {mut}, false);
509
510macro_rules! impl_into_view {
511    ($n:tt, ($($xyz:tt),+), ($($abc:tt),+), ($($idx:tt),+)) => {
512        impl<'a, T, $($xyz: Dim,)+ L: Layout> View<'a, T, ($($xyz,)+), L> {
513            /// Converts the array view into a new array view for the specified subarray.
514            ///
515            /// # Panics
516            ///
517            /// Panics if the subarray is out of bounds.
518            #[inline]
519            pub fn into_view<$($abc: DimIndex),+>(
520                self,
521                $($idx: $abc),+
522            ) -> View<
523                'a,
524                T,
525                <($($abc,)+) as ViewIndex>::Shape<($($xyz,)+)>,
526                <($($abc,)+) as ViewIndex>::Layout<L>,
527            > {
528                let (offset, mapping) = ($($idx,)+).view_index(self.mapping());
529
530                // If the view is empty, we must not offset the pointer.
531                let count = if mapping.is_empty() { 0 } else { offset };
532
533                unsafe { View::new_unchecked(self.as_ptr().offset(count), mapping) }
534            }
535        }
536
537        impl<'a, T, $($xyz: Dim,)+ L: Layout> ViewMut<'a, T, ($($xyz,)+), L> {
538            /// Converts the array view into a new array view for the specified subarray.
539            ///
540            /// # Panics
541            ///
542            /// Panics if the subarray is out of bounds.
543            #[inline]
544            pub fn into_view<$($abc: DimIndex),+>(
545                mut self,
546                $($idx: $abc),+
547            ) -> ViewMut<
548                'a,
549                T,
550                <($($abc,)+) as ViewIndex>::Shape<($($xyz,)+)>,
551                <($($abc,)+) as ViewIndex>::Layout<L>,
552            > {
553                let (offset, mapping) = ($($idx,)+).view_index(self.mapping());
554
555                // If the view is empty, we must not offset the pointer.
556                let count = if mapping.is_empty() { 0 } else { offset };
557
558                unsafe { ViewMut::new_unchecked(self.as_mut_ptr().offset(count), mapping) }
559            }
560        }
561    };
562}
563
564impl_into_view!(1, (X), (A), (a));
565impl_into_view!(2, (X, Y), (A, B), (a, b));
566impl_into_view!(3, (X, Y, Z), (A, B, C), (a, b, c));
567impl_into_view!(4, (X, Y, Z, W), (A, B, C, D), (a, b, c, d));
568impl_into_view!(5, (X, Y, Z, W, U), (A, B, C, D, E), (a, b, c, d, e));
569impl_into_view!(6, (X, Y, Z, W, U, V), (A, B, C, D, E, F), (a, b, c, d, e, f));
570
571impl<'a, T, U, S: Shape, L: Layout> Apply<U> for &'a mut ViewMut<'_, T, S, L> {
572    type Output<F: FnMut(&'a mut T) -> U> = Map<Self::IntoExpr, F>;
573    type ZippedWith<I: IntoExpression, F: FnMut((&'a mut T, I::Item)) -> U> =
574        Map<Zip<Self::IntoExpr, I::IntoExpr>, F>;
575
576    #[inline]
577    fn apply<F: FnMut(&'a mut T) -> U>(self, f: F) -> Self::Output<F> {
578        self.expr_mut().map(f)
579    }
580
581    #[inline]
582    fn zip_with<I: IntoExpression, F>(self, expr: I, f: F) -> Self::ZippedWith<I, F>
583    where
584        F: FnMut((&'a mut T, I::Item)) -> U,
585    {
586        self.expr_mut().zip(expr).map(f)
587    }
588}
589
590impl<T, U: ?Sized, S: Shape, L: Layout> AsMut<U> for ViewMut<'_, T, S, L>
591where
592    Slice<T, S, L>: AsMut<U>,
593{
594    #[inline]
595    fn as_mut(&mut self) -> &mut U {
596        (**self).as_mut()
597    }
598}
599
600impl<T, S: Shape, L: Layout> BorrowMut<Slice<T, S, L>> for ViewMut<'_, T, S, L> {
601    #[inline]
602    fn borrow_mut(&mut self) -> &mut Slice<T, S, L> {
603        self
604    }
605}
606
607impl<T, S: Shape, L: Layout> Clone for View<'_, T, S, L> {
608    #[inline]
609    fn clone(&self) -> Self {
610        Self { slice: self.slice.clone(), phantom: PhantomData }
611    }
612
613    #[inline]
614    fn clone_from(&mut self, source: &Self) {
615        self.slice.clone_from(&source.slice);
616    }
617}
618
619impl<T, S: Shape, L: Layout<Mapping<S>: Copy>> Copy for View<'_, T, S, L> {}
620
621impl<T, S: Shape, L: Layout> DerefMut for ViewMut<'_, T, S, L> {
622    #[inline]
623    fn deref_mut(&mut self) -> &mut Self::Target {
624        self.slice.as_mut_slice()
625    }
626}
627
628macro_rules! impl_from_array_ref {
629    (($($xyz:tt),+), ($($abc:tt),+), $array:tt) => {
630        impl<'a, T $(,$xyz: Dim + From<Const<$abc>>)+ $(,const $abc: usize)+> From<&'a $array>
631            for View<'a, T, ($($xyz,)+)>
632        {
633            #[inline]
634            fn from(value: &'a $array) -> Self {
635                let mapping = DenseMapping::new(($($xyz::from(Const::<$abc>),)+));
636
637                _ = mapping.shape().checked_len().expect("invalid length");
638
639                unsafe { Self::new_unchecked(value.as_ptr().cast(), mapping) }
640            }
641        }
642
643        impl<'a, T $(,$xyz: Dim + From<Const<$abc>>)+ $(,const $abc: usize)+> From<&'a mut $array>
644            for ViewMut<'a, T, ($($xyz,)+)>
645        {
646            #[inline]
647            fn from(value: &'a mut $array) -> Self {
648                let mapping = DenseMapping::new(($($xyz::from(Const::<$abc>),)+));
649
650                _ = mapping.shape().checked_len().expect("invalid length");
651
652                unsafe { Self::new_unchecked(value.as_mut_ptr().cast(), mapping) }
653            }
654        }
655
656        impl<'a, T $(,const $abc: usize)+> From<View<'a, T, ($(Const<$abc>,)+)>> for &'a $array {
657            #[inline]
658            fn from(value: View<'a, T, ($(Const<$abc>,)+)>) -> Self {
659                unsafe { &*value.as_ptr().cast() }
660            }
661        }
662
663        impl<'a, T $(,const $abc: usize)+> From<ViewMut<'a, T, ($(Const<$abc>,)+)>>
664            for &'a mut $array
665        {
666            #[inline]
667            fn from(mut value: ViewMut<'a, T, ($(Const<$abc>,)+)>) -> Self {
668                unsafe { &mut *value.as_mut_ptr().cast() }
669            }
670        }
671    };
672}
673
674impl_from_array_ref!((X), (A), [T; A]);
675impl_from_array_ref!((X, Y), (A, B), [[T; B]; A]);
676impl_from_array_ref!((X, Y, Z), (A, B, C), [[[T; C]; B]; A]);
677impl_from_array_ref!((X, Y, Z, W), (A, B, C, D), [[[[T; D]; C]; B]; A]);
678impl_from_array_ref!((X, Y, Z, W, U), (A, B, C, D, E), [[[[[T; E]; D]; C]; B]; A]);
679impl_from_array_ref!((X, Y, Z, W, U, V), (A, B, C, D, E, F), [[[[[[T; F]; E]; D]; C]; B]; A]);
680
681impl<T, S: Shape, L: Layout, I: SliceIndex<T, S, L>> IndexMut<I> for ViewMut<'_, T, S, L> {
682    #[inline]
683    fn index_mut(&mut self, index: I) -> &mut I::Output {
684        index.index_mut(self)
685    }
686}
687
688impl<'a, T, S: Shape, L: Layout> IntoExpression for &'a mut ViewMut<'_, T, S, L> {
689    type Shape = S;
690    type IntoExpr = ViewMut<'a, T, S, L>;
691
692    #[inline]
693    fn into_expr(self) -> Self::IntoExpr {
694        self.expr_mut()
695    }
696}
697
698impl<'a, T, S: Shape, L: Layout> IntoIterator for &'a mut ViewMut<'_, T, S, L> {
699    type Item = &'a mut T;
700    type IntoIter = Iter<ViewMut<'a, T, S, L>>;
701
702    #[inline]
703    fn into_iter(self) -> Self::IntoIter {
704        self.expr_mut().into_iter()
705    }
706}
707
708unsafe impl<T: Sync, S: Shape, L: Layout> Send for View<'_, T, S, L> {}
709unsafe impl<T: Sync, S: Shape, L: Layout> Sync for View<'_, T, S, L> {}
710
711unsafe impl<T: Send, S: Shape, L: Layout> Send for ViewMut<'_, T, S, L> {}
712unsafe impl<T: Sync, S: Shape, L: Layout> Sync for ViewMut<'_, T, S, L> {}