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}