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 // Internal invariant: the size of the block is a subset of the provenance of the pointer.
95 data: NonNull<T>,
96 block: BlockSlice,
97 lifetime: PhantomData<&'a [T]>,
98}
99
100// SAFETY: See `&[T]`. The reference can be used to, potentially, get a `&T` for each element in
101// the block and thus the block itself provides the exact same properties as `T`. The `BlockRef` is
102// then `&[T]` itself and thus has properties of a reference to such a type. Refer to the
103// reference: <https://doc.rust-lang.org/stable/std/primitive.reference.html>
104//
105// We have `&T: Sync` iff `T: Sync`
106unsafe impl<T> Sync for BlockRef<'_, T> where T: Sync {}
107// We have `&T: Send` iff `T: Sync`
108unsafe impl<T> Send for BlockRef<'_, T> where T: Sync {}
109
110const _: () = {
111 // We can coerce a block to a shorter lifetime.
112 fn _coerce_block<'a, 'b: 'a, T>(v: BlockRef<'b, T>) -> BlockRef<'a, T> {
113 v
114 }
115
116 // We can coerce a reference to a block to a shorter lifetime.
117 fn _coerce_covariant<'lt, 'a, 'b: 'a, T>(v: &'lt BlockRef<'b, T>) -> &'lt BlockRef<'a, T> {
118 v
119 }
120
121 fn _coerce_covariant_fn<'lt, 'a, 'b: 'a, T>(v: fn(BlockRef<'a, T>)) -> fn(BlockRef<'b, T>) {
122 v
123 }
124
125 fn _coerce_item_covariant<'lt, 'a, 'b: 'a, T>(v: BlockRef<'lt, &'b T>) -> BlockRef<'lt, &'a T> {
126 v
127 }
128};
129
130/// Creates an empty block reference, within a matrix of a dangling slice.
131impl<T> Default for BlockRef<'_, T> {
132 fn default() -> Self {
133 from_array_rows::<T, 0>(&[])
134 }
135}
136
137impl<'data, T> BlockRef<'data, T> {
138 /// Create a new block reference from a raw slice and pitch.
139 ///
140 /// The resulting block refers to the whole matrix.
141 ///
142 /// # Panics
143 ///
144 /// Panics if the length of `data` is not a multiple of `pitch`.
145 pub fn new(data: &'data [T], pitch: usize) -> Self {
146 assert!(data.len().is_multiple_of(pitch));
147
148 BlockRef {
149 block: BlockSlice {
150 rows: data.len() / pitch,
151 cols: pitch,
152 pitch,
153 },
154 data: NonNull::from_ref(data).cast(),
155 lifetime: PhantomData,
156 }
157 }
158
159 /// Number of rows in this block.
160 pub fn rows(&self) -> usize {
161 self.block.rows
162 }
163
164 /// Number of columns in this block.
165 pub fn cols(&self) -> usize {
166 self.block.cols
167 }
168
169 /// Divide into two blocks at the given column.
170 ///
171 /// # Examples
172 ///
173 /// ```
174 /// let data = &[
175 /// [0, 1, 2],
176 /// [3, 4, 5],
177 /// ];
178 ///
179 /// let block = matrix_slice::from_array_rows(data);
180 /// let (left, right) = block.split_at_col(2);
181 ///
182 /// assert_eq!(left[(1, 0)], 3);
183 /// assert_eq!(right[(1, 0)], 5);
184 /// ```
185 pub fn split_at_col(self, mid: usize) -> (BlockRef<'data, T>, BlockRef<'data, T>) {
186 self.split_at_col_checked(mid).unwrap()
187 }
188
189 /// Divide into two blocks at the given column.
190 ///
191 /// See [`Self::split_at_col`] but returns `None` if out of bounds.
192 pub fn split_at_col_checked(
193 self,
194 mid: usize,
195 ) -> Option<(BlockRef<'data, T>, BlockRef<'data, T>)> {
196 if let Some((lhs, rhs, offset)) = self.block.split_at_col(mid) {
197 Some((
198 BlockRef {
199 data: self.data,
200 block: lhs,
201 lifetime: self.lifetime,
202 },
203 BlockRef {
204 // SAFETY: `split_at_col` guarantees that `offset` is in-bounds of the
205 // provenance tracked by `self.block`, which is in-sync with the pointer field
206 // (but we not necessary access these without synchronization). By extension
207 // of being in-bounds of the allocation the offset does not overflow `isize`.
208 data: unsafe { self.data.add(offset) },
209 block: rhs,
210 lifetime: self.lifetime,
211 },
212 ))
213 } else {
214 None
215 }
216 }
217
218 /// Divide into two blocks at the given row.
219 ///
220 /// # Examples
221 ///
222 /// ```
223 /// let data = &[
224 /// [0, 1, 2],
225 /// [3, 4, 5],
226 /// ];
227 ///
228 /// let block = matrix_slice::from_array_rows(data);
229 /// let (top, bot) = block.split_at_row(1);
230 ///
231 /// assert_eq!(top[(0, 2)], 2);
232 /// assert_eq!(bot[(0, 2)], 5);
233 /// ```
234 pub fn split_at_row(self, mid: usize) -> (BlockRef<'data, T>, BlockRef<'data, T>) {
235 self.split_at_row_checked(mid).unwrap()
236 }
237
238 /// Divide into two blocks at the given row.
239 ///
240 /// See [`Self::split_at_row`] but returns `None` if out of bounds.
241 pub fn split_at_row_checked(
242 self,
243 mid: usize,
244 ) -> Option<(BlockRef<'data, T>, BlockRef<'data, T>)> {
245 if let Some((lhs, rhs, offset)) = self.block.split_at_row(mid) {
246 Some((
247 BlockRef {
248 data: self.data,
249 block: lhs,
250 lifetime: self.lifetime,
251 },
252 BlockRef {
253 // SAFETY: `split_at_row` guarantees that `offset` is in-bounds of the
254 // provenance tracked by `self.block`, which is in-sync with the pointer field
255 // (but we not necessary access these without synchronization). By extension
256 // of being in-bounds of the allocation the offset does not overflow `isize`.
257 data: unsafe { self.data.add(offset) },
258 block: rhs,
259 lifetime: self.lifetime,
260 },
261 ))
262 } else {
263 None
264 }
265 }
266
267 /// Choose a single row and refer to its data.
268 ///
269 /// # Examples
270 ///
271 /// ```
272 /// let data = &[
273 /// [0, 1, 2],
274 /// [3, 4, 5],
275 /// [6, 7, 8],
276 /// ];
277 ///
278 /// let block = matrix_slice::from_array_rows(data);
279 /// let row = block.row(1);
280 /// assert_eq!(row[0], 3);
281 /// ```
282 pub fn row(self, row: usize) -> VecRef<'data, T> {
283 self.row_checked(row).unwrap()
284 }
285
286 /// Choose a single row and refer to its data.
287 ///
288 /// See [`Self::row`] but returns `None` if out of bounds.
289 pub fn row_checked(self, row: usize) -> Option<VecRef<'data, T>> {
290 let (_, block, offset) = self.block.split_at_row(row)?;
291
292 if block.rows == 0 {
293 return None;
294 }
295
296 Some(VecRef {
297 block: VectorSlice {
298 count: block.cols,
299 pitch: 1,
300 },
301 // SAFETY: `split_at_row` guarantees that `offset` is in-bounds of the
302 // provenance tracked by `self.block`, which is in-sync with the pointer field
303 // (but we not necessary access these without synchronization). By extension
304 // of being in-bounds of the allocation the offset does not overflow `isize`.
305 data: unsafe { self.data.add(offset) },
306 lifetime: self.lifetime,
307 })
308 }
309
310 /// Choose a single column and refer to its data.
311 ///
312 /// # Examples
313 ///
314 /// ```
315 /// let data = &[
316 /// [0, 1, 2],
317 /// [3, 4, 5],
318 /// [6, 7, 8],
319 /// ];
320 ///
321 /// let block = matrix_slice::from_array_rows(data);
322 /// let row = block.col(1);
323 /// assert_eq!(row[0], 1);
324 /// ```
325 pub fn col(self, col: usize) -> VecRef<'data, T> {
326 self.col_checked(col).unwrap()
327 }
328
329 /// Choose a single column and refer to its data.
330 ///
331 /// See [`Self::col`] but returns `None` if out of bounds.
332 pub fn col_checked(self, col: usize) -> Option<VecRef<'data, T>> {
333 let (_, block, offset) = self.block.split_at_col(col)?;
334
335 if block.cols == 0 {
336 return None;
337 }
338
339 Some(VecRef {
340 block: VectorSlice {
341 count: block.rows,
342 pitch: block.pitch,
343 },
344 // SAFETY: `split_at_col` guarantees that `offset` is in-bounds of the
345 // provenance tracked by `self.block`, which is in-sync with the pointer field
346 // (but we not necessary access these without synchronization). By extension
347 // of being in-bounds of the allocation the offset does not overflow `isize`.
348 data: unsafe { self.data.add(offset) },
349 lifetime: self.lifetime,
350 })
351 }
352
353 /// Choose a range of rows and contract the block to that.
354 ///
355 /// The argument type is flexible, allowing ranges (`1..3`), half open ranges (`2..` and `..2`)
356 /// among others. See the [`MatrixIndex`] trait, which is sealed though as its details are not
357 /// yet finalized.
358 ///
359 /// # Examples
360 ///
361 /// ```
362 /// let data = &[
363 /// [0, 1, 2],
364 /// [3, 4, 5],
365 /// [6, 7, 8],
366 /// ];
367 ///
368 /// let block = matrix_slice::from_array_rows(data);
369 ///
370 /// let center = block.select_rows(1..2).unwrap();
371 /// assert_eq!(center.rows(), 1);
372 /// assert_eq!(center.cols(), 3);
373 /// assert_eq!(center[(0, 1)], 4);
374 /// ```
375 pub fn select_rows<R>(self, range: R) -> Option<BlockRef<'data, T>>
376 where
377 R: MatrixIndex,
378 {
379 let (start, len) = range.into_start_and_len(self.block.rows)?;
380 let (_, block, offset) = self.block.split_at_row(start)?;
381 // SAFETY: ensures that the resulting block is more constrained, this property should be
382 // ensured by our sealed `MatrixIndex` implementations.
383 assert!(block.rows >= len);
384
385 Some(BlockRef {
386 block: BlockSlice { rows: len, ..block },
387 // SAFETY: offset is in-bounds as per `split_at_row` contract.
388 data: unsafe { self.data.add(offset) },
389 lifetime: self.lifetime,
390 })
391 }
392
393 /// Choose a range of columns and contract the block to that.
394 ///
395 /// The argument type is flexible, allowing ranges (`1..3`), half open ranges (`2..` and `..2`)
396 /// among others. See the [`MatrixIndex`] trait, which is sealed though as its details are not
397 /// yet finalized.
398 ///
399 /// # Examples
400 ///
401 /// ```
402 /// let data = &[
403 /// [0, 1],
404 /// [3, 4],
405 /// [6, 7],
406 /// ];
407 ///
408 /// let mut block = matrix_slice::from_array_rows(data);
409 ///
410 /// assert!(block.reborrow().select_cols(1..).is_some_and(|b| b.cols() == 1));
411 /// assert!(block.reborrow().select_cols(2..).is_some_and(|b| b.cols() == 0));
412 /// assert!(block.reborrow().select_cols(3..).is_none());
413 /// ```
414 pub fn select_cols<R>(self, range: R) -> Option<BlockRef<'data, T>>
415 where
416 R: MatrixIndex,
417 {
418 let (start, len) = range.into_start_and_len(self.block.cols)?;
419 let (_, block, offset) = self.block.split_at_col(start)?;
420 debug_assert!(block.cols >= len);
421
422 Some(BlockRef {
423 block: BlockSlice { cols: len, ..block },
424 // SAFETY: `split_at_col` guarantees that `offset` is in-bounds of the
425 // provenance tracked by `self.block`, which is in-sync with the pointer field
426 // (but we not necessary access these without synchronization). By extension
427 // of being in-bounds of the allocation the offset does not overflow `isize`.
428 data: unsafe { self.data.add(offset) },
429 lifetime: self.lifetime,
430 })
431 }
432
433 /// Choose a sub-block by its range of rows and columns.
434 pub fn select(
435 self,
436 row_range: impl MatrixIndex,
437 col_range: impl MatrixIndex,
438 ) -> Option<BlockRef<'data, T>> {
439 let block = self.select_rows(row_range)?;
440 block.select_cols(col_range)
441 }
442
443 /// Extract a contiguous underlying slice of elements if the block is contiguous.
444 ///
445 /// # Examples
446 ///
447 /// ```
448 /// let data = &[[0u32; 3]; 3];
449 /// let block = matrix_slice::from_array_rows(data);
450 ///
451 /// let (block, _) = block.split_at_row(2);
452 /// assert!(block.into_contiguous_slice().is_some());
453 ///
454 /// let (pre, post) = block.split_at_col(2);
455 /// assert!(pre.into_contiguous_slice().is_none());
456 /// assert!(post.into_contiguous_slice().is_none());
457 ///
458 /// let (same, _) = block.split_at_col(3);
459 /// assert!(same.into_contiguous_slice().is_some());
460 /// ```
461 pub fn into_contiguous_slice(self) -> Option<&'data [T]> {
462 if let Some(items) = self.block.contiguous_span() {
463 // SAFETY: `contiguous_span` ensures the block covers `items` contiguous elements.
464 // Since pointer provenance is a superset of block's element access that implies the
465 // pointer also has provenance for these elements. Since we have unique access to all
466 // the elements in the block we have non-aliased access to the whole slice.
467 Some(unsafe { core::slice::from_raw_parts(self.data.as_ptr().cast(), items) })
468 } else {
469 None
470 }
471 }
472
473 /// Turn this into a slice of the first row, assuming it is at most one row.
474 fn fake_contiguity(mut self) -> &'data [T] {
475 self.block.fake_contiguity();
476 self.into_contiguous_slice().unwrap()
477 }
478
479 /// Extract access as a slice of arrays if the block is contiguous.
480 ///
481 /// The caller must choose `N` matching the number of columns.
482 pub fn into_array_rows_checked<const N: usize>(self) -> Option<&'data [[T; N]]> {
483 if let Some(rows) = self.block.contiguous_arrays::<N>() {
484 // SAFETY: `` ensures the block covers `items` contiguous N-arrays of
485 // elements. Since pointer provenance is a superset of block's element access that
486 // implies the pointer also has provenance for these elements. Since we have unique
487 // access to all the elements in the block we have non-aliased access to the whole
488 // slice of elements. A slice and a slice of arrays have the same layout so the same
489 // holds for the correctly sized array the length of which `contiguous_arrays` promises
490 // to return.
491 Some(unsafe { core::slice::from_raw_parts(self.data.as_ptr().cast(), rows) })
492 } else {
493 None
494 }
495 }
496
497 /// Iterate over the rows of this block.
498 pub fn iter_rows(self) -> IterRows<'data, T> {
499 IterRows { block: self }
500 }
501
502 /// Create a reference to this block with a shorter lifetime.
503 pub fn reborrow(&self) -> BlockRef<'_, T> {
504 BlockRef {
505 data: self.data,
506 block: self.block,
507 lifetime: PhantomData,
508 }
509 }
510}
511
512impl<T> ops::Index<(usize, usize)> for BlockRef<'_, T> {
513 type Output = T;
514
515 fn index(&self, index: (usize, usize)) -> &Self::Output {
516 let idx = self.block.in_bounds_offset(index.0, index.1);
517 // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
518 // provenance of the pointer.
519 unsafe { &*self.data.as_ptr().add(idx) }
520 }
521}
522
523impl<T: fmt::Debug> fmt::Debug for BlockRef<'_, T> {
524 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
525 f.debug_list().entries(self.reborrow().iter_rows()).finish()
526 }
527}
528
529/// Create a mutable block reference from a full matrix represented as an array of rows.
530///
531/// # Examples
532///
533/// ```
534/// let data = &mut [
535/// [0, 1, 2],
536/// [3, 4, 5],
537/// ];
538///
539/// let mut block = matrix_slice::from_array_rows_mut(data);
540///
541/// assert_eq!(block.rows(), 2);
542/// assert_eq!(block.cols(), 3);
543///
544/// block[(1, 1)] = 42;
545///
546/// assert_eq!(data[1][1], 42);
547/// ```
548pub fn from_array_rows_mut<'a, T, const N: usize>(data: &'a mut [[T; N]]) -> BlockMut<'a, T> {
549 BlockMut {
550 block: BlockSlice {
551 rows: data.len(),
552 cols: N,
553 pitch: N,
554 },
555 data: NonNull::from_mut(data).cast(),
556 lifetime: PhantomData,
557 }
558}
559
560/// A reference to a block of a matrix with unique access to elements.
561pub struct BlockMut<'a, T> {
562 // Internal invariant: the size of the block is a subset of the provenance of the pointer. Also
563 // we never have two `BlockMut` with the same accessible elements active at the same time.
564 data: NonNull<T>,
565 block: BlockSlice,
566 lifetime: PhantomData<&'a mut [T]>,
567}
568
569// SAFETY: See `BlockRef` but with `&mut [T]`.
570//
571// We have `&mut T: Sync` iff `T: Sync`
572unsafe impl<T> Sync for BlockMut<'_, T> where T: Sync {}
573// We have `&mut T: Send` iff `T: Send`
574unsafe impl<T> Send for BlockMut<'_, T> where T: Sync {}
575
576/// ```compile_fail
577/// use matrix_slice::BlockMut;
578///
579/// // This coercion must *not* be possible. The field `lifetime` ensures the right variance.
580/// fn _coerce_item_not_covariant<'lt, 'a, 'b: 'a, T>(
581/// v: BlockMut<'lt, &'b T>,
582/// ) -> BlockMut<'lt, &'a T> {
583/// v
584/// // ^ function was supposed to return data with lifetime `'b` but it is returning data with lifetime `'a`
585/// }
586///
587/// ```compile_fail
588/// use matrix_slice::BlockMut;
589///
590/// fn _copy_block(v: BlockMut<'_, u32>) -> [BlockMut<'_, u32>; 2] {
591/// [v, v]
592/// }
593const _: () = {
594 // We can coerce a block to a shorter lifetime.
595 fn _coerce_block_mut<'a, 'b: 'a, T>(v: BlockMut<'b, T>) -> BlockMut<'a, T> {
596 v
597 }
598
599 // We can coerce a reference to a block to a shorter lifetime.
600 fn _coerce_covariant<'lt, 'a, 'b: 'a, T>(v: &'lt BlockMut<'b, T>) -> &'lt BlockMut<'a, T> {
601 v
602 }
603
604 fn _coerce_covariant_fn<'lt, 'a, 'b: 'a, T>(v: fn(BlockMut<'a, T>)) -> fn(BlockMut<'b, T>) {
605 v
606 }
607};
608
609/// Creates an empty block reference, within a matrix of a dangling slice.
610impl<T> Default for BlockMut<'_, T> {
611 fn default() -> Self {
612 from_array_rows_mut::<T, 0>(&mut [])
613 }
614}
615
616impl<'data, T> BlockMut<'data, T> {
617 /// Create a new block reference from a raw slice and pitch.
618 ///
619 /// The resulting block refers to the whole matrix.
620 ///
621 /// # Panics
622 ///
623 /// Panics if the length of `data` is not a multiple of `pitch`.
624 pub fn new(data: &'data mut [T], pitch: usize) -> Self {
625 assert!(data.len().is_multiple_of(pitch));
626
627 // SAFETY:
628 // - construction implies `count * pitch <= data.len()` covering the provenance.
629 // - this is the only block with mutable access to the whole data.
630 BlockMut {
631 block: BlockSlice {
632 rows: data.len() / pitch,
633 cols: pitch,
634 pitch,
635 },
636 data: NonNull::from_mut(data).cast(),
637 lifetime: PhantomData,
638 }
639 }
640
641 /// Number of rows in this block.
642 pub fn rows(&self) -> usize {
643 self.block.rows
644 }
645
646 /// Number of columns in this block.
647 pub fn cols(&self) -> usize {
648 self.block.cols
649 }
650
651 /// Divide into two blocks at the given column.
652 ///
653 /// # Examples
654 ///
655 /// ```
656 /// let data = &mut [
657 /// [0, 1, 2],
658 /// [3, 4, 5],
659 /// ];
660 ///
661 /// let block = matrix_slice::from_array_rows_mut(data);
662 /// let (left, right) = block.split_at_col(2);
663 ///
664 /// assert_eq!(left[(1, 0)], 3);
665 /// assert_eq!(right[(1, 0)], 5);
666 /// ```
667 pub fn split_at_col(self, mid: usize) -> (BlockMut<'data, T>, BlockMut<'data, T>) {
668 self.split_at_col_checked(mid).unwrap()
669 }
670
671 /// Divide into two blocks at the given column.
672 ///
673 /// See [`Self::split_at_col`] but returns `None` if out of bounds.
674 pub fn split_at_col_checked(
675 self,
676 mid: usize,
677 ) -> Option<(BlockMut<'data, T>, BlockMut<'data, T>)> {
678 if let Some((lhs, rhs, offset)) = self.block.split_at_col(mid) {
679 // SAFETY:
680 // - `split_at_col` guarantees that `offset` is in-bounds of the
681 // provenance tracked by `self.block`, which is in-sync with the pointer field
682 // (but we not necessary access these without synchronization). By extension
683 // of being in-bounds of the allocation the offset does not overflow `isize`.
684 // - the two blocks have disjunct access to the same elements as the input that is
685 // consumed by this operation.
686 Some((
687 BlockMut {
688 data: self.data,
689 block: lhs,
690 lifetime: self.lifetime,
691 },
692 BlockMut {
693 data: unsafe { self.data.add(offset) },
694 block: rhs,
695 lifetime: self.lifetime,
696 },
697 ))
698 } else {
699 None
700 }
701 }
702
703 /// Divide into two blocks at the given row.
704 ///
705 /// # Examples
706 ///
707 /// ```
708 /// let data = &mut [
709 /// [0, 1, 2],
710 /// [3, 4, 5],
711 /// ];
712 ///
713 /// let block = matrix_slice::from_array_rows_mut(data);
714 /// let (top, bot) = block.split_at_row(1);
715 ///
716 /// assert_eq!(top[(0, 2)], 2);
717 /// assert_eq!(bot[(0, 2)], 5);
718 /// ```
719 pub fn split_at_row(self, mid: usize) -> (BlockMut<'data, T>, BlockMut<'data, T>) {
720 self.split_at_row_checked(mid).unwrap()
721 }
722
723 /// Divide into two blocks at the given row.
724 ///
725 /// See [`Self::split_at_row`] but returns `None` if out of bounds.
726 pub fn split_at_row_checked(
727 self,
728 mid: usize,
729 ) -> Option<(BlockMut<'data, T>, BlockMut<'data, T>)> {
730 if let Some((lhs, rhs, offset)) = self.block.split_at_row(mid) {
731 // SAFETY:
732 // - `split_at_row` guarantees that `offset` is in-bounds of the
733 // provenance tracked by `self.block`, which is in-sync with the pointer field
734 // (but we not necessary access these without synchronization). By extension
735 // of being in-bounds of the allocation the offset does not overflow `isize`.
736 // - the two blocks have disjunct access to the same elements as the input that is
737 // consumed by this operation.
738 Some((
739 BlockMut {
740 data: self.data,
741 block: lhs,
742 lifetime: self.lifetime,
743 },
744 BlockMut {
745 data: unsafe { self.data.add(offset) },
746 block: rhs,
747 lifetime: self.lifetime,
748 },
749 ))
750 } else {
751 None
752 }
753 }
754
755 /// Choose a single row and refer to its data.
756 ///
757 /// # Examples
758 ///
759 /// ```
760 /// let data = &mut [
761 /// [0, 1, 2],
762 /// [3, 4, 5],
763 /// [6, 7, 8],
764 /// ];
765 ///
766 /// let mut block = matrix_slice::from_array_rows_mut(data);
767 /// let mut row = block.reborrow().row(1);
768 /// row[0] = 0x42;
769 /// assert_eq!(block[(1, 0)], 0x42);
770 /// ```
771 pub fn row(self, row: usize) -> VecMut<'data, T> {
772 self.row_checked(row).unwrap()
773 }
774
775 /// Choose a single row and refer to its data.
776 ///
777 /// See [`Self::row`] but returns `None` if out of bounds.
778 pub fn row_checked(self, row: usize) -> Option<VecMut<'data, T>> {
779 let (_, block, offset) = self.block.split_at_row(row)?;
780
781 if block.rows == 0 {
782 return None;
783 }
784
785 // - `split_at_row` guarantees that `offset` is in-bounds of the
786 // provenance tracked by `self.block`, which is in-sync with the pointer field
787 // (but we not necessary access these without synchronization). By extension
788 // of being in-bounds of the allocation the offset does not overflow `isize`.
789 // - the `block` has disjunct access to its column elements and contains
790 // at least one row of data as asserted. Elements within a row have pitch `1`.
791 Some(VecMut {
792 block: VectorSlice {
793 count: block.cols,
794 pitch: 1,
795 },
796 // SAFETY: see above.
797 data: unsafe { self.data.add(offset) },
798 lifetime: self.lifetime,
799 })
800 }
801
802 /// Choose a single column and refer to its data.
803 ///
804 /// # Examples
805 ///
806 /// ```
807 /// let data = &mut [
808 /// [0, 1, 2],
809 /// [3, 4, 5],
810 /// [6, 7, 8],
811 /// ];
812 ///
813 /// let mut block = matrix_slice::from_array_rows_mut(data);
814 /// let mut row = block.reborrow().col(1);
815 /// row[0] = 0x42;
816 /// assert_eq!(block[(0, 1)], 0x42);
817 /// ```
818 pub fn col(self, col: usize) -> VecMut<'data, T> {
819 self.col_checked(col).unwrap()
820 }
821
822 /// Choose a single column and refer to its data.
823 ///
824 /// See [`Self::col`] but returns `None` if out of bounds.
825 pub fn col_checked(self, col: usize) -> Option<VecMut<'data, T>> {
826 let (_, block, offset) = self.block.split_at_col(col)?;
827
828 if block.cols == 0 {
829 return None;
830 }
831
832 // - `split_at_col` guarantees that `offset` is in-bounds of the
833 // provenance tracked by `self.block`, which is in-sync with the pointer field
834 // (but we not necessary access these without synchronization). By extension
835 // of being in-bounds of the allocation the offset does not overflow `isize`.
836 // - the `block` has disjunct access to its row elements and contains
837 // at least one column of data as asserted. Elements within a column have pitch
838 // `block.pitch`.
839 Some(VecMut {
840 block: VectorSlice {
841 count: block.rows,
842 pitch: block.pitch,
843 },
844 // SAFETY: see above.
845 data: unsafe { self.data.add(offset) },
846 lifetime: self.lifetime,
847 })
848 }
849
850 /// Choose a range of rows and contract the block to that.
851 ///
852 /// The argument type is flexible, allowing ranges (`1..3`), half open ranges (`2..` and `..2`)
853 /// among others. See the [`MatrixIndex`] trait, which is sealed though as its details are not
854 /// yet finalized.
855 ///
856 /// # Examples
857 ///
858 /// ```
859 /// let data = &mut [
860 /// [0, 1, 2],
861 /// [3, 4, 5],
862 /// [6, 7, 8],
863 /// ];
864 ///
865 /// let block = matrix_slice::from_array_rows_mut(data);
866 ///
867 /// let center = block.select_rows(1..2).unwrap();
868 /// assert_eq!(center.rows(), 1);
869 /// assert_eq!(center.cols(), 3);
870 /// assert_eq!(center[(0, 1)], 4);
871 /// ```
872 pub fn select_rows<R>(self, range: R) -> Option<BlockMut<'data, T>>
873 where
874 R: MatrixIndex,
875 {
876 let (start, len) = range.into_start_and_len(self.block.rows)?;
877 let (_, block, offset) = self.block.split_at_row(start)?;
878 assert!(block.rows >= len);
879
880 Some(BlockMut {
881 block: BlockSlice { rows: len, ..block },
882 // SAFETY:
883 // - `split_at_row` guarantees that `offset` is in-bounds of the provenance tracked by
884 // `self.block`, which is in-sync with the pointer field (but we not necessary access
885 // these without synchronization). By extension of being in-bounds of the allocation
886 // the offset does not overflow `isize`.
887 // - the block has access to a subset of elements as `self` which is consumed. This
888 // holds because `into_start_and_len` ensures that `start + len <= self.block.rows`.
889 data: unsafe { self.data.add(offset) },
890 lifetime: self.lifetime,
891 })
892 }
893
894 /// Choose a range of columns and contract the block to that.
895 ///
896 /// The argument type is flexible, allowing ranges (`1..3`), half open ranges (`2..` and `..2`)
897 /// among others. See the [`MatrixIndex`] trait, which is sealed though as its details are not
898 /// yet finalized.
899 ///
900 /// ```
901 /// let data = &mut [
902 /// [0, 1],
903 /// [3, 4],
904 /// [6, 7],
905 /// ];
906 ///
907 /// let mut block = matrix_slice::from_array_rows_mut(data);
908 ///
909 /// assert!(block.reborrow().select_cols(1..).is_some_and(|b| b.cols() == 1));
910 /// assert!(block.reborrow().select_cols(2..).is_some_and(|b| b.cols() == 0));
911 /// assert!(block.reborrow().select_cols(3..).is_none());
912 /// ```
913 pub fn select_cols<R>(self, range: R) -> Option<BlockMut<'data, T>>
914 where
915 R: MatrixIndex,
916 {
917 let (start, len) = range.into_start_and_len(self.block.cols)?;
918 let (_, block, offset) = self.block.split_at_col(start)?;
919 debug_assert!(block.cols >= len);
920
921 Some(BlockMut {
922 block: BlockSlice { cols: len, ..block },
923 // SAFETY:
924 // - `split_at_col` guarantees that `offset` is in-bounds of the provenance tracked by
925 // `self.block`, which is in-sync with the pointer field (but we not necessary access
926 // these without synchronization). By extension of being in-bounds of the allocation
927 // the offset does not overflow `isize`.
928 // - the block has access to a subset of elements as `self` which is consumed. This
929 // holds because `into_start_and_len` ensures that `start + len <= self.block.cols`.
930 data: unsafe { self.data.add(offset) },
931 lifetime: self.lifetime,
932 })
933 }
934
935 /// Choose a sub-block by its range of rows and columns.
936 pub fn select(
937 self,
938 row_range: impl MatrixIndex,
939 col_range: impl MatrixIndex,
940 ) -> Option<BlockMut<'data, T>> {
941 let block = self.select_rows(row_range)?;
942 block.select_cols(col_range)
943 }
944
945 /// Extract a contiguous underlying slice of elements if the block is contiguous.
946 ///
947 /// # Examples
948 ///
949 /// ```
950 /// let data = &mut [[0u32; 3]; 3];
951 /// let mut block = matrix_slice::from_array_rows_mut(data);
952 ///
953 /// let (mut part, _) = block.reborrow().split_at_row(2);
954 /// assert!(part.into_contiguous_slice().is_some());
955 ///
956 /// let (pre, post) = block.reborrow().split_at_col(2);
957 /// assert!(pre.into_contiguous_slice().is_none());
958 /// assert!(post.into_contiguous_slice().is_none());
959 ///
960 /// let (same, _) = block.reborrow().split_at_col(3);
961 /// assert!(same.into_contiguous_slice().is_some());
962 /// ```
963 pub fn into_contiguous_slice(self) -> Option<&'data mut [T]> {
964 if let Some(items) = self.block.contiguous_span() {
965 // SAFETY: `contiguous_span` ensures the block covers `items` contiguous elements.
966 // Since pointer provenance is a superset of block's element access that implies the
967 // pointer also has provenance for these elements. Since we have unique access to all
968 // the elements in the block we have non-aliased access to the whole slice.
969 Some(unsafe { core::slice::from_raw_parts_mut(self.data.as_ptr().cast(), items) })
970 } else {
971 None
972 }
973 }
974
975 /// Turn this into a slice of the first row, assuming it is at most one row.
976 fn fake_contiguity(mut self) -> &'data mut [T] {
977 self.block.fake_contiguity();
978 self.into_contiguous_slice().unwrap()
979 }
980
981 /// Extract access as a slice of arrays if the block is contiguous.
982 ///
983 /// The caller must choose `N` matching the number of columns.
984 ///
985 /// # Examples
986 ///
987 /// ```
988 /// let data = &mut [[0u32; 3]; 3];
989 /// let mut block = matrix_slice::from_array_rows_mut(data);
990 ///
991 /// // Turns this back into the same type as `data` had.
992 /// assert!(block.reborrow().into_array_rows_checked::<3>().is_some());
993 ///
994 /// // Using an incorrect number of columns fails.
995 /// assert!(block.reborrow().into_array_rows_checked::<2>().is_none());
996 ///
997 /// // Can still be used after splitting at rows.
998 /// let (_, mut block) = block.split_at_row(2);
999 /// assert!(block.reborrow().into_array_rows_checked::<3>().is_some());
1000 /// ```
1001 pub fn into_array_rows_checked<const N: usize>(self) -> Option<&'data mut [[T; N]]> {
1002 if let Some(rows) = self.block.contiguous_arrays::<N>() {
1003 // SAFETY: `` ensures the block covers `items` contiguous N-arrays of
1004 // elements. Since pointer provenance is a superset of block's element access that
1005 // implies the pointer also has provenance for these elements. Since we have unique
1006 // access to all the elements in the block we have non-aliased access to the whole
1007 // slice of elements. A slice and a slice of arrays have the same layout so the same
1008 // holds for the correctly sized array the length of which `contiguous_arrays` promises
1009 // to return.
1010 Some(unsafe { core::slice::from_raw_parts_mut(self.data.as_ptr().cast(), rows) })
1011 } else {
1012 None
1013 }
1014 }
1015
1016 /// Turn this unique reference into a shared reference.
1017 pub fn cast_const(self) -> BlockRef<'data, T> {
1018 // SAFETY: shared access can always be re-tagged from unique access.
1019 BlockRef {
1020 data: self.data,
1021 block: self.block,
1022 lifetime: PhantomData,
1023 }
1024 }
1025
1026 /// Create a unique reference to this block with a shorter lifetime.
1027 pub fn reborrow(&mut self) -> BlockMut<'_, T> {
1028 // SAFETY: Unique access is created by deriving it from our current pointer so the
1029 // provenance is the same, and temporally it can not overlap access through the current
1030 // value due to the lifetime enforcing a borrow relationship.
1031 BlockMut {
1032 data: self.data,
1033 block: self.block,
1034 lifetime: PhantomData,
1035 }
1036 }
1037
1038 /// Iterate over the rows of this block.
1039 pub fn iter_rows(self) -> IterRows<'data, T> {
1040 self.cast_const().iter_rows()
1041 }
1042
1043 /// Iterate over the rows of this block.
1044 pub fn iter_rows_mut(self) -> IterRowsMut<'data, T> {
1045 IterRowsMut { block: self }
1046 }
1047
1048 /// Modify the item type to a `Cell`, allowing interior mutability.
1049 ///
1050 /// This is the equivalent of [`Cell::from_mut`] over elements in this slice.
1051 pub fn as_cells(self) -> BlockMut<'data, Cell<T>> {
1052 // SAFETY: `Cell<T>` has the same layout as `T`.
1053 BlockMut {
1054 data: self.data.cast(),
1055 block: self.block,
1056 lifetime: PhantomData,
1057 }
1058 }
1059}
1060
1061impl<'data, T> BlockMut<'data, Cell<T>> {
1062 /// Modify the item type from a `Cell` to its interior type.
1063 ///
1064 /// This is the equivalent of [`Cell::get_mut`] over elements in this slice.
1065 pub fn as_cell_items(self) -> BlockMut<'data, T> {
1066 // SAFETY: `Cell<T>` has the same layout as `T`.
1067 BlockMut {
1068 data: self.data.cast(),
1069 block: self.block,
1070 lifetime: PhantomData,
1071 }
1072 }
1073}
1074
1075impl<T> ops::Index<(usize, usize)> for BlockMut<'_, T> {
1076 type Output = T;
1077
1078 fn index(&self, index: (usize, usize)) -> &Self::Output {
1079 let idx = self.block.in_bounds_offset(index.0, index.1);
1080 // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
1081 // provenance of the pointer.
1082 unsafe { &*self.data.as_ptr().add(idx) }
1083 }
1084}
1085
1086impl<T> ops::IndexMut<(usize, usize)> for BlockMut<'_, T> {
1087 fn index_mut(&mut self, index: (usize, usize)) -> &mut Self::Output {
1088 let idx = self.block.in_bounds_offset(index.0, index.1);
1089 // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
1090 // provenance of the pointer.
1091 unsafe { &mut *self.data.as_ptr().add(idx) }
1092 }
1093}
1094
1095/// Represents the provenance of a pointer to a block of a matrix.
1096///
1097/// FIXME: before exposing this consider `PartialEq, … Ord` implications. These were added to
1098/// satisfy the `Pointee` trait requirements but really what does ordering mean? We have chosen the
1099/// field `pitch` to be last but that is super arbitrary.
1100///
1101/// We assume row major order here for the convention of _naming_ things. That is, when we say row
1102/// we mean a tightly packed slice of items. This implies that the item pitch is assumed to be `1`.
1103/// We have two major possible choices in representation a block-subset of a matrix: store the
1104/// dimensions of the block with a matrix row pitch or store the total size of the matrix and two
1105/// lengths.
1106///
1107/// The former of these allows us to represent both `0×N` and `M×0` blocks naturally, while the
1108/// latter allows one of them but provides a fast capacity that's pre-calculated. We choose the
1109/// former. In either case we need to store three `usize` values. Note that the total span of items
1110/// is *not* `rows * pitch` since the last row might be ragged.
1111#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
1112struct BlockSlice {
1113 rows: usize,
1114 cols: usize,
1115 pitch: usize,
1116}
1117
1118const _: () = {
1119 // As per Rust 1.92's `Pointee` trait. Suspicious: `Ord`. See comment on `BlockSlice`.
1120 use core::{fmt, hash};
1121
1122 fn _can_eventually_be_ptr_metadata<
1123 // Missing: `Freeze` which is unstable
1124 Metadata: fmt::Debug + Copy + Send + Sync + Ord + hash::Hash + Unpin,
1125 >() {
1126 }
1127
1128 let _ = _can_eventually_be_ptr_metadata::<BlockSlice>;
1129};
1130
1131impl BlockSlice {
1132 /// The number of elements if this block is contiguous (cols equals pitch).
1133 fn contiguous_span(&self) -> Option<usize> {
1134 if self.cols == self.pitch {
1135 Some(self.rows * self.cols)
1136 } else {
1137 None
1138 }
1139 }
1140
1141 /// The number of rows if this block is contiguous (cols equals pitch) and matching a static
1142 /// count of column elements.
1143 fn contiguous_arrays<const N: usize>(&self) -> Option<usize> {
1144 if self.cols == self.pitch && self.cols == N {
1145 Some(self.rows)
1146 } else {
1147 None
1148 }
1149 }
1150
1151 /// The number of elements spanned by this block (including those we are not allowed to
1152 /// access).
1153 fn total_span(&self) -> usize {
1154 if let Some(all_but_last) = self.rows.checked_sub(1) {
1155 all_but_last * self.pitch + self.cols
1156 } else {
1157 0
1158 }
1159 }
1160
1161 /// The caller must ensure that this block has at most one row.
1162 fn fake_contiguity(&mut self) {
1163 debug_assert!(self.rows <= 1);
1164 debug_assert!(self.cols <= self.pitch);
1165
1166 self.rows = self.rows.min(1);
1167 // SAFETY: Reducing the pitch when we have at most one row does not change the elements we
1168 // may refer to. The pitch always exceeds the number of columns.
1169 self.pitch = self.cols;
1170 }
1171
1172 /// Split into two block descriptors.
1173 ///
1174 /// Returns `Some` with two valid blocks. The first block is in-bounds. Also returns an offset
1175 /// that is in-bounds of the current block and such that the elements valid for both blocks do
1176 /// not alias. The second block is in-bounds when interpreted as start at the offset.
1177 fn split_at_row(self, mid: usize) -> Option<(BlockSlice, BlockSlice, usize)> {
1178 let n = self.rows.checked_sub(mid)?;
1179
1180 let lhs = BlockSlice {
1181 rows: mid,
1182 cols: self.cols,
1183 pitch: self.pitch,
1184 };
1185
1186 let rhs = BlockSlice {
1187 rows: n,
1188 cols: self.cols,
1189 pitch: self.pitch,
1190 };
1191
1192 // Careful: If we split a block after its last row (i.e. lhs and self are identical),
1193 // the naive offset of rows * pitch may point beyond the total span of elements covered
1194 // by ourselves. In this case the rhs does not cover any row so we assign it any
1195 // in-bounds offset.
1196 let offset = if n > 0 { mid * self.pitch } else { 0 };
1197 debug_assert!(offset <= self.total_span());
1198
1199 Some((lhs, rhs, offset))
1200 }
1201
1202 fn split_at_col(self, mid: usize) -> Option<(BlockSlice, BlockSlice, usize)> {
1203 let n = self.cols.checked_sub(mid)?;
1204
1205 let lhs = BlockSlice {
1206 rows: self.rows,
1207 cols: mid,
1208 pitch: self.pitch,
1209 };
1210
1211 let rhs = BlockSlice {
1212 rows: self.rows,
1213 cols: n,
1214 pitch: self.pitch,
1215 };
1216
1217 // If we have no rows at all then this block does not cover any elements so we must
1218 // pick an offset of 0 to guarantee in-bounds access. The good news is that this case
1219 // also implies that the other side is empty so its offset does not matter.
1220 let offset = if self.rows > 0 { mid } else { 0 };
1221 debug_assert!(offset <= self.total_span());
1222
1223 Some((lhs, rhs, offset))
1224 }
1225
1226 /// Return the absolute position of the element, if in bounds. Otherwise, panic.
1227 fn in_bounds_offset(&self, row: usize, col: usize) -> usize {
1228 assert!(row < self.rows);
1229 assert!(col < self.cols);
1230 let idx = row * self.pitch + col;
1231 debug_assert!(idx < self.total_span());
1232 idx
1233 }
1234}
1235
1236/// Represents the provenance of a pointer to a single column/row of a matrix.
1237///
1238/// FIXME: before exposing this consider `PartialEq, … Ord` implications. These were added to
1239/// satisfy the `Pointee` trait requirements but really what does ordering mean? We have chosen the
1240/// field `pitch` to be last but that is super arbitrary.
1241#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
1242struct VectorSlice {
1243 count: usize,
1244 pitch: usize,
1245}
1246
1247const _: () = {
1248 // As per Rust 1.92's `Pointee` trait. Suspicious: `Ord`. See comment on `VectorSlice`.
1249 use core::{fmt, hash};
1250
1251 fn _can_eventually_be_ptr_metadata<
1252 // Missing: `Freeze` which is unstable
1253 Metadata: fmt::Debug + Copy + Send + Sync + Ord + hash::Hash + Unpin,
1254 >() {
1255 }
1256
1257 let _ = _can_eventually_be_ptr_metadata::<VectorSlice>;
1258};
1259
1260impl VectorSlice {
1261 /// Split into two vector descriptors.
1262 ///
1263 /// Returns `Some` with two valid slice. The first slice is in-bounds. Also returns an offset
1264 /// that is in-bounds of the current slice and such that the elements valid for both blocks do
1265 /// not alias. The second block is in-bounds when interpreted as start at the offset.
1266 fn split_at(self, mid: usize) -> Option<(VectorSlice, VectorSlice, usize)> {
1267 let right_count = self.count.checked_sub(mid)?;
1268
1269 let left = VectorSlice {
1270 count: mid,
1271 pitch: self.pitch,
1272 };
1273
1274 let right = VectorSlice {
1275 count: right_count,
1276 pitch: self.pitch,
1277 };
1278
1279 // We need to make sure that this is in-bounds of the allocation. Note that the provenance
1280 // stretches only past our last element, not an additional pitch past it. So we can use the
1281 // simple formula only if there are elements covered by the right part of the split.
1282 // Fortunately the opposite of this implies that the right does not cover any elements and
1283 // we can thus use any inbounds pointer; like the zero offset.
1284 let offset = if right_count == 0 {
1285 0
1286 } else {
1287 mid * self.pitch
1288 };
1289
1290 Some((left, right, offset))
1291 }
1292
1293 /// Return the absolute position of the element, if in bounds. Otherwise, panic.
1294 fn in_bounds_offset(&self, index: usize) -> usize {
1295 assert!(index < self.count);
1296 index * self.pitch
1297 }
1298}
1299
1300/// Iterate over the rows of a block in a matrix.
1301///
1302/// We assume row-major matrices here, a row is a contiguous slice of items.
1303pub struct IterRows<'a, T> {
1304 block: BlockRef<'a, T>,
1305}
1306
1307impl<'data, T> Iterator for IterRows<'data, T> {
1308 type Item = &'data [T];
1309
1310 fn next(&mut self) -> Option<Self::Item> {
1311 if self.block.rows() == 0 {
1312 None
1313 } else {
1314 // FIXME: add `split_off_rows` instead.
1315 let (row, rest) = core::mem::take(&mut self.block).split_at_row(1);
1316 self.block = rest;
1317 // One row as it was created from `split_at_row(1)`.
1318 Some(row.fake_contiguity())
1319 }
1320 }
1321}
1322
1323/// Iterate over mutable rows of a block in a matrix.
1324///
1325/// We assume row-major matrices here, a row is a contiguous slice of items.
1326pub struct IterRowsMut<'a, T> {
1327 block: BlockMut<'a, T>,
1328}
1329
1330impl<'data, T> Iterator for IterRowsMut<'data, T> {
1331 type Item = &'data mut [T];
1332
1333 fn next(&mut self) -> Option<Self::Item> {
1334 if self.block.rows() == 0 {
1335 None
1336 } else {
1337 // FIXME: add `split_off_rows` instead.
1338 let (row, rest) = core::mem::take(&mut self.block).split_at_row(1);
1339 self.block = rest;
1340 // One row as it was created from `split_at_row(1)`.
1341 Some(row.fake_contiguity())
1342 }
1343 }
1344}
1345
1346pub trait MatrixIndex: sealed::Sealed {}
1347
1348impl MatrixIndex for ops::Range<usize> {}
1349impl MatrixIndex for ops::RangeInclusive<usize> {}
1350impl MatrixIndex for ops::RangeFrom<usize> {}
1351impl MatrixIndex for ops::RangeTo<usize> {}
1352impl MatrixIndex for ops::RangeToInclusive<usize> {}
1353impl MatrixIndex for ops::RangeFull {}
1354
1355pub trait OneSidedMatrixIndex: sealed::SealedOneSided {}
1356
1357impl OneSidedMatrixIndex for ops::RangeFrom<usize> {}
1358impl OneSidedMatrixIndex for ops::RangeTo<usize> {}
1359impl OneSidedMatrixIndex for ops::RangeToInclusive<usize> {}
1360
1361mod sealed {
1362 use core::ops;
1363
1364 pub trait Sealed {
1365 /// SAFETY: It is crucial that `start + len <= dim` holds if `Some` is returned.
1366 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)>;
1367 }
1368
1369 pub trait SealedOneSided {
1370 /// SAFETY: It is crucial that `split <= dim` holds if `Some` is returned.
1371 fn into_split_point(self, dim: usize) -> Option<(bool, usize)>;
1372 }
1373
1374 impl Sealed for ops::Range<usize> {
1375 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1376 if self.start <= self.end && self.end <= dim {
1377 // SAFETY: overflow can not have occurred, so `self.start + len = self.end <= dim`.
1378 Some((self.start, self.end - self.start))
1379 } else {
1380 None
1381 }
1382 }
1383 }
1384
1385 impl Sealed for ops::RangeInclusive<usize> {
1386 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1387 let start = *self.start();
1388 let end = *self.end();
1389 if start <= end && end < dim {
1390 // SAFETY: overflow can not have occurred, so `self.start + len = self.end + 1 <= dim`.
1391 Some((start, end - start + 1))
1392 } else {
1393 None
1394 }
1395 }
1396 }
1397
1398 impl Sealed for ops::RangeFrom<usize> {
1399 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1400 if self.start <= dim {
1401 // SAFETY: overflow can not have occurred, so `self.start + len = dim <= dim`.
1402 Some((self.start, dim - self.start))
1403 } else {
1404 None
1405 }
1406 }
1407 }
1408
1409 impl Sealed for ops::RangeTo<usize> {
1410 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1411 if self.end <= dim {
1412 // SAFETY: `self.end <= dim` by test.
1413 Some((0, self.end))
1414 } else {
1415 None
1416 }
1417 }
1418 }
1419
1420 impl Sealed for ops::RangeToInclusive<usize> {
1421 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1422 if self.end < dim {
1423 // SAFETY: `self.end + 1 <= dim` by test.
1424 Some((0, self.end + 1))
1425 } else {
1426 None
1427 }
1428 }
1429 }
1430
1431 impl Sealed for ops::RangeFull {
1432 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1433 // SAFETY: `dim <= dim` by tautology.
1434 Some((0, dim))
1435 }
1436 }
1437
1438 impl SealedOneSided for ops::RangeFrom<usize> {
1439 fn into_split_point(self, dim: usize) -> Option<(bool, usize)> {
1440 if self.start <= dim {
1441 // SAFETY: `self.start <= dim` by test.
1442 Some((false, self.start))
1443 } else {
1444 None
1445 }
1446 }
1447 }
1448
1449 impl SealedOneSided for ops::RangeTo<usize> {
1450 fn into_split_point(self, dim: usize) -> Option<(bool, usize)> {
1451 if self.end <= dim {
1452 // SAFETY: `self.end <= dim` by test.
1453 Some((true, self.end))
1454 } else {
1455 None
1456 }
1457 }
1458 }
1459
1460 impl SealedOneSided for ops::RangeToInclusive<usize> {
1461 fn into_split_point(self, dim: usize) -> Option<(bool, usize)> {
1462 if self.end < dim {
1463 // SAFETY: `self.end <= dim` by test.
1464 Some((true, self.end + 1))
1465 } else {
1466 None
1467 }
1468 }
1469 }
1470}
1471
1472/// A reference to a single column/row of a matrix.
1473///
1474/// This is similar to `&[T]` but with a pitch potentially different from `1` between its elements,
1475/// i.e. there is no guarantee of contiguity. As a consequence this does not have a simple
1476/// past-the-end pointer like a slice would have. For an empty slice the only guaranteed-valid
1477/// pointer is the base pointer itself while for larger slices the last guaranteed-valid pointer is
1478/// one-past the last element, _not_ one additional pitch.
1479///
1480/// Created from its constructors or a block reference via the [`BlockRef::col`] and
1481/// [`BlockRef::row`] methods.
1482#[derive(Copy, Clone)]
1483pub struct VecRef<'a, T> {
1484 // Internal invariant: the size of the block is a subset of the provenance of the pointer.
1485 data: NonNull<T>,
1486 block: VectorSlice,
1487 lifetime: PhantomData<&'a [T]>,
1488}
1489
1490// SAFETY: See `&[T]`. The reference can be used to, potentially, get a `&T` for each element in
1491// the block and thus the block itself provides the exact same properties as `T`. The `VecRef` is
1492// then `&[T]` itself and thus has properties of a reference to such a type. Refer to the
1493// reference: <https://doc.rust-lang.org/stable/std/primitive.reference.html>
1494//
1495// We have `&T: Sync` iff `T: Sync`
1496unsafe impl<T> Sync for VecRef<'_, T> where T: Sync {}
1497// We have `&T: Send` iff `T: Sync`
1498unsafe impl<T> Send for VecRef<'_, T> where T: Sync {}
1499
1500impl<'data, T> VecRef<'data, T> {
1501 /// Create a new vector reference from a raw slice and pitch.
1502 ///
1503 /// The resulting block refers to the first column of the matrix.
1504 ///
1505 /// # Panics
1506 ///
1507 /// Panics if the pitch is zero.
1508 pub fn new(data: &'data [T], pitch: usize) -> Self {
1509 assert_ne!(pitch, 0);
1510
1511 VecRef {
1512 // SAFETY: construction implies `count * pitch <= data.len()`.
1513 block: VectorSlice {
1514 count: data.len() / pitch,
1515 pitch,
1516 },
1517 data: NonNull::from(data).cast(),
1518 lifetime: PhantomData,
1519 }
1520 }
1521
1522 /// Create a new vector reference from a raw slice with pitch `1`.
1523 pub fn from_slice(data: &'data [T]) -> Self {
1524 VecRef {
1525 block: VectorSlice {
1526 count: data.len(),
1527 pitch: 1,
1528 },
1529 data: NonNull::from(data).cast(),
1530 lifetime: PhantomData,
1531 }
1532 }
1533
1534 /// Number of elements in this vector.
1535 pub fn len(&self) -> usize {
1536 self.block.count
1537 }
1538
1539 /// Whether this vector is empty.
1540 pub fn is_empty(&self) -> bool {
1541 self.block.count == 0
1542 }
1543
1544 /// Divide into two vectors at the given element.
1545 ///
1546 /// # Examples
1547 ///
1548 /// ```
1549 /// use matrix_slice::VecRef;
1550 ///
1551 /// let data = &[0, 1, 2, 3, 4, 5];
1552 ///
1553 /// let block = VecRef::new(data, 1);
1554 /// let (left, right) = block.split_at(2);
1555 ///
1556 /// assert_eq!(left[1], 1);
1557 /// assert_eq!(right[3], 5);
1558 /// ```
1559 pub fn split_at(self, mid: usize) -> (VecRef<'data, T>, VecRef<'data, T>) {
1560 self.split_at_checked(mid).unwrap()
1561 }
1562
1563 /// Divide into two vectors at the given element.
1564 ///
1565 /// See [`Self::split_at`] but returns `None` if out of bounds.
1566 pub fn split_at_checked(mut self, mid: usize) -> Option<(VecRef<'data, T>, VecRef<'data, T>)> {
1567 // Let's assume this will collapse during const-prop after the type here is inserted.
1568 let tail = self.split_off(mid..)?;
1569 Some((self, tail))
1570 }
1571
1572 /// Take part of the vector.
1573 ///
1574 /// # Examples
1575 ///
1576 /// ```
1577 /// use matrix_slice::VecRef;
1578 ///
1579 /// let data = &[0, 1, 2, 3, 4, 5];
1580 /// let mut vec = VecRef::new(data, 1);
1581 ///
1582 /// // Does nothing.
1583 /// assert!(vec.split_off(6..).is_some_and(|v| v.is_empty()));
1584 /// assert!(vec.split_off(7..).is_none());
1585 /// assert!(vec.split_off(..7).is_none());
1586 ///
1587 /// let right = vec.split_off(2..).unwrap();
1588 /// assert_eq!(vec.len(), 2);
1589 /// assert_eq!(right[3], 5);
1590 /// ```
1591 ///
1592 /// You can also split off the start:
1593 ///
1594 /// ```
1595 /// use matrix_slice::VecRef;
1596 ///
1597 /// let data = &[0, 1, 2, 3, 4, 5];
1598 /// let mut vec = VecRef::new(data, 1);
1599 /// let start = vec.split_off(..=2).unwrap();
1600 ///
1601 /// assert_eq!(vec[0], 3);
1602 /// assert_eq!(start[0], 0);
1603 /// ```
1604 pub fn split_off<R>(&mut self, range: R) -> Option<Self>
1605 where
1606 R: OneSidedMatrixIndex,
1607 {
1608 let (is_front, split_point) = range.into_split_point(self.block.count)?;
1609 let (left, right, offset) = self.block.split_at(split_point)?;
1610
1611 let ptr = self.data;
1612 let (ours, theirs) = if is_front {
1613 ((right, offset), (left, 0))
1614 } else {
1615 ((left, 0), (right, offset))
1616 };
1617
1618 self.block = ours.0;
1619 self.data = unsafe { ptr.add(ours.1) };
1620
1621 Some(VecRef {
1622 block: theirs.0,
1623 data: unsafe { ptr.add(theirs.1) },
1624 lifetime: self.lifetime,
1625 })
1626 }
1627
1628 /// Choose a range of elements and contract the vector to that.
1629 pub fn select<R>(self, range: R) -> Option<VecRef<'data, T>>
1630 where
1631 R: MatrixIndex,
1632 {
1633 let (start, len) = range.into_start_and_len(self.block.count)?;
1634 let (_, block, offset) = self.block.split_at(start)?;
1635 // Safety: ensures that the resulting block is more constrained, this property should be
1636 // ensured by our sealed `MatrixIndex` implementations.
1637 assert!(block.count >= len);
1638
1639 Some(VecRef {
1640 block: VectorSlice {
1641 count: len,
1642 ..block
1643 },
1644 // SAFETY: offset is in-bounds as per `split_at` contract.
1645 data: unsafe { self.data.add(offset) },
1646 lifetime: self.lifetime,
1647 })
1648 }
1649
1650 /// # Examples
1651 ///
1652 /// ```
1653 /// let data = &[
1654 /// [0, 1, 2],
1655 /// [3, 4, 5],
1656 /// [6, 7, 8],
1657 /// ];
1658 ///
1659 /// let block = matrix_slice::from_array_rows(data);
1660 /// let column = block.col(1);
1661 ///
1662 /// assert!(column.iter().eq(&[1, 4, 7]));
1663 /// ```
1664 pub fn iter(self) -> IterVec<'data, T> {
1665 IterVec { vec: self }
1666 }
1667}
1668
1669impl<T> ops::Index<usize> for VecRef<'_, T> {
1670 type Output = T;
1671
1672 fn index(&self, index: usize) -> &Self::Output {
1673 let idx = self.block.in_bounds_offset(index);
1674 // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
1675 // provenance of the pointer.
1676 unsafe { &*self.data.as_ptr().add(idx) }
1677 }
1678}
1679
1680/// A reference to a single column/row of a matrix.
1681///
1682/// This is similar to `&[T]` but with a pitch potentially different from `1` between its elements,
1683/// i.e. there is no guarantee of contiguity. As a consequence this does not have a simple
1684/// past-the-end pointer like a slice would have. For an empty slice the only guaranteed-valid
1685/// pointer is the base pointer itself while for larger slices the last guaranteed-valid pointer is
1686/// one-past the last element, _not_ one additional pitch.
1687///
1688/// Created from its constructors or a block reference via the [`BlockMut::col`] and
1689/// [`BlockMut::row`] methods.
1690pub struct VecMut<'a, T> {
1691 // Internal invariant: the size of the block is a subset of the provenance of the pointer. Also
1692 // we never have two `VecMut` with the same accessible elements active at the same time.
1693 data: NonNull<T>,
1694 block: VectorSlice,
1695 lifetime: PhantomData<&'a mut [T]>,
1696}
1697
1698// SAFETY: See `VecRef` but with `&mut [T]`.
1699//
1700// We have `&mut T: Sync` iff `T: Sync`
1701unsafe impl<T> Sync for VecMut<'_, T> where T: Sync {}
1702// We have `&mut T: Send` iff `T: Send`
1703unsafe impl<T> Send for VecMut<'_, T> where T: Sync {}
1704
1705impl<'data, T> VecMut<'data, T> {
1706 /// Create a new vector reference from a raw slice and pitch.
1707 ///
1708 /// The resulting block refers to the first column of the matrix.
1709 pub fn new(data: &'data mut [T], pitch: usize) -> Self {
1710 VecMut {
1711 // SAFETY: construction implies `count * pitch <= data.len()`.
1712 block: VectorSlice {
1713 count: data.len() / pitch,
1714 pitch,
1715 },
1716 data: NonNull::from(data).cast(),
1717 lifetime: PhantomData,
1718 }
1719 }
1720
1721 /// Create a new vector reference from a raw slice with pitch `1`.
1722 pub fn from_slice(data: &'data mut [T]) -> Self {
1723 VecMut {
1724 block: VectorSlice {
1725 count: data.len(),
1726 pitch: 1,
1727 },
1728 data: NonNull::from(data).cast(),
1729 lifetime: PhantomData,
1730 }
1731 }
1732
1733 /// Number of elements in this vector.
1734 pub fn len(&self) -> usize {
1735 self.block.count
1736 }
1737
1738 /// Whether this vector is empty.
1739 pub fn is_empty(&self) -> bool {
1740 self.block.count == 0
1741 }
1742
1743 /// Divide into two vectors at the given element.
1744 ///
1745 /// # Examples
1746 ///
1747 /// ```
1748 /// use matrix_slice::VecMut;
1749 ///
1750 /// let data = &mut [0, 1, 2, 3, 4, 5];
1751 ///
1752 /// let block = VecMut::new(data, 1);
1753 /// let (left, right) = block.split_at(2);
1754 ///
1755 /// assert_eq!(left[1], 1);
1756 /// assert_eq!(right[3], 5);
1757 /// ```
1758 pub fn split_at(self, mid: usize) -> (VecMut<'data, T>, VecMut<'data, T>) {
1759 self.split_at_checked(mid).unwrap()
1760 }
1761
1762 /// Divide into two vectors at the given element.
1763 ///
1764 /// See [`Self::split_at`] but returns `None` if out of bounds.
1765 pub fn split_at_checked(self, mid: usize) -> Option<(VecMut<'data, T>, VecMut<'data, T>)> {
1766 if let Some((lhs, rhs, offset)) = self.block.split_at(mid) {
1767 Some((
1768 VecMut {
1769 data: self.data,
1770 block: lhs,
1771 lifetime: self.lifetime,
1772 },
1773 VecMut {
1774 data: unsafe { self.data.add(offset) },
1775 block: rhs,
1776 lifetime: self.lifetime,
1777 },
1778 ))
1779 } else {
1780 None
1781 }
1782 }
1783
1784 /// Take part of the vector.
1785 ///
1786 /// # Examples
1787 ///
1788 /// ```
1789 /// use matrix_slice::VecMut;
1790 ///
1791 /// let data = &mut [0, 1, 2, 3, 4, 5];
1792 /// let mut vec = VecMut::new(data, 1);
1793 ///
1794 /// // Does nothing.
1795 /// assert!(vec.split_off(6..).is_some_and(|v| v.is_empty()));
1796 /// assert!(vec.split_off(7..).is_none());
1797 /// assert!(vec.split_off(..7).is_none());
1798 ///
1799 /// let mut right = vec.split_off(2..).unwrap();
1800 /// assert_eq!(vec.len(), 2);
1801 /// assert_eq!(right[3], 5);
1802 ///
1803 /// // The two halves are disjoint:
1804 /// right[0] = 0x42;
1805 /// assert_eq!(vec[1], 1);
1806 /// ```
1807 ///
1808 /// You can also split off the start:
1809 ///
1810 /// ```
1811 /// use matrix_slice::VecMut;
1812 ///
1813 /// let data = &mut [0, 1, 2, 3, 4, 5];
1814 /// let mut vec = VecMut::new(data, 1);
1815 /// let start = vec.split_off(..=2).unwrap();
1816 ///
1817 /// assert_eq!(vec[0], 3);
1818 /// assert_eq!(start[0], 0);
1819 /// ```
1820 pub fn split_off<R>(&mut self, range: R) -> Option<Self>
1821 where
1822 R: OneSidedMatrixIndex,
1823 {
1824 let (is_front, split_point) = range.into_split_point(self.block.count)?;
1825 let (left, right, offset) = self.block.split_at(split_point)?;
1826
1827 let ptr = self.data;
1828 let (ours, theirs) = if is_front {
1829 ((right, offset), (left, 0))
1830 } else {
1831 ((left, 0), (right, offset))
1832 };
1833
1834 self.block = ours.0;
1835 self.data = unsafe { ptr.add(ours.1) };
1836
1837 Some(VecMut {
1838 block: theirs.0,
1839 data: unsafe { ptr.add(theirs.1) },
1840 lifetime: self.lifetime,
1841 })
1842 }
1843
1844 /// Choose a range of elements and contract the vector to that.
1845 pub fn select<R>(self, range: R) -> Option<VecMut<'data, T>>
1846 where
1847 R: MatrixIndex,
1848 {
1849 let (start, len) = range.into_start_and_len(self.block.count)?;
1850 let (_, block, offset) = self.block.split_at(start)?;
1851 // Safety: ensures that the resulting block is more constrained, this property should be
1852 // ensured by our sealed `MatrixIndex` implementations.
1853 assert!(block.count >= len);
1854
1855 Some(VecMut {
1856 block: VectorSlice {
1857 count: len,
1858 ..block
1859 },
1860 // SAFETY: offset is in-bounds as per `split_at` contract.
1861 data: unsafe { self.data.add(offset) },
1862 lifetime: self.lifetime,
1863 })
1864 }
1865
1866 /// Turn this unique reference into a shared reference.
1867 pub fn cast_const(self) -> VecRef<'data, T> {
1868 // SAFETY: shared access can always be re-tagged from unique access.
1869 VecRef {
1870 data: self.data,
1871 block: self.block,
1872 lifetime: PhantomData,
1873 }
1874 }
1875
1876 /// Create a unique reference to this block with a shorter lifetime.
1877 pub fn reborrow(&mut self) -> VecMut<'_, T> {
1878 // SAFETY: Unique access is created by deriving it from our current pointer so the
1879 // provenance is the same, and temporally it can not overlap access through the current
1880 // value due to the lifetime enforcing a borrow relationship.
1881 VecMut {
1882 data: self.data,
1883 block: self.block,
1884 lifetime: PhantomData,
1885 }
1886 }
1887
1888 /// Modify the item type to a `Cell`, allowing interior mutability.
1889 ///
1890 /// This is the equivalent of [`Cell::from_mut`] over elements in this slice.
1891 pub fn as_cells(self) -> VecMut<'data, Cell<T>> {
1892 // SAFETY: `Cell<T>` has the same layout as `T`.
1893 VecMut {
1894 data: self.data.cast(),
1895 block: self.block,
1896 lifetime: PhantomData,
1897 }
1898 }
1899
1900 /// # Examples
1901 ///
1902 /// ```
1903 /// let data = &mut [
1904 /// [0, 1, 2],
1905 /// [3, 4, 5],
1906 /// [6, 7, 8],
1907 /// ];
1908 ///
1909 /// let mut block = matrix_slice::from_array_rows_mut(data);
1910 ///
1911 /// for item in block.reborrow().col(1) {
1912 /// *item *= 2;
1913 /// }
1914 ///
1915 /// assert!(block.col(1).iter().eq(&[2, 8, 14]));
1916 /// ```
1917 pub fn iter(self) -> IterVecMut<'data, T> {
1918 IterVecMut { vec: self }
1919 }
1920}
1921
1922impl<'data, T> VecMut<'data, Cell<T>> {
1923 /// Modify the item type from a `Cell` to its interior type.
1924 ///
1925 /// This is the equivalent of [`Cell::get_mut`] over elements in this slice.
1926 pub fn as_cell_items(self) -> VecMut<'data, T> {
1927 // SAFETY: `Cell<T>` has the same layout as `T`.
1928 VecMut {
1929 data: self.data.cast(),
1930 block: self.block,
1931 lifetime: PhantomData,
1932 }
1933 }
1934}
1935
1936impl<T> ops::Index<usize> for VecMut<'_, T> {
1937 type Output = T;
1938
1939 fn index(&self, index: usize) -> &Self::Output {
1940 let idx = self.block.in_bounds_offset(index);
1941 // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
1942 // provenance of the pointer.
1943 unsafe { &*self.data.as_ptr().add(idx) }
1944 }
1945}
1946
1947impl<T> ops::IndexMut<usize> for VecMut<'_, T> {
1948 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
1949 let idx = self.block.in_bounds_offset(index);
1950 // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
1951 // provenance of the pointer. By construction the `VecMut` has exclusive access to all
1952 // elements reachable as multiples of its pitch. We access exactly one of them here.
1953 unsafe { &mut *self.data.as_ptr().add(idx) }
1954 }
1955}
1956
1957/// Iterate over the rows of a block in a matrix.
1958///
1959/// We assume row-major matrices here, a row is a contiguous slice of items.
1960pub struct IterVec<'a, T> {
1961 // FIXME: see `std::slice::Iter` which stores the end pointer instead of the full
1962 // representation. That way we do not update two fields each time, i.e. iterating only updates
1963 // a pointer and not a pointer _and_ a `count` field in `block`.
1964 vec: VecRef<'a, T>,
1965}
1966
1967impl<'data, T> IntoIterator for VecRef<'data, T> {
1968 type Item = &'data T;
1969 type IntoIter = IterVec<'data, T>;
1970
1971 fn into_iter(self) -> Self::IntoIter {
1972 self.iter()
1973 }
1974}
1975
1976// FIXME: if budget allows it we should implement common inner-iteration methods such as
1977// `for_each`, `collect`, `all` by doing pointer arithmetic on a range iterator which avoids all
1978// writes to the value's tracking state itself.
1979impl<'data, T> Iterator for IterVec<'data, T> {
1980 type Item = &'data T;
1981
1982 fn next(&mut self) -> Option<Self::Item> {
1983 let base = self.vec.split_off(..1)?;
1984 Some(unsafe { &*base.data.as_ptr() })
1985 }
1986
1987 fn size_hint(&self) -> (usize, Option<usize>) {
1988 let remain = self.vec.len();
1989 (remain, Some(remain))
1990 }
1991
1992 fn count(self) -> usize {
1993 self.vec.len()
1994 }
1995}
1996
1997impl<'data, T> core::iter::FusedIterator for IterVec<'data, T> {}
1998
1999/// Iterate over mutable rows of a block in a matrix.
2000///
2001/// We assume row-major matrices here, a row is a contiguous slice of items.
2002pub struct IterVecMut<'a, T> {
2003 vec: VecMut<'a, T>,
2004}
2005
2006impl<'data, T> IntoIterator for VecMut<'data, T> {
2007 type Item = &'data mut T;
2008 type IntoIter = IterVecMut<'data, T>;
2009
2010 fn into_iter(self) -> Self::IntoIter {
2011 self.iter()
2012 }
2013}
2014
2015// FIXME: if budget allows it we should implement common inner-iteration methods such as
2016// `for_each`, `collect`, `all` by doing pointer arithmetic on a range iterator which avoids all
2017// writes to the value's tracking state itself.
2018impl<'data, T> Iterator for IterVecMut<'data, T> {
2019 type Item = &'data mut T;
2020
2021 fn next(&mut self) -> Option<Self::Item> {
2022 let base = self.vec.split_off(..1)?;
2023 Some(unsafe { &mut *base.data.as_ptr() })
2024 }
2025
2026 fn size_hint(&self) -> (usize, Option<usize>) {
2027 let remain = self.vec.len();
2028 (remain, Some(remain))
2029 }
2030
2031 fn count(self) -> usize {
2032 self.vec.len()
2033 }
2034}
2035
2036impl<'data, T> core::iter::FusedIterator for IterVecMut<'data, T> {}
2037
2038/// Tests should also be ran under MIRI.
2039#[cfg(test)]
2040mod tests {
2041 // Verify that splitting as in the example works.
2042 #[test]
2043 fn well_defined_split() {
2044 let data = &[[0u32; 3]; 3];
2045 let block = super::from_array_rows(data);
2046 let (_, block) = block.split_at_row(1);
2047 let (_, block) = block.split_at_col(1);
2048
2049 block.split_at_row_checked(2).unwrap();
2050 }
2051 #[test]
2052 fn well_defined_split_mut() {
2053 let data = &mut [[0u32; 3]; 3];
2054 let block = super::from_array_rows_mut(data);
2055 let (_, block) = block.split_at_row(1);
2056 let (_, block) = block.split_at_col(1);
2057
2058 block.split_at_row_checked(2).unwrap();
2059 }
2060
2061 /// Check our pointer derivation does not cause retagging that would cause any block to lose
2062 /// provenance over its items. Access individual rows (derived slices) from an overlapping split
2063 /// concurrently.
2064 #[test]
2065 fn soundness_interleaved_block_access() {
2066 let data = &mut [[0u32; 4]; 4];
2067 let block = super::from_array_rows_mut(data);
2068
2069 let (mut lhs, rhs) = block.split_at_col(2);
2070
2071 for (left, right) in lhs.reborrow().iter_rows_mut().zip(rhs.iter_rows_mut()) {
2072 left[0] = right[0];
2073 left[1] = right[1];
2074 right.fill(1);
2075 }
2076
2077 // Check that this pointer is still valid.
2078 for row in lhs.iter_rows_mut() {
2079 row.fill(2);
2080 }
2081
2082 for row in data.iter() {
2083 assert_eq!(row, &[2, 2, 1, 1]);
2084 }
2085 }
2086}