Skip to main content

matrix_slice/
lib.rs

1//! Implements references to blocks of a matrix.
2//!
3//! Consider a reference to a slice (sometimes also just called slice). Typically, it is created by
4//! unsizing a reference to an array through type coercion, such as sing `&[0, 1, 2]` in a
5//! parameter to function that takes `&[u32]` which turns a reference `&[u32; 3]` to a slice
6//! `&[u32]`. The length of the slice, controlling the number of elements and thus the provenance
7//! of access that the reference allows, is stored in a tag alongside the pointer to its elements
8//! and initialized from the known length of the array. Since this tag is a runtime value we can
9//! manipulate it while upholding the invariants required by the type system.
10//!
11//! This is analogous to that but for blocks of a matrix. A block is a rectangular region of a
12//! matrix where the matrix provides an underlying pitch (or stride) between rows and a total
13//! number of elements and the block the number of rows and columns that are spanned, i.e. are
14//! allowed to be accessed by (mutable) reference.
15//!
16//! ## Treatment of empty blocks
17//!
18//! A block may have zero rows or zero columns. In either case the block is empty and provides no
19//! access to any elements yet will still return an empty slice for some operations that would
20//! otherwise access multiple elements. The memory address of such a block is **not** necessarily
21//! at its expected location but it will be in-bounds of the underlying matrix data.
22//!
23//! Consider the bottom right `2x2` block of a row-major `3x3` matrix.
24//!
25//! ```text
26//! +---+---+---+
27//! | x | x | x |
28//! +---+---+---+
29//! | x | 4 | 5 |
30//! +---+---+---+
31//! | x | 7 | 8 |
32//! +---+---+---+
33//! ```
34//!
35//! This block has a pitch of 3 but only spans 2 columns. If we would naively calculate the address
36//! of its past-the-end element we would get an element below `7` which is out-of-bounds. Hence if
37//! we split this at row 2, into itself and an empty `0x2` block, the latter block's data pointer
38//! would be created with undefined behavior. Instead, we sacrifice the ability to 'locate' such
39//! empty blocks and instead have them point at an arbitrary (empty) in-bounds slice within the
40//! matrix. (Currently, that is the start of the block from which it was created).
41#![no_std]
42use core::{cell::Cell, fmt, marker::PhantomData, ops, ptr::NonNull};
43
44/// The Readme of the crate and links to further documentation.
45///
46/// Note: This module only exists on `cfg(doc)` builds, do not refer to it.
47///
48#[cfg(doc)]
49#[doc = include_str!("../Readme.md")]
50pub mod docs {
51    /// A discussion of the approach, alternatives, trade-offs and context.
52    ///
53    #[doc = include_str!("../docs/development_log.md")]
54    pub const DEVELOPMENT_NOTES: () = ();
55
56    /// Documentation of each released version.
57    ///
58    #[doc = include_str!("../Changes.md")]
59    pub const CHANGELOG: () = ();
60}
61
62/// Create a block reference from a full matrix represented as an array of rows.
63///
64/// # Examples
65///
66/// ```
67/// let data = &mut [
68///    [0, 1, 2],
69///    [3, 4, 5],
70/// ];
71///
72/// let mut block = matrix_slice::from_array_rows(data);
73///
74/// assert_eq!(block.rows(), 2);
75/// assert_eq!(block.cols(), 3);
76///
77/// assert_eq!(block[(1, 1)], 4);
78/// ```
79pub fn from_array_rows<'a, T, const N: usize>(data: &'a [[T; N]]) -> BlockRef<'a, T> {
80    BlockRef {
81        block: BlockSlice {
82            rows: data.len(),
83            cols: N,
84            pitch: N,
85        },
86        data: NonNull::from_ref(data).cast(),
87        lifetime: PhantomData,
88    }
89}
90
91/// A reference to a block of a matrix with shared access to elements.
92#[derive(Copy, Clone)]
93pub struct BlockRef<'a, T> {
94    data: NonNull<T>,
95    block: BlockSlice,
96    lifetime: PhantomData<&'a [T]>,
97}
98
99// SAFETY: See `&[T]`. The reference can be used to, potentially, get a `&T` for each element in
100// the block and thus the block itself provides the exact same properties as `T`. The `BlockRef` is
101// then `&[T]` itself and thus has properties of a reference to such a type. Refer to the
102// reference: <https://doc.rust-lang.org/stable/std/primitive.reference.html>
103//
104// We have `&T: Sync` iff `T: Sync`
105unsafe impl<T> Sync for BlockRef<'_, T> where T: Sync {}
106// We have `&T: Send` iff `T: Sync`
107unsafe impl<T> Send for BlockRef<'_, T> where T: Sync {}
108
109const _: () = {
110    // We can coerce a block to a shorter lifetime.
111    fn _coerce_block<'a, 'b: 'a, T>(v: BlockRef<'b, T>) -> BlockRef<'a, T> {
112        v
113    }
114
115    // We can coerce a reference to a block to a shorter lifetime.
116    fn _coerce_covariant<'lt, 'a, 'b: 'a, T>(v: &'lt BlockRef<'b, T>) -> &'lt BlockRef<'a, T> {
117        v
118    }
119
120    fn _coerce_covariant_fn<'lt, 'a, 'b: 'a, T>(v: fn(BlockRef<'a, T>)) -> fn(BlockRef<'b, T>) {
121        v
122    }
123
124    fn _coerce_item_covariant<'lt, 'a, 'b: 'a, T>(v: BlockRef<'lt, &'b T>) -> BlockRef<'lt, &'a T> {
125        v
126    }
127};
128
129/// Creates an empty block reference, within a matrix of a dangling slice.
130impl<T> Default for BlockRef<'_, T> {
131    fn default() -> Self {
132        from_array_rows::<T, 0>(&[])
133    }
134}
135
136impl<'data, T> BlockRef<'data, T> {
137    /// Create a new block reference from a raw slice and pitch.
138    ///
139    /// The resulting block refers to the whole matrix.
140    ///
141    /// # Panics
142    ///
143    /// Panics if the length of `data` is not a multiple of `pitch`.
144    pub fn new(data: &'data [T], pitch: usize) -> Self {
145        assert!(data.len().is_multiple_of(pitch));
146
147        BlockRef {
148            block: BlockSlice {
149                rows: data.len() / pitch,
150                cols: pitch,
151                pitch,
152            },
153            data: NonNull::from_ref(data).cast(),
154            lifetime: PhantomData,
155        }
156    }
157
158    /// Number of rows in this block.
159    pub fn rows(&self) -> usize {
160        self.block.rows
161    }
162
163    /// Number of columns in this block.
164    pub fn cols(&self) -> usize {
165        self.block.cols
166    }
167
168    /// Divide into two blocks at the given column.
169    ///
170    /// # Examples
171    ///
172    /// ```
173    /// let data = &[
174    ///     [0, 1, 2],
175    ///     [3, 4, 5],
176    /// ];
177    ///
178    /// let block = matrix_slice::from_array_rows(data);
179    /// let (left, right) = block.split_at_col(2);
180    ///
181    /// assert_eq!(left[(1, 0)], 3);
182    /// assert_eq!(right[(1, 0)], 5);
183    /// ```
184    pub fn split_at_col(self, mid: usize) -> (BlockRef<'data, T>, BlockRef<'data, T>) {
185        self.split_at_col_checked(mid).unwrap()
186    }
187
188    /// Divide into two blocks at the given column.
189    ///
190    /// See [`Self::split_at_col`] but returns `None` if out of bounds.
191    pub fn split_at_col_checked(
192        self,
193        mid: usize,
194    ) -> Option<(BlockRef<'data, T>, BlockRef<'data, T>)> {
195        if let Some((lhs, rhs, offset)) = self.block.split_at_col(mid) {
196            Some((
197                BlockRef {
198                    data: self.data,
199                    block: lhs,
200                    lifetime: self.lifetime,
201                },
202                BlockRef {
203                    data: unsafe { self.data.add(offset) },
204                    block: rhs,
205                    lifetime: self.lifetime,
206                },
207            ))
208        } else {
209            None
210        }
211    }
212
213    /// Divide into two blocks at the given row.
214    ///
215    /// # Examples
216    ///
217    /// ```
218    /// let data = &[
219    ///     [0, 1, 2],
220    ///     [3, 4, 5],
221    /// ];
222    ///
223    /// let block = matrix_slice::from_array_rows(data);
224    /// let (top, bot) = block.split_at_row(1);
225    ///
226    /// assert_eq!(top[(0, 2)], 2);
227    /// assert_eq!(bot[(0, 2)], 5);
228    /// ```
229    pub fn split_at_row(self, mid: usize) -> (BlockRef<'data, T>, BlockRef<'data, T>) {
230        self.split_at_row_checked(mid).unwrap()
231    }
232
233    /// Divide into two blocks at the given row.
234    ///
235    /// See [`Self::split_at_row`] but returns `None` if out of bounds.
236    pub fn split_at_row_checked(
237        self,
238        mid: usize,
239    ) -> Option<(BlockRef<'data, T>, BlockRef<'data, T>)> {
240        if let Some((lhs, rhs, offset)) = self.block.split_at_row(mid) {
241            Some((
242                BlockRef {
243                    data: self.data,
244                    block: lhs,
245                    lifetime: self.lifetime,
246                },
247                BlockRef {
248                    data: unsafe { self.data.add(offset) },
249                    block: rhs,
250                    lifetime: self.lifetime,
251                },
252            ))
253        } else {
254            None
255        }
256    }
257
258    /// Choose a single row and refer to its data.
259    ///
260    /// # Examples
261    ///
262    /// ```
263    /// let data = &[
264    ///     [0, 1, 2],
265    ///     [3, 4, 5],
266    ///     [6, 7, 8],
267    /// ];
268    ///
269    /// let block = matrix_slice::from_array_rows(data);
270    /// let row = block.row(1);
271    /// assert_eq!(row[0], 3);
272    /// ```
273    pub fn row(self, row: usize) -> VecRef<'data, T> {
274        let (_, block, offset) = self.block.split_at_row(row).unwrap();
275        assert!(block.rows >= 1);
276
277        VecRef {
278            block: VectorSlice {
279                count: block.cols,
280                pitch: 1,
281            },
282            data: unsafe { self.data.add(offset) },
283            lifetime: self.lifetime,
284        }
285    }
286
287    /// Choose a single column and refer to its data.
288    ///
289    /// # Examples
290    ///
291    /// ```
292    /// let data = &[
293    ///     [0, 1, 2],
294    ///     [3, 4, 5],
295    ///     [6, 7, 8],
296    /// ];
297    ///
298    /// let block = matrix_slice::from_array_rows(data);
299    /// let row = block.col(1);
300    /// assert_eq!(row[0], 1);
301    /// ```
302    pub fn col(self, col: usize) -> VecRef<'data, T> {
303        let (_, block, offset) = self.block.split_at_col(col).unwrap();
304        assert!(block.cols >= 1);
305
306        VecRef {
307            block: VectorSlice {
308                count: block.rows,
309                pitch: block.pitch,
310            },
311            data: unsafe { self.data.add(offset) },
312            lifetime: self.lifetime,
313        }
314    }
315
316    /// Choose a range of rows and contract the block to that.
317    ///
318    /// The argument type is flexible, allowing ranges (`1..3`), half open ranges (`2..` and `..2`)
319    /// among others. See the [`MatrixIndex`] trait, which is sealed though as its details are not
320    /// yet finalized.
321    ///
322    /// # Examples
323    ///
324    /// ```
325    /// let data = &[
326    ///     [0, 1, 2],
327    ///     [3, 4, 5],
328    ///     [6, 7, 8],
329    /// ];
330    ///
331    /// let block = matrix_slice::from_array_rows(data);
332    ///
333    /// let center = block.select_rows(1..2).unwrap();
334    /// assert_eq!(center.rows(), 1);
335    /// assert_eq!(center.cols(), 3);
336    /// assert_eq!(center[(0, 1)], 4);
337    /// ```
338    pub fn select_rows<R>(self, range: R) -> Option<BlockRef<'data, T>>
339    where
340        R: MatrixIndex,
341    {
342        let (start, len) = range.into_start_and_len(self.block.rows)?;
343        let (_, block, offset) = self.block.split_at_row(start)?;
344        // Safety: ensures that the resulting block is more constrained, this property should be
345        // ensured by our sealed `MatrixIndex` implementations.
346        assert!(block.rows >= len);
347
348        Some(BlockRef {
349            block: BlockSlice { rows: len, ..block },
350            // SAFETY: offset is in-bounds as per `split_at_row` contract.
351            data: unsafe { self.data.add(offset) },
352            lifetime: self.lifetime,
353        })
354    }
355
356    /// Choose a range of columns and contract the block to that.
357    ///
358    /// The argument type is flexible, allowing ranges (`1..3`), half open ranges (`2..` and `..2`)
359    /// among others. See the [`MatrixIndex`] trait, which is sealed though as its details are not
360    /// yet finalized.
361    pub fn select_cols<R>(self, range: R) -> Option<BlockRef<'data, T>>
362    where
363        R: MatrixIndex,
364    {
365        let (start, len) = range.into_start_and_len(self.block.rows)?;
366        let (_, block, offset) = self.block.split_at_col(start)?;
367        assert!(block.cols >= len);
368
369        Some(BlockRef {
370            block: BlockSlice { cols: len, ..block },
371            data: unsafe { self.data.add(offset) },
372            lifetime: self.lifetime,
373        })
374    }
375
376    /// Choose a sub-block by its range of rows and columns.
377    pub fn select(
378        self,
379        row_range: impl MatrixIndex,
380        col_range: impl MatrixIndex,
381    ) -> Option<BlockRef<'data, T>> {
382        let block = self.select_rows(row_range)?;
383        block.select_cols(col_range)
384    }
385
386    /// Extract a contiguous underlying slice of elements if the block is contiguous.
387    ///
388    /// # Examples
389    ///
390    /// ```
391    /// let data = &[[0u32; 3]; 3];
392    /// let block = matrix_slice::from_array_rows(data);
393    ///
394    /// let (block, _) = block.split_at_row(2);
395    /// assert!(block.into_contiguous_slice().is_some());
396    ///
397    /// let (pre, post) = block.split_at_col(2);
398    /// assert!(pre.into_contiguous_slice().is_none());
399    /// assert!(post.into_contiguous_slice().is_none());
400    ///
401    /// let (same, _) = block.split_at_col(3);
402    /// assert!(same.into_contiguous_slice().is_some());
403    /// ```
404    pub fn into_contiguous_slice(self) -> Option<&'data [T]> {
405        if let Some(items) = self.block.contiguous_span() {
406            Some(unsafe { core::slice::from_raw_parts(self.data.as_ptr().cast(), items) })
407        } else {
408            None
409        }
410    }
411
412    /// Turn this into a slice of the first row, assuming it is at most one row.
413    fn fake_contiguity(mut self) -> &'data [T] {
414        self.block.fake_contiguity();
415        self.into_contiguous_slice().unwrap()
416    }
417
418    /// Extract access as a slice of arrays if the block is contiguous.
419    ///
420    /// The caller must choose `N` matching the number of columns.
421    pub fn into_array_rows_checked<const N: usize>(self) -> Option<&'data [[T; N]]> {
422        if self.block.cols == self.block.pitch && self.block.cols == N {
423            Some(unsafe { core::slice::from_raw_parts(self.data.as_ptr().cast(), self.block.rows) })
424        } else {
425            None
426        }
427    }
428
429    /// Iterate over the rows of this block.
430    pub fn iter_rows(self) -> IterRows<'data, T> {
431        IterRows { block: self }
432    }
433
434    /// Create a reference to this block with a shorter lifetime.
435    pub fn reborrow(&self) -> BlockRef<'_, T> {
436        BlockRef {
437            data: self.data,
438            block: self.block,
439            lifetime: PhantomData,
440        }
441    }
442}
443
444impl<T> ops::Index<(usize, usize)> for BlockRef<'_, T> {
445    type Output = T;
446
447    fn index(&self, index: (usize, usize)) -> &Self::Output {
448        let idx = self.block.in_bounds_offset(index.0, index.1);
449        // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
450        // provenance of the pointer.
451        unsafe { &*self.data.as_ptr().add(idx) }
452    }
453}
454
455impl<T: fmt::Debug> fmt::Debug for BlockRef<'_, T> {
456    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
457        f.debug_list().entries(self.reborrow().iter_rows()).finish()
458    }
459}
460
461/// Create a mutable block reference from a full matrix represented as an array of rows.
462///
463/// # Examples
464///
465/// ```
466/// let data = &mut [
467///    [0, 1, 2],
468///    [3, 4, 5],
469/// ];
470///
471/// let mut block = matrix_slice::from_array_rows_mut(data);
472///
473/// assert_eq!(block.rows(), 2);
474/// assert_eq!(block.cols(), 3);
475///
476/// block[(1, 1)] = 42;
477///
478/// assert_eq!(data[1][1], 42);
479/// ```
480pub fn from_array_rows_mut<'a, T, const N: usize>(data: &'a mut [[T; N]]) -> BlockMut<'a, T> {
481    BlockMut {
482        block: BlockSlice {
483            rows: data.len(),
484            cols: N,
485            pitch: N,
486        },
487        data: NonNull::from_mut(data).cast(),
488        lifetime: PhantomData,
489    }
490}
491
492/// A reference to a block of a matrix with unique access to elements.
493pub struct BlockMut<'a, T> {
494    data: NonNull<T>,
495    block: BlockSlice,
496    lifetime: PhantomData<&'a mut [T]>,
497}
498
499// SAFETY: See `BlockRef` but with `&mut [T]`.
500//
501// We have `&mut T: Sync` iff `T: Sync`
502unsafe impl<T> Sync for BlockMut<'_, T> where T: Sync {}
503// We have `&mut T: Send` iff `T: Send`
504unsafe impl<T> Send for BlockMut<'_, T> where T: Sync {}
505
506/// ```compile_fail
507/// use matrix_slice::BlockMut;
508///
509/// // This coercion must *not* be possible. The field `lifetime` ensures the right variance.
510/// fn _coerce_item_not_covariant<'lt, 'a, 'b: 'a, T>(
511///     v: BlockMut<'lt, &'b T>,
512/// ) -> BlockMut<'lt, &'a T> {
513///     v
514/// //  ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
515/// }
516///
517/// ```compile_fail
518/// use matrix_slice::BlockMut;
519///
520/// fn _copy_block(v: BlockMut<'_, u32>) -> [BlockMut<'_, u32>; 2] {
521///    [v, v]
522/// }
523const _: () = {
524    // We can coerce a block to a shorter lifetime.
525    fn _coerce_block_mut<'a, 'b: 'a, T>(v: BlockMut<'b, T>) -> BlockMut<'a, T> {
526        v
527    }
528
529    // We can coerce a reference to a block to a shorter lifetime.
530    fn _coerce_covariant<'lt, 'a, 'b: 'a, T>(v: &'lt BlockMut<'b, T>) -> &'lt BlockMut<'a, T> {
531        v
532    }
533
534    fn _coerce_covariant_fn<'lt, 'a, 'b: 'a, T>(v: fn(BlockMut<'a, T>)) -> fn(BlockMut<'b, T>) {
535        v
536    }
537};
538
539/// Creates an empty block reference, within a matrix of a dangling slice.
540impl<T> Default for BlockMut<'_, T> {
541    fn default() -> Self {
542        from_array_rows_mut::<T, 0>(&mut [])
543    }
544}
545
546impl<'data, T> BlockMut<'data, T> {
547    /// Create a new block reference from a raw slice and pitch.
548    ///
549    /// The resulting block refers to the whole matrix.
550    ///
551    /// # Panics
552    ///
553    /// Panics if the length of `data` is not a multiple of `pitch`.
554    pub fn new(data: &'data mut [T], pitch: usize) -> Self {
555        assert!(data.len().is_multiple_of(pitch));
556
557        BlockMut {
558            block: BlockSlice {
559                rows: data.len() / pitch,
560                cols: pitch,
561                pitch,
562            },
563            data: NonNull::from_mut(data).cast(),
564            lifetime: PhantomData,
565        }
566    }
567
568    /// Number of rows in this block.
569    pub fn rows(&self) -> usize {
570        self.block.rows
571    }
572
573    /// Number of columns in this block.
574    pub fn cols(&self) -> usize {
575        self.block.cols
576    }
577
578    /// Divide into two blocks at the given column.
579    ///
580    /// # Examples
581    ///
582    /// ```
583    /// let data = &mut [
584    ///     [0, 1, 2],
585    ///     [3, 4, 5],
586    /// ];
587    ///
588    /// let block = matrix_slice::from_array_rows_mut(data);
589    /// let (left, right) = block.split_at_col(2);
590    ///
591    /// assert_eq!(left[(1, 0)], 3);
592    /// assert_eq!(right[(1, 0)], 5);
593    /// ```
594    pub fn split_at_col(self, mid: usize) -> (BlockMut<'data, T>, BlockMut<'data, T>) {
595        self.split_at_col_checked(mid).unwrap()
596    }
597
598    /// Divide into two blocks at the given column.
599    ///
600    /// See [`Self::split_at_col`] but returns `None` if out of bounds.
601    pub fn split_at_col_checked(
602        self,
603        mid: usize,
604    ) -> Option<(BlockMut<'data, T>, BlockMut<'data, T>)> {
605        if let Some((lhs, rhs, offset)) = self.block.split_at_col(mid) {
606            Some((
607                BlockMut {
608                    data: self.data,
609                    block: lhs,
610                    lifetime: self.lifetime,
611                },
612                BlockMut {
613                    data: unsafe { self.data.add(offset) },
614                    block: rhs,
615                    lifetime: self.lifetime,
616                },
617            ))
618        } else {
619            None
620        }
621    }
622
623    /// Divide into two blocks at the given row.
624    ///
625    /// # Examples
626    ///
627    /// ```
628    /// let data = &mut [
629    ///     [0, 1, 2],
630    ///     [3, 4, 5],
631    /// ];
632    ///
633    /// let block = matrix_slice::from_array_rows_mut(data);
634    /// let (top, bot) = block.split_at_row(1);
635    ///
636    /// assert_eq!(top[(0, 2)], 2);
637    /// assert_eq!(bot[(0, 2)], 5);
638    /// ```
639    pub fn split_at_row(self, mid: usize) -> (BlockMut<'data, T>, BlockMut<'data, T>) {
640        self.split_at_row_checked(mid).unwrap()
641    }
642
643    /// Divide into two blocks at the given row.
644    ///
645    /// See [`Self::split_at_row`] but returns `None` if out of bounds.
646    pub fn split_at_row_checked(
647        self,
648        mid: usize,
649    ) -> Option<(BlockMut<'data, T>, BlockMut<'data, T>)> {
650        if let Some((lhs, rhs, offset)) = self.block.split_at_row(mid) {
651            Some((
652                BlockMut {
653                    data: self.data,
654                    block: lhs,
655                    lifetime: self.lifetime,
656                },
657                BlockMut {
658                    data: unsafe { self.data.add(offset) },
659                    block: rhs,
660                    lifetime: self.lifetime,
661                },
662            ))
663        } else {
664            None
665        }
666    }
667
668    /// Choose a single row and refer to its data.
669    ///
670    /// # Examples
671    ///
672    /// ```
673    /// let data = &mut [
674    ///     [0, 1, 2],
675    ///     [3, 4, 5],
676    ///     [6, 7, 8],
677    /// ];
678    ///
679    /// let mut block = matrix_slice::from_array_rows_mut(data);
680    /// let mut row = block.reborrow().row(1);
681    /// row[0] = 0x42;
682    /// assert_eq!(block[(1, 0)], 0x42);
683    /// ```
684    pub fn row(self, row: usize) -> VecMut<'data, T> {
685        let (_, block, offset) = self.block.split_at_row(row).unwrap();
686        assert!(block.rows >= 1);
687
688        VecMut {
689            block: VectorSlice {
690                count: block.cols,
691                pitch: 1,
692            },
693            data: unsafe { self.data.add(offset) },
694            lifetime: self.lifetime,
695        }
696    }
697
698    /// Choose a single column and refer to its data.
699    ///
700    /// # Examples
701    ///
702    /// ```
703    /// let data = &mut [
704    ///     [0, 1, 2],
705    ///     [3, 4, 5],
706    ///     [6, 7, 8],
707    /// ];
708    ///
709    /// let mut block = matrix_slice::from_array_rows_mut(data);
710    /// let mut row = block.reborrow().col(1);
711    /// row[0] = 0x42;
712    /// assert_eq!(block[(0, 1)], 0x42);
713    /// ```
714    pub fn col(self, col: usize) -> VecMut<'data, T> {
715        let (_, block, offset) = self.block.split_at_col(col).unwrap();
716        assert!(block.cols >= 1);
717
718        VecMut {
719            block: VectorSlice {
720                count: block.rows,
721                pitch: block.pitch,
722            },
723            data: unsafe { self.data.add(offset) },
724            lifetime: self.lifetime,
725        }
726    }
727
728    /// Choose a range of rows and contract the block to that.
729    ///
730    /// The argument type is flexible, allowing ranges (`1..3`), half open ranges (`2..` and `..2`)
731    /// among others. See the [`MatrixIndex`] trait, which is sealed though as its details are not
732    /// yet finalized.
733    ///
734    /// # Examples
735    ///
736    /// ```
737    /// let data = &mut [
738    ///     [0, 1, 2],
739    ///     [3, 4, 5],
740    ///     [6, 7, 8],
741    /// ];
742    ///
743    /// let block = matrix_slice::from_array_rows_mut(data);
744    ///
745    /// let center = block.select_rows(1..2).unwrap();
746    /// assert_eq!(center.rows(), 1);
747    /// assert_eq!(center.cols(), 3);
748    /// assert_eq!(center[(0, 1)], 4);
749    /// ```
750    pub fn select_rows<R>(self, range: R) -> Option<BlockMut<'data, T>>
751    where
752        R: MatrixIndex,
753    {
754        let (start, len) = range.into_start_and_len(self.block.rows)?;
755        let (_, block, offset) = self.block.split_at_row(start)?;
756        assert!(block.rows >= len);
757
758        Some(BlockMut {
759            block: BlockSlice { rows: len, ..block },
760            data: unsafe { self.data.add(offset) },
761            lifetime: self.lifetime,
762        })
763    }
764
765    /// Choose a range of columns and contract the block to that.
766    ///
767    /// The argument type is flexible, allowing ranges (`1..3`), half open ranges (`2..` and `..2`)
768    /// among others. See the [`MatrixIndex`] trait, which is sealed though as its details are not
769    /// yet finalized.
770    pub fn select_cols<R>(self, range: R) -> Option<BlockMut<'data, T>>
771    where
772        R: MatrixIndex,
773    {
774        let (start, len) = range.into_start_and_len(self.block.rows)?;
775        let (_, block, offset) = self.block.split_at_col(start)?;
776        assert!(block.cols >= len);
777
778        Some(BlockMut {
779            block: BlockSlice { cols: len, ..block },
780            data: unsafe { self.data.add(offset) },
781            lifetime: self.lifetime,
782        })
783    }
784
785    /// Choose a sub-block by its range of rows and columns.
786    pub fn select(
787        self,
788        row_range: impl MatrixIndex,
789        col_range: impl MatrixIndex,
790    ) -> Option<BlockMut<'data, T>> {
791        let block = self.select_rows(row_range)?;
792        block.select_cols(col_range)
793    }
794
795    /// Extract a contiguous underlying slice of elements if the block is contiguous.
796    ///
797    /// # Examples
798    ///
799    /// ```
800    /// let data = &mut [[0u32; 3]; 3];
801    /// let mut block = matrix_slice::from_array_rows_mut(data);
802    ///
803    /// let (mut part, _) = block.reborrow().split_at_row(2);
804    /// assert!(part.into_contiguous_slice().is_some());
805    ///
806    /// let (pre, post) = block.reborrow().split_at_col(2);
807    /// assert!(pre.into_contiguous_slice().is_none());
808    /// assert!(post.into_contiguous_slice().is_none());
809    ///
810    /// let (same, _) = block.reborrow().split_at_col(3);
811    /// assert!(same.into_contiguous_slice().is_some());
812    /// ```
813    pub fn into_contiguous_slice(self) -> Option<&'data mut [T]> {
814        if let Some(items) = self.block.contiguous_span() {
815            Some(unsafe { core::slice::from_raw_parts_mut(self.data.as_ptr().cast(), items) })
816        } else {
817            None
818        }
819    }
820
821    /// Turn this into a slice of the first row, assuming it is at most one row.
822    fn fake_contiguity(mut self) -> &'data mut [T] {
823        self.block.fake_contiguity();
824        self.into_contiguous_slice().unwrap()
825    }
826
827    /// Extract access as a slice of arrays if the block is contiguous.
828    ///
829    /// The caller must choose `N` matching the number of columns.
830    ///
831    /// # Examples
832    ///
833    /// ```
834    /// let data = &mut [[0u32; 3]; 3];
835    /// let mut block = matrix_slice::from_array_rows_mut(data);
836    ///
837    /// // Turns this back into the same type as `data` had.
838    /// assert!(block.reborrow().into_array_rows_checked::<3>().is_some());
839    ///
840    /// // Using an incorrect number of columns fails.
841    /// assert!(block.reborrow().into_array_rows_checked::<2>().is_none());
842    ///
843    /// // Can still be used after splitting at rows.
844    /// let (_, mut block) = block.split_at_row(2);
845    /// assert!(block.reborrow().into_array_rows_checked::<3>().is_some());
846    /// ```
847    pub fn into_array_rows_checked<const N: usize>(self) -> Option<&'data mut [[T; N]]> {
848        if self.block.cols == self.block.pitch && self.block.cols == N {
849            Some(unsafe {
850                core::slice::from_raw_parts_mut(self.data.as_ptr().cast(), self.block.rows)
851            })
852        } else {
853            None
854        }
855    }
856
857    /// Turn this unique reference into a shared reference.
858    pub fn cast_const(self) -> BlockRef<'data, T> {
859        // SAFETY: shared access can always be re-tagged from unique access.
860        BlockRef {
861            data: self.data,
862            block: self.block,
863            lifetime: PhantomData,
864        }
865    }
866
867    /// Create a unique reference to this block with a shorter lifetime.
868    pub fn reborrow(&mut self) -> BlockMut<'_, T> {
869        // SAFETY: Unique access is created by deriving it from our current pointer so the
870        // provenance is the same, and temporally it can not overlap access through the current
871        // value due to the lifetime enforcing a borrow relationship.
872        BlockMut {
873            data: self.data,
874            block: self.block,
875            lifetime: PhantomData,
876        }
877    }
878
879    /// Iterate over the rows of this block.
880    pub fn iter_rows(self) -> IterRows<'data, T> {
881        self.cast_const().iter_rows()
882    }
883
884    /// Iterate over the rows of this block.
885    pub fn iter_rows_mut(self) -> IterRowsMut<'data, T> {
886        IterRowsMut { block: self }
887    }
888
889    /// Modify the item type to a `Cell`, allowing interior mutability.
890    ///
891    /// This is the equivalent of [`Cell::from_mut`] over elements in this slice.
892    pub fn as_cells(self) -> BlockMut<'data, Cell<T>> {
893        // SAFETY: `Cell<T>` has the same layout as `T`.
894        BlockMut {
895            data: self.data.cast(),
896            block: self.block,
897            lifetime: PhantomData,
898        }
899    }
900}
901
902impl<'data, T> BlockMut<'data, Cell<T>> {
903    /// Modify the item type from a `Cell` to its interior type.
904    ///
905    /// This is the equivalent of [`Cell::get_mut`] over elements in this slice.
906    pub fn as_cell_items(self) -> BlockMut<'data, T> {
907        // SAFETY: `Cell<T>` has the same layout as `T`.
908        BlockMut {
909            data: self.data.cast(),
910            block: self.block,
911            lifetime: PhantomData,
912        }
913    }
914}
915
916impl<T> ops::Index<(usize, usize)> for BlockMut<'_, T> {
917    type Output = T;
918
919    fn index(&self, index: (usize, usize)) -> &Self::Output {
920        let idx = self.block.in_bounds_offset(index.0, index.1);
921        // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
922        // provenance of the pointer.
923        unsafe { &*self.data.as_ptr().add(idx) }
924    }
925}
926
927impl<T> ops::IndexMut<(usize, usize)> for BlockMut<'_, T> {
928    fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
929        let idx = self.block.in_bounds_offset(index.0, index.1);
930        // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
931        // provenance of the pointer.
932        unsafe { &mut *self.data.as_ptr().add(idx) }
933    }
934}
935
936/// Represents the provenance of a pointer to a block of a matrix.
937///
938/// FIXME: before exposing this consider `PartialEq, … Ord` implications. These were added to
939/// satisfy the `Pointee` trait requirements but really what does ordering mean? We have chosen the
940/// field `pitch` to be last but that is super arbitrary.
941///
942/// We assume row major order here for the convention of _naming_ things. That is, when we say row
943/// we mean a tightly packed slice of items. This implies that the item pitch is assumed to be `1`.
944/// We have two major possible choices in representation a block-subset of a matrix: store the
945/// dimensions of the block with a matrix row pitch or store the total size of the matrix and two
946/// lengths.
947///
948/// The former of these allows us to represent both `0×N` and `M×0` blocks naturally, while the
949/// latter allows one of them but provides a fast capacity that's pre-calculated. We choose the
950/// former. In either case we need to store three `usize` values. Note that the total span of items
951/// is *not* `rows * pitch` since the last row might be ragged.
952#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
953struct BlockSlice {
954    rows: usize,
955    cols: usize,
956    pitch: usize,
957}
958
959const _: () = {
960    // As per Rust 1.92's `Pointee` trait. Suspicious: `Ord`. See comment on `BlockSlice`.
961    use core::{fmt, hash};
962
963    fn _can_eventually_be_ptr_metadata<
964        // Missing: `Freeze` which is unstable
965        Metadata: fmt::Debug + Copy + Send + Sync + Ord + hash::Hash + Unpin,
966    >() {
967    }
968
969    let _ = _can_eventually_be_ptr_metadata::<BlockSlice>;
970};
971
972impl BlockSlice {
973    /// The number of elements if this block is contiguous (cols equals pitch).
974    fn contiguous_span(&self) -> Option<usize> {
975        if self.cols == self.pitch {
976            Some(self.rows * self.cols)
977        } else {
978            None
979        }
980    }
981
982    /// The number of elements spanned by this block (including those we are not allowed to
983    /// access).
984    fn total_span(&self) -> usize {
985        if let Some(all_but_last) = self.rows.checked_sub(1) {
986            all_but_last * self.pitch + self.cols
987        } else {
988            0
989        }
990    }
991
992    /// The caller must ensure that this block has at most one row.
993    fn fake_contiguity(&mut self) {
994        debug_assert!(self.rows <= 1);
995        debug_assert!(self.cols <= self.pitch);
996
997        self.rows = self.rows.min(1);
998        // SAFETY: Reducing the pitch when we have at most one row does not change the elements we
999        // may refer to. The pitch always exceeds the number of columns.
1000        self.pitch = self.cols;
1001    }
1002
1003    /// Split into two block descriptors.
1004    ///
1005    /// Returns `Some` with two valid blocks. The first block is in-bounds. Also returns an offset
1006    /// that is in-bounds of the current block and such that the elements valid for both blocks do
1007    /// not alias. The second block is in-bounds when interpreted as start at the offset.
1008    fn split_at_row(self, mid: usize) -> Option<(BlockSlice, BlockSlice, usize)> {
1009        let n = self.rows.checked_sub(mid)?;
1010
1011        let lhs = BlockSlice {
1012            rows: mid,
1013            cols: self.cols,
1014            pitch: self.pitch,
1015        };
1016
1017        let rhs = BlockSlice {
1018            rows: n,
1019            cols: self.cols,
1020            pitch: self.pitch,
1021        };
1022
1023        // Careful: If we split a block after its last row (i.e. lhs and self are identical),
1024        // the naive offset of rows * pitch may point beyond the total span of elements covered
1025        // by ourselves. In this case the rhs does not cover any row so we assign it any
1026        // in-bounds offset.
1027        let offset = if n > 0 { mid * self.pitch } else { 0 };
1028        debug_assert!(offset <= self.total_span());
1029
1030        Some((lhs, rhs, offset))
1031    }
1032
1033    fn split_at_col(self, mid: usize) -> Option<(BlockSlice, BlockSlice, usize)> {
1034        let n = self.cols.checked_sub(mid)?;
1035
1036        let lhs = BlockSlice {
1037            rows: self.rows,
1038            cols: mid,
1039            pitch: self.pitch,
1040        };
1041
1042        let rhs = BlockSlice {
1043            rows: self.rows,
1044            cols: n,
1045            pitch: self.pitch,
1046        };
1047
1048        // If we have no rows at all then this block does not cover any elements so we must
1049        // pick an offset of 0 to guarantee in-bounds access. The good news is that this case
1050        // also implies that the other side is empty so its offset does not matter.
1051        let offset = if self.rows > 0 { mid } else { 0 };
1052        debug_assert!(offset <= self.total_span());
1053
1054        Some((lhs, rhs, offset))
1055    }
1056
1057    /// Return the absolute position of the element, if in bounds. Otherwise, panic.
1058    fn in_bounds_offset(&self, row: usize, col: usize) -> usize {
1059        assert!(row < self.rows);
1060        assert!(col < self.cols);
1061        let idx = row * self.pitch + col;
1062        debug_assert!(idx < self.total_span());
1063        idx
1064    }
1065}
1066
1067/// Represents the provenance of a pointer to a single column/row of a matrix.
1068///
1069/// FIXME: before exposing this consider `PartialEq, … Ord` implications. These were added to
1070/// satisfy the `Pointee` trait requirements but really what does ordering mean? We have chosen the
1071/// field `pitch` to be last but that is super arbitrary.
1072#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
1073struct VectorSlice {
1074    count: usize,
1075    pitch: usize,
1076}
1077
1078const _: () = {
1079    // As per Rust 1.92's `Pointee` trait. Suspicious: `Ord`. See comment on `VectorSlice`.
1080    use core::{fmt, hash};
1081
1082    fn _can_eventually_be_ptr_metadata<
1083        // Missing: `Freeze` which is unstable
1084        Metadata: fmt::Debug + Copy + Send + Sync + Ord + hash::Hash + Unpin,
1085    >() {
1086    }
1087
1088    let _ = _can_eventually_be_ptr_metadata::<VectorSlice>;
1089};
1090
1091impl VectorSlice {
1092    /// Split into two vector descriptors.
1093    ///
1094    /// Returns `Some` with two valid slice. The first slice is in-bounds. Also returns an offset
1095    /// that is in-bounds of the current slice and such that the elements valid for both blocks do
1096    /// not alias. The second block is in-bounds when interpreted as start at the offset.
1097    fn split_at(self, mid: usize) -> Option<(VectorSlice, VectorSlice, usize)> {
1098        let right_count = self.count.checked_sub(mid)?;
1099
1100        let left = VectorSlice {
1101            count: mid,
1102            pitch: self.pitch,
1103        };
1104
1105        let right = VectorSlice {
1106            count: right_count,
1107            pitch: self.pitch,
1108        };
1109
1110        let offset = mid * self.pitch;
1111        Some((left, right, offset))
1112    }
1113
1114    /// Return the absolute position of the element, if in bounds. Otherwise, panic.
1115    fn in_bounds_offset(&self, index: usize) -> usize {
1116        assert!(index < self.count);
1117        index * self.pitch
1118    }
1119}
1120
1121/// Iterate over the rows of a block in a matrix.
1122///
1123/// We assume row-major matrices here, a row is a contiguous slice of items.
1124pub struct IterRows<'a, T> {
1125    block: BlockRef<'a, T>,
1126}
1127
1128impl<'data, T> Iterator for IterRows<'data, T> {
1129    type Item = &'data [T];
1130
1131    fn next(&mut self) -> Option<Self::Item> {
1132        if self.block.rows() == 0 {
1133            None
1134        } else {
1135            // FIXME: add `split_off_rows` instead.
1136            let (row, rest) = core::mem::take(&mut self.block).split_at_row(1);
1137            self.block = rest;
1138            // One row as it was created from `split_at_row(1)`.
1139            Some(row.fake_contiguity())
1140        }
1141    }
1142}
1143
1144/// Iterate over mutable rows of a block in a matrix.
1145///
1146/// We assume row-major matrices here, a row is a contiguous slice of items.
1147pub struct IterRowsMut<'a, T> {
1148    block: BlockMut<'a, T>,
1149}
1150
1151impl<'data, T> Iterator for IterRowsMut<'data, T> {
1152    type Item = &'data mut [T];
1153
1154    fn next(&mut self) -> Option<Self::Item> {
1155        if self.block.rows() == 0 {
1156            None
1157        } else {
1158            // FIXME: add `split_off_rows` instead.
1159            let (row, rest) = core::mem::take(&mut self.block).split_at_row(1);
1160            self.block = rest;
1161            // One row as it was created from `split_at_row(1)`.
1162            Some(row.fake_contiguity())
1163        }
1164    }
1165}
1166
1167pub trait MatrixIndex: sealed::Sealed {}
1168
1169impl MatrixIndex for ops::Range<usize> {}
1170impl MatrixIndex for ops::RangeInclusive<usize> {}
1171impl MatrixIndex for ops::RangeFrom<usize> {}
1172impl MatrixIndex for ops::RangeTo<usize> {}
1173impl MatrixIndex for ops::RangeToInclusive<usize> {}
1174impl MatrixIndex for ops::RangeFull {}
1175
1176mod sealed {
1177    use core::ops;
1178
1179    pub trait Sealed {
1180        fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)>;
1181    }
1182
1183    impl Sealed for ops::Range<usize> {
1184        fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1185            if self.start <= self.end && self.end <= dim {
1186                Some((self.start, self.end - self.start))
1187            } else {
1188                None
1189            }
1190        }
1191    }
1192
1193    impl Sealed for ops::RangeInclusive<usize> {
1194        fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1195            let start = *self.start();
1196            let end = *self.end();
1197            if start <= end && end < dim {
1198                Some((start, end - start + 1))
1199            } else {
1200                None
1201            }
1202        }
1203    }
1204
1205    impl Sealed for ops::RangeFrom<usize> {
1206        fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1207            if self.start <= dim {
1208                Some((self.start, dim - self.start))
1209            } else {
1210                None
1211            }
1212        }
1213    }
1214
1215    impl Sealed for ops::RangeTo<usize> {
1216        fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1217            if self.end <= dim {
1218                Some((0, self.end))
1219            } else {
1220                None
1221            }
1222        }
1223    }
1224
1225    impl Sealed for ops::RangeToInclusive<usize> {
1226        fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1227            if self.end < dim {
1228                Some((0, self.end + 1))
1229            } else {
1230                None
1231            }
1232        }
1233    }
1234
1235    impl Sealed for ops::RangeFull {
1236        fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1237            Some((0, dim))
1238        }
1239    }
1240}
1241
1242/// A reference to a single column/row of a matrix.
1243///
1244/// This is similar to `&[T]` but with a pitch potentially different from `1` between its elements,
1245/// i.e. there is no guarantee of contiguity. As a consequence this does not have a simple
1246/// past-the-end pointer like a slice would have. For an empty slice the only guaranteed-valid
1247/// pointer is the base pointer itself while for larger slices the last guaranteed-valid pointer is
1248/// one-past the last element, _not_ one additional pitch.
1249///
1250/// Created from its constructors or a block reference via the [`BlockRef::col`] and
1251/// [`BlockRef::row`] methods.
1252#[derive(Copy, Clone)]
1253pub struct VecRef<'a, T> {
1254    data: NonNull<T>,
1255    block: VectorSlice,
1256    lifetime: PhantomData<&'a [T]>,
1257}
1258
1259// SAFETY: See `&[T]`. The reference can be used to, potentially, get a `&T` for each element in
1260// the block and thus the block itself provides the exact same properties as `T`. The `VecRef` is
1261// then `&[T]` itself and thus has properties of a reference to such a type. Refer to the
1262// reference: <https://doc.rust-lang.org/stable/std/primitive.reference.html>
1263//
1264// We have `&T: Sync` iff `T: Sync`
1265unsafe impl<T> Sync for VecRef<'_, T> where T: Sync {}
1266// We have `&T: Send` iff `T: Sync`
1267unsafe impl<T> Send for VecRef<'_, T> where T: Sync {}
1268
1269impl<'data, T> VecRef<'data, T> {
1270    /// Create a new vector reference from a raw slice and pitch.
1271    ///
1272    /// The resulting block refers to the first column of the matrix.
1273    ///
1274    /// # Panics
1275    ///
1276    /// Panics if the pitch is zero.
1277    pub fn new(data: &'data [T], pitch: usize) -> Self {
1278        assert_ne!(pitch, 0);
1279
1280        VecRef {
1281            // Safety: construction implies `count * pitch <= data.len()`.
1282            block: VectorSlice {
1283                count: data.len() / pitch,
1284                pitch,
1285            },
1286            data: NonNull::from(data).cast(),
1287            lifetime: PhantomData,
1288        }
1289    }
1290
1291    /// Create a new vector reference from a raw slice with pitch `1`.
1292    pub fn from_slice(data: &'data [T]) -> Self {
1293        VecRef {
1294            block: VectorSlice {
1295                count: data.len(),
1296                pitch: 1,
1297            },
1298            data: NonNull::from(data).cast(),
1299            lifetime: PhantomData,
1300        }
1301    }
1302
1303    /// Number of elements in this vector.
1304    pub fn len(&self) -> usize {
1305        self.block.count
1306    }
1307
1308    /// Whether this vector is empty.
1309    pub fn is_empty(&self) -> bool {
1310        self.block.count == 0
1311    }
1312
1313    /// Divide into two vectors at the given element.
1314    ///
1315    /// # Examples
1316    ///
1317    /// ```
1318    /// use matrix_slice::VecRef;
1319    ///
1320    /// let data = &[0, 1, 2, 3, 4, 5];
1321    ///
1322    /// let block = VecRef::new(data, 1);
1323    /// let (left, right) = block.split_at(2);
1324    ///
1325    /// assert_eq!(left[1], 1);
1326    /// assert_eq!(right[3], 5);
1327    /// ```
1328    pub fn split_at(self, mid: usize) -> (VecRef<'data, T>, VecRef<'data, T>) {
1329        self.split_at_checked(mid).unwrap()
1330    }
1331
1332    /// Divide into two vectors at the given element.
1333    ///
1334    /// See [`Self::split_at`] but returns `None` if out of bounds.
1335    pub fn split_at_checked(self, mid: usize) -> Option<(VecRef<'data, T>, VecRef<'data, T>)> {
1336        if let Some((lhs, rhs, offset)) = self.block.split_at(mid) {
1337            Some((
1338                VecRef {
1339                    data: self.data,
1340                    block: lhs,
1341                    lifetime: self.lifetime,
1342                },
1343                VecRef {
1344                    data: unsafe { self.data.add(offset) },
1345                    block: rhs,
1346                    lifetime: self.lifetime,
1347                },
1348            ))
1349        } else {
1350            None
1351        }
1352    }
1353
1354    /// Choose a range of elements and contract the vector to that.
1355    pub fn select<R>(self, range: R) -> Option<VecRef<'data, T>>
1356    where
1357        R: MatrixIndex,
1358    {
1359        let (start, len) = range.into_start_and_len(self.block.count)?;
1360        let (_, block, offset) = self.block.split_at(start)?;
1361        // Safety: ensures that the resulting block is more constrained, this property should be
1362        // ensured by our sealed `MatrixIndex` implementations.
1363        assert!(block.count >= len);
1364
1365        Some(VecRef {
1366            block: VectorSlice {
1367                count: len,
1368                ..block
1369            },
1370            // SAFETY: offset is in-bounds as per `split_at` contract.
1371            data: unsafe { self.data.add(offset) },
1372            lifetime: self.lifetime,
1373        })
1374    }
1375}
1376
1377impl<T> ops::Index<usize> for VecRef<'_, T> {
1378    type Output = T;
1379
1380    fn index(&self, index: usize) -> &Self::Output {
1381        let idx = self.block.in_bounds_offset(index);
1382        // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
1383        // provenance of the pointer.
1384        unsafe { &*self.data.as_ptr().add(idx) }
1385    }
1386}
1387
1388/// A reference to a single column/row of a matrix.
1389///
1390/// This is similar to `&[T]` but with a pitch potentially different from `1` between its elements,
1391/// i.e. there is no guarantee of contiguity. As a consequence this does not have a simple
1392/// past-the-end pointer like a slice would have. For an empty slice the only guaranteed-valid
1393/// pointer is the base pointer itself while for larger slices the last guaranteed-valid pointer is
1394/// one-past the last element, _not_ one additional pitch.
1395///
1396/// Created from its constructors or a block reference via the [`BlockMut::col`] and
1397/// [`BlockMut::row`] methods.
1398pub struct VecMut<'a, T> {
1399    data: NonNull<T>,
1400    block: VectorSlice,
1401    lifetime: PhantomData<&'a mut [T]>,
1402}
1403
1404// SAFETY: See `VecRef` but with `&mut [T]`.
1405//
1406// We have `&mut T: Sync` iff `T: Sync`
1407unsafe impl<T> Sync for VecMut<'_, T> where T: Sync {}
1408// We have `&mut T: Send` iff `T: Send`
1409unsafe impl<T> Send for VecMut<'_, T> where T: Sync {}
1410
1411impl<'data, T> VecMut<'data, T> {
1412    /// Create a new vector reference from a raw slice and pitch.
1413    ///
1414    /// The resulting block refers to the first column of the matrix.
1415    pub fn new(data: &'data mut [T], pitch: usize) -> Self {
1416        VecMut {
1417            // Safety: construction implies `count * pitch <= data.len()`.
1418            block: VectorSlice {
1419                count: data.len() / pitch,
1420                pitch,
1421            },
1422            data: NonNull::from(data).cast(),
1423            lifetime: PhantomData,
1424        }
1425    }
1426
1427    /// Create a new vector reference from a raw slice with pitch `1`.
1428    pub fn from_slice(data: &'data mut [T]) -> Self {
1429        VecMut {
1430            block: VectorSlice {
1431                count: data.len(),
1432                pitch: 1,
1433            },
1434            data: NonNull::from(data).cast(),
1435            lifetime: PhantomData,
1436        }
1437    }
1438
1439    /// Number of elements in this vector.
1440    pub fn len(&self) -> usize {
1441        self.block.count
1442    }
1443
1444    /// Whether this vector is empty.
1445    pub fn is_empty(&self) -> bool {
1446        self.block.count == 0
1447    }
1448
1449    /// Divide into two vectors at the given element.
1450    ///
1451    /// # Examples
1452    ///
1453    /// ```
1454    /// use matrix_slice::VecMut;
1455    ///
1456    /// let data = &mut [0, 1, 2, 3, 4, 5];
1457    ///
1458    /// let block = VecMut::new(data, 1);
1459    /// let (left, right) = block.split_at(2);
1460    ///
1461    /// assert_eq!(left[1], 1);
1462    /// assert_eq!(right[3], 5);
1463    /// ```
1464    pub fn split_at(self, mid: usize) -> (VecMut<'data, T>, VecMut<'data, T>) {
1465        self.split_at_checked(mid).unwrap()
1466    }
1467
1468    /// Divide into two vectors at the given element.
1469    ///
1470    /// See [`Self::split_at`] but returns `None` if out of bounds.
1471    pub fn split_at_checked(self, mid: usize) -> Option<(VecMut<'data, T>, VecMut<'data, T>)> {
1472        if let Some((lhs, rhs, offset)) = self.block.split_at(mid) {
1473            Some((
1474                VecMut {
1475                    data: self.data,
1476                    block: lhs,
1477                    lifetime: self.lifetime,
1478                },
1479                VecMut {
1480                    data: unsafe { self.data.add(offset) },
1481                    block: rhs,
1482                    lifetime: self.lifetime,
1483                },
1484            ))
1485        } else {
1486            None
1487        }
1488    }
1489
1490    /// Choose a range of elements and contract the vector to that.
1491    pub fn select<R>(self, range: R) -> Option<VecMut<'data, T>>
1492    where
1493        R: MatrixIndex,
1494    {
1495        let (start, len) = range.into_start_and_len(self.block.count)?;
1496        let (_, block, offset) = self.block.split_at(start)?;
1497        // Safety: ensures that the resulting block is more constrained, this property should be
1498        // ensured by our sealed `MatrixIndex` implementations.
1499        assert!(block.count >= len);
1500
1501        Some(VecMut {
1502            block: VectorSlice {
1503                count: len,
1504                ..block
1505            },
1506            // SAFETY: offset is in-bounds as per `split_at` contract.
1507            data: unsafe { self.data.add(offset) },
1508            lifetime: self.lifetime,
1509        })
1510    }
1511
1512    /// Turn this unique reference into a shared reference.
1513    pub fn cast_const(self) -> VecRef<'data, T> {
1514        // SAFETY: shared access can always be re-tagged from unique access.
1515        VecRef {
1516            data: self.data,
1517            block: self.block,
1518            lifetime: PhantomData,
1519        }
1520    }
1521
1522    /// Create a unique reference to this block with a shorter lifetime.
1523    pub fn reborrow(&mut self) -> VecMut<'_, T> {
1524        // SAFETY: Unique access is created by deriving it from our current pointer so the
1525        // provenance is the same, and temporally it can not overlap access through the current
1526        // value due to the lifetime enforcing a borrow relationship.
1527        VecMut {
1528            data: self.data,
1529            block: self.block,
1530            lifetime: PhantomData,
1531        }
1532    }
1533
1534    /// Modify the item type to a `Cell`, allowing interior mutability.
1535    ///
1536    /// This is the equivalent of [`Cell::from_mut`] over elements in this slice.
1537    pub fn as_cells(self) -> VecMut<'data, Cell<T>> {
1538        // SAFETY: `Cell<T>` has the same layout as `T`.
1539        VecMut {
1540            data: self.data.cast(),
1541            block: self.block,
1542            lifetime: PhantomData,
1543        }
1544    }
1545}
1546
1547impl<'data, T> VecMut<'data, Cell<T>> {
1548    /// Modify the item type from a `Cell` to its interior type.
1549    ///
1550    /// This is the equivalent of [`Cell::get_mut`] over elements in this slice.
1551    pub fn as_cell_items(self) -> VecMut<'data, T> {
1552        // SAFETY: `Cell<T>` has the same layout as `T`.
1553        VecMut {
1554            data: self.data.cast(),
1555            block: self.block,
1556            lifetime: PhantomData,
1557        }
1558    }
1559}
1560
1561impl<T> ops::Index<usize> for VecMut<'_, T> {
1562    type Output = T;
1563
1564    fn index(&self, index: usize) -> &Self::Output {
1565        let idx = self.block.in_bounds_offset(index);
1566        // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
1567        // provenance of the pointer.
1568        unsafe { &*self.data.as_ptr().add(idx) }
1569    }
1570}
1571
1572impl<T> ops::IndexMut<usize> for VecMut<'_, T> {
1573    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
1574        let idx = self.block.in_bounds_offset(index);
1575        // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
1576        // provenance of the pointer. By construction the `VecMut` has exclusive access to all
1577        // elements reachable as multiples of its pitch. We access exactly one of them here.
1578        unsafe { &mut *self.data.as_ptr().add(idx) }
1579    }
1580}
1581
1582/// Tests should also be ran under MIRI.
1583#[cfg(test)]
1584mod tests {
1585    // Verify that splitting as in the example works.
1586    #[test]
1587    fn well_defined_split() {
1588        let data = &[[0u32; 3]; 3];
1589        let block = super::from_array_rows(data);
1590        let (_, block) = block.split_at_row(1);
1591        let (_, block) = block.split_at_col(1);
1592
1593        block.split_at_row_checked(2).unwrap();
1594    }
1595    #[test]
1596    fn well_defined_split_mut() {
1597        let data = &mut [[0u32; 3]; 3];
1598        let block = super::from_array_rows_mut(data);
1599        let (_, block) = block.split_at_row(1);
1600        let (_, block) = block.split_at_col(1);
1601
1602        block.split_at_row_checked(2).unwrap();
1603    }
1604
1605    /// Check our pointer derivation does not cause retagging that would cause any block to lose
1606    /// provenance over its items. Access individual rows (derived slices) from an overlapping split
1607    /// concurrently.
1608    #[test]
1609    fn soundness_interleaved_block_access() {
1610        let data = &mut [[0u32; 4]; 4];
1611        let block = super::from_array_rows_mut(data);
1612
1613        let (mut lhs, rhs) = block.split_at_col(2);
1614
1615        for (left, right) in lhs.reborrow().iter_rows_mut().zip(rhs.iter_rows_mut()) {
1616            left[0] = right[0];
1617            left[1] = right[1];
1618            right.fill(1);
1619        }
1620
1621        // Check that this pointer is still valid.
1622        for row in lhs.iter_rows_mut() {
1623            row.fill(2);
1624        }
1625
1626        for row in data.iter() {
1627            assert_eq!(row, &[2, 2, 1, 1]);
1628        }
1629    }
1630}