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 // We need to make sure that this is in-bounds of the allocation. Note that the provenance
1111 // stretches only past our last element, not an additional pitch past it. So we can use the
1112 // simple formula only if there are elements covered by the right part of the split.
1113 // Fortunately the opposite of this implies that the right does not cover any elements and
1114 // we can thus use any inbounds pointer; like the zero offset.
1115 let offset = if right_count == 0 {
1116 0
1117 } else {
1118 mid * self.pitch
1119 };
1120
1121 Some((left, right, offset))
1122 }
1123
1124 /// Return the absolute position of the element, if in bounds. Otherwise, panic.
1125 fn in_bounds_offset(&self, index: usize) -> usize {
1126 assert!(index < self.count);
1127 index * self.pitch
1128 }
1129}
1130
1131/// Iterate over the rows of a block in a matrix.
1132///
1133/// We assume row-major matrices here, a row is a contiguous slice of items.
1134pub struct IterRows<'a, T> {
1135 block: BlockRef<'a, T>,
1136}
1137
1138impl<'data, T> Iterator for IterRows<'data, T> {
1139 type Item = &'data [T];
1140
1141 fn next(&mut self) -> Option<Self::Item> {
1142 if self.block.rows() == 0 {
1143 None
1144 } else {
1145 // FIXME: add `split_off_rows` instead.
1146 let (row, rest) = core::mem::take(&mut self.block).split_at_row(1);
1147 self.block = rest;
1148 // One row as it was created from `split_at_row(1)`.
1149 Some(row.fake_contiguity())
1150 }
1151 }
1152}
1153
1154/// Iterate over mutable rows of a block in a matrix.
1155///
1156/// We assume row-major matrices here, a row is a contiguous slice of items.
1157pub struct IterRowsMut<'a, T> {
1158 block: BlockMut<'a, T>,
1159}
1160
1161impl<'data, T> Iterator for IterRowsMut<'data, T> {
1162 type Item = &'data mut [T];
1163
1164 fn next(&mut self) -> Option<Self::Item> {
1165 if self.block.rows() == 0 {
1166 None
1167 } else {
1168 // FIXME: add `split_off_rows` instead.
1169 let (row, rest) = core::mem::take(&mut self.block).split_at_row(1);
1170 self.block = rest;
1171 // One row as it was created from `split_at_row(1)`.
1172 Some(row.fake_contiguity())
1173 }
1174 }
1175}
1176
1177pub trait MatrixIndex: sealed::Sealed {}
1178
1179impl MatrixIndex for ops::Range<usize> {}
1180impl MatrixIndex for ops::RangeInclusive<usize> {}
1181impl MatrixIndex for ops::RangeFrom<usize> {}
1182impl MatrixIndex for ops::RangeTo<usize> {}
1183impl MatrixIndex for ops::RangeToInclusive<usize> {}
1184impl MatrixIndex for ops::RangeFull {}
1185
1186pub trait OneSidedMatrixIndex: sealed::SealedOneSided {}
1187
1188impl OneSidedMatrixIndex for ops::RangeFrom<usize> {}
1189impl OneSidedMatrixIndex for ops::RangeTo<usize> {}
1190impl OneSidedMatrixIndex for ops::RangeToInclusive<usize> {}
1191
1192mod sealed {
1193 use core::ops;
1194
1195 pub trait Sealed {
1196 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)>;
1197 }
1198
1199 pub trait SealedOneSided {
1200 fn into_split_point(self, dim: usize) -> Option<(bool, usize)>;
1201 }
1202
1203 impl Sealed for ops::Range<usize> {
1204 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1205 if self.start <= self.end && self.end <= dim {
1206 Some((self.start, self.end - self.start))
1207 } else {
1208 None
1209 }
1210 }
1211 }
1212
1213 impl Sealed for ops::RangeInclusive<usize> {
1214 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1215 let start = *self.start();
1216 let end = *self.end();
1217 if start <= end && end < dim {
1218 Some((start, end - start + 1))
1219 } else {
1220 None
1221 }
1222 }
1223 }
1224
1225 impl Sealed for ops::RangeFrom<usize> {
1226 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1227 if self.start <= dim {
1228 Some((self.start, dim - self.start))
1229 } else {
1230 None
1231 }
1232 }
1233 }
1234
1235 impl Sealed for ops::RangeTo<usize> {
1236 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1237 if self.end <= dim {
1238 Some((0, self.end))
1239 } else {
1240 None
1241 }
1242 }
1243 }
1244
1245 impl Sealed for ops::RangeToInclusive<usize> {
1246 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1247 if self.end < dim {
1248 Some((0, self.end + 1))
1249 } else {
1250 None
1251 }
1252 }
1253 }
1254
1255 impl Sealed for ops::RangeFull {
1256 fn into_start_and_len(self, dim: usize) -> Option<(usize, usize)> {
1257 Some((0, dim))
1258 }
1259 }
1260
1261 impl SealedOneSided for ops::RangeFrom<usize> {
1262 fn into_split_point(self, dim: usize) -> Option<(bool, usize)> {
1263 if self.start <= dim {
1264 Some((false, self.start))
1265 } else {
1266 None
1267 }
1268 }
1269 }
1270
1271 impl SealedOneSided for ops::RangeTo<usize> {
1272 fn into_split_point(self, dim: usize) -> Option<(bool, usize)> {
1273 if self.end <= dim {
1274 Some((true, self.end))
1275 } else {
1276 None
1277 }
1278 }
1279 }
1280
1281 impl SealedOneSided for ops::RangeToInclusive<usize> {
1282 fn into_split_point(self, dim: usize) -> Option<(bool, usize)> {
1283 if self.end < dim {
1284 Some((true, self.end + 1))
1285 } else {
1286 None
1287 }
1288 }
1289 }
1290}
1291
1292/// A reference to a single column/row of a matrix.
1293///
1294/// This is similar to `&[T]` but with a pitch potentially different from `1` between its elements,
1295/// i.e. there is no guarantee of contiguity. As a consequence this does not have a simple
1296/// past-the-end pointer like a slice would have. For an empty slice the only guaranteed-valid
1297/// pointer is the base pointer itself while for larger slices the last guaranteed-valid pointer is
1298/// one-past the last element, _not_ one additional pitch.
1299///
1300/// Created from its constructors or a block reference via the [`BlockRef::col`] and
1301/// [`BlockRef::row`] methods.
1302#[derive(Copy, Clone)]
1303pub struct VecRef<'a, T> {
1304 data: NonNull<T>,
1305 block: VectorSlice,
1306 lifetime: PhantomData<&'a [T]>,
1307}
1308
1309// SAFETY: See `&[T]`. The reference can be used to, potentially, get a `&T` for each element in
1310// the block and thus the block itself provides the exact same properties as `T`. The `VecRef` is
1311// then `&[T]` itself and thus has properties of a reference to such a type. Refer to the
1312// reference: <https://doc.rust-lang.org/stable/std/primitive.reference.html>
1313//
1314// We have `&T: Sync` iff `T: Sync`
1315unsafe impl<T> Sync for VecRef<'_, T> where T: Sync {}
1316// We have `&T: Send` iff `T: Sync`
1317unsafe impl<T> Send for VecRef<'_, T> where T: Sync {}
1318
1319impl<'data, T> VecRef<'data, T> {
1320 /// Create a new vector reference from a raw slice and pitch.
1321 ///
1322 /// The resulting block refers to the first column of the matrix.
1323 ///
1324 /// # Panics
1325 ///
1326 /// Panics if the pitch is zero.
1327 pub fn new(data: &'data [T], pitch: usize) -> Self {
1328 assert_ne!(pitch, 0);
1329
1330 VecRef {
1331 // Safety: construction implies `count * pitch <= data.len()`.
1332 block: VectorSlice {
1333 count: data.len() / pitch,
1334 pitch,
1335 },
1336 data: NonNull::from(data).cast(),
1337 lifetime: PhantomData,
1338 }
1339 }
1340
1341 /// Create a new vector reference from a raw slice with pitch `1`.
1342 pub fn from_slice(data: &'data [T]) -> Self {
1343 VecRef {
1344 block: VectorSlice {
1345 count: data.len(),
1346 pitch: 1,
1347 },
1348 data: NonNull::from(data).cast(),
1349 lifetime: PhantomData,
1350 }
1351 }
1352
1353 /// Number of elements in this vector.
1354 pub fn len(&self) -> usize {
1355 self.block.count
1356 }
1357
1358 /// Whether this vector is empty.
1359 pub fn is_empty(&self) -> bool {
1360 self.block.count == 0
1361 }
1362
1363 /// Divide into two vectors at the given element.
1364 ///
1365 /// # Examples
1366 ///
1367 /// ```
1368 /// use matrix_slice::VecRef;
1369 ///
1370 /// let data = &[0, 1, 2, 3, 4, 5];
1371 ///
1372 /// let block = VecRef::new(data, 1);
1373 /// let (left, right) = block.split_at(2);
1374 ///
1375 /// assert_eq!(left[1], 1);
1376 /// assert_eq!(right[3], 5);
1377 /// ```
1378 pub fn split_at(self, mid: usize) -> (VecRef<'data, T>, VecRef<'data, T>) {
1379 self.split_at_checked(mid).unwrap()
1380 }
1381
1382 /// Divide into two vectors at the given element.
1383 ///
1384 /// See [`Self::split_at`] but returns `None` if out of bounds.
1385 pub fn split_at_checked(mut self, mid: usize) -> Option<(VecRef<'data, T>, VecRef<'data, T>)> {
1386 // Let's assume this will collapse during const-prop after the type here is inserted.
1387 let tail = self.split_off(mid..)?;
1388 Some((self, tail))
1389 }
1390
1391 /// Take part of the vector.
1392 ///
1393 /// # Examples
1394 ///
1395 /// ```
1396 /// use matrix_slice::VecRef;
1397 ///
1398 /// let data = &[0, 1, 2, 3, 4, 5];
1399 /// let mut vec = VecRef::new(data, 1);
1400 ///
1401 /// // Does nothing.
1402 /// assert!(vec.split_off(6..).is_some_and(|v| v.is_empty()));
1403 /// assert!(vec.split_off(7..).is_none());
1404 /// assert!(vec.split_off(..7).is_none());
1405 ///
1406 /// let right = vec.split_off(2..).unwrap();
1407 /// assert_eq!(vec.len(), 2);
1408 /// assert_eq!(right[3], 5);
1409 /// ```
1410 ///
1411 /// You can also split off the start:
1412 ///
1413 /// ```
1414 /// use matrix_slice::VecRef;
1415 ///
1416 /// let data = &[0, 1, 2, 3, 4, 5];
1417 /// let mut vec = VecRef::new(data, 1);
1418 /// let start = vec.split_off(..=2).unwrap();
1419 ///
1420 /// assert_eq!(vec[0], 3);
1421 /// assert_eq!(start[0], 0);
1422 /// ```
1423 pub fn split_off<R>(&mut self, range: R) -> Option<Self>
1424 where
1425 R: OneSidedMatrixIndex,
1426 {
1427 let (is_front, split_point) = range.into_split_point(self.block.count)?;
1428 let (left, right, offset) = self.block.split_at(split_point)?;
1429
1430 let ptr = self.data;
1431 let (ours, theirs) = if is_front {
1432 ((right, offset), (left, 0))
1433 } else {
1434 ((left, 0), (right, offset))
1435 };
1436
1437 self.block = ours.0;
1438 self.data = unsafe { ptr.add(ours.1) };
1439
1440 Some(VecRef {
1441 block: theirs.0,
1442 data: unsafe { ptr.add(theirs.1) },
1443 lifetime: self.lifetime,
1444 })
1445 }
1446
1447 /// Choose a range of elements and contract the vector to that.
1448 pub fn select<R>(self, range: R) -> Option<VecRef<'data, T>>
1449 where
1450 R: MatrixIndex,
1451 {
1452 let (start, len) = range.into_start_and_len(self.block.count)?;
1453 let (_, block, offset) = self.block.split_at(start)?;
1454 // Safety: ensures that the resulting block is more constrained, this property should be
1455 // ensured by our sealed `MatrixIndex` implementations.
1456 assert!(block.count >= len);
1457
1458 Some(VecRef {
1459 block: VectorSlice {
1460 count: len,
1461 ..block
1462 },
1463 // SAFETY: offset is in-bounds as per `split_at` contract.
1464 data: unsafe { self.data.add(offset) },
1465 lifetime: self.lifetime,
1466 })
1467 }
1468
1469 /// # Examples
1470 ///
1471 /// ```
1472 /// let data = &[
1473 /// [0, 1, 2],
1474 /// [3, 4, 5],
1475 /// [6, 7, 8],
1476 /// ];
1477 ///
1478 /// let block = matrix_slice::from_array_rows(data);
1479 /// let column = block.col(1);
1480 ///
1481 /// assert!(column.iter().eq(&[1, 4, 7]));
1482 /// ```
1483 pub fn iter(self) -> IterVec<'data, T> {
1484 IterVec { vec: self }
1485 }
1486}
1487
1488impl<T> ops::Index<usize> for VecRef<'_, T> {
1489 type Output = T;
1490
1491 fn index(&self, index: usize) -> &Self::Output {
1492 let idx = self.block.in_bounds_offset(index);
1493 // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
1494 // provenance of the pointer.
1495 unsafe { &*self.data.as_ptr().add(idx) }
1496 }
1497}
1498
1499/// A reference to a single column/row of a matrix.
1500///
1501/// This is similar to `&[T]` but with a pitch potentially different from `1` between its elements,
1502/// i.e. there is no guarantee of contiguity. As a consequence this does not have a simple
1503/// past-the-end pointer like a slice would have. For an empty slice the only guaranteed-valid
1504/// pointer is the base pointer itself while for larger slices the last guaranteed-valid pointer is
1505/// one-past the last element, _not_ one additional pitch.
1506///
1507/// Created from its constructors or a block reference via the [`BlockMut::col`] and
1508/// [`BlockMut::row`] methods.
1509pub struct VecMut<'a, T> {
1510 data: NonNull<T>,
1511 block: VectorSlice,
1512 lifetime: PhantomData<&'a mut [T]>,
1513}
1514
1515// SAFETY: See `VecRef` but with `&mut [T]`.
1516//
1517// We have `&mut T: Sync` iff `T: Sync`
1518unsafe impl<T> Sync for VecMut<'_, T> where T: Sync {}
1519// We have `&mut T: Send` iff `T: Send`
1520unsafe impl<T> Send for VecMut<'_, T> where T: Sync {}
1521
1522impl<'data, T> VecMut<'data, T> {
1523 /// Create a new vector reference from a raw slice and pitch.
1524 ///
1525 /// The resulting block refers to the first column of the matrix.
1526 pub fn new(data: &'data mut [T], pitch: usize) -> Self {
1527 VecMut {
1528 // Safety: construction implies `count * pitch <= data.len()`.
1529 block: VectorSlice {
1530 count: data.len() / pitch,
1531 pitch,
1532 },
1533 data: NonNull::from(data).cast(),
1534 lifetime: PhantomData,
1535 }
1536 }
1537
1538 /// Create a new vector reference from a raw slice with pitch `1`.
1539 pub fn from_slice(data: &'data mut [T]) -> Self {
1540 VecMut {
1541 block: VectorSlice {
1542 count: data.len(),
1543 pitch: 1,
1544 },
1545 data: NonNull::from(data).cast(),
1546 lifetime: PhantomData,
1547 }
1548 }
1549
1550 /// Number of elements in this vector.
1551 pub fn len(&self) -> usize {
1552 self.block.count
1553 }
1554
1555 /// Whether this vector is empty.
1556 pub fn is_empty(&self) -> bool {
1557 self.block.count == 0
1558 }
1559
1560 /// Divide into two vectors at the given element.
1561 ///
1562 /// # Examples
1563 ///
1564 /// ```
1565 /// use matrix_slice::VecMut;
1566 ///
1567 /// let data = &mut [0, 1, 2, 3, 4, 5];
1568 ///
1569 /// let block = VecMut::new(data, 1);
1570 /// let (left, right) = block.split_at(2);
1571 ///
1572 /// assert_eq!(left[1], 1);
1573 /// assert_eq!(right[3], 5);
1574 /// ```
1575 pub fn split_at(self, mid: usize) -> (VecMut<'data, T>, VecMut<'data, T>) {
1576 self.split_at_checked(mid).unwrap()
1577 }
1578
1579 /// Divide into two vectors at the given element.
1580 ///
1581 /// See [`Self::split_at`] but returns `None` if out of bounds.
1582 pub fn split_at_checked(self, mid: usize) -> Option<(VecMut<'data, T>, VecMut<'data, T>)> {
1583 if let Some((lhs, rhs, offset)) = self.block.split_at(mid) {
1584 Some((
1585 VecMut {
1586 data: self.data,
1587 block: lhs,
1588 lifetime: self.lifetime,
1589 },
1590 VecMut {
1591 data: unsafe { self.data.add(offset) },
1592 block: rhs,
1593 lifetime: self.lifetime,
1594 },
1595 ))
1596 } else {
1597 None
1598 }
1599 }
1600
1601 /// Take part of the vector.
1602 ///
1603 /// # Examples
1604 ///
1605 /// ```
1606 /// use matrix_slice::VecMut;
1607 ///
1608 /// let data = &mut [0, 1, 2, 3, 4, 5];
1609 /// let mut vec = VecMut::new(data, 1);
1610 ///
1611 /// // Does nothing.
1612 /// assert!(vec.split_off(6..).is_some_and(|v| v.is_empty()));
1613 /// assert!(vec.split_off(7..).is_none());
1614 /// assert!(vec.split_off(..7).is_none());
1615 ///
1616 /// let mut right = vec.split_off(2..).unwrap();
1617 /// assert_eq!(vec.len(), 2);
1618 /// assert_eq!(right[3], 5);
1619 ///
1620 /// // The two halves are disjoint:
1621 /// right[0] = 0x42;
1622 /// assert_eq!(vec[1], 1);
1623 /// ```
1624 ///
1625 /// You can also split off the start:
1626 ///
1627 /// ```
1628 /// use matrix_slice::VecMut;
1629 ///
1630 /// let data = &mut [0, 1, 2, 3, 4, 5];
1631 /// let mut vec = VecMut::new(data, 1);
1632 /// let start = vec.split_off(..=2).unwrap();
1633 ///
1634 /// assert_eq!(vec[0], 3);
1635 /// assert_eq!(start[0], 0);
1636 /// ```
1637 pub fn split_off<R>(&mut self, range: R) -> Option<Self>
1638 where
1639 R: OneSidedMatrixIndex,
1640 {
1641 let (is_front, split_point) = range.into_split_point(self.block.count)?;
1642 let (left, right, offset) = self.block.split_at(split_point)?;
1643
1644 let ptr = self.data;
1645 let (ours, theirs) = if is_front {
1646 ((right, offset), (left, 0))
1647 } else {
1648 ((left, 0), (right, offset))
1649 };
1650
1651 self.block = ours.0;
1652 self.data = unsafe { ptr.add(ours.1) };
1653
1654 Some(VecMut {
1655 block: theirs.0,
1656 data: unsafe { ptr.add(theirs.1) },
1657 lifetime: self.lifetime,
1658 })
1659 }
1660
1661 /// Choose a range of elements and contract the vector to that.
1662 pub fn select<R>(self, range: R) -> Option<VecMut<'data, T>>
1663 where
1664 R: MatrixIndex,
1665 {
1666 let (start, len) = range.into_start_and_len(self.block.count)?;
1667 let (_, block, offset) = self.block.split_at(start)?;
1668 // Safety: ensures that the resulting block is more constrained, this property should be
1669 // ensured by our sealed `MatrixIndex` implementations.
1670 assert!(block.count >= len);
1671
1672 Some(VecMut {
1673 block: VectorSlice {
1674 count: len,
1675 ..block
1676 },
1677 // SAFETY: offset is in-bounds as per `split_at` contract.
1678 data: unsafe { self.data.add(offset) },
1679 lifetime: self.lifetime,
1680 })
1681 }
1682
1683 /// Turn this unique reference into a shared reference.
1684 pub fn cast_const(self) -> VecRef<'data, T> {
1685 // SAFETY: shared access can always be re-tagged from unique access.
1686 VecRef {
1687 data: self.data,
1688 block: self.block,
1689 lifetime: PhantomData,
1690 }
1691 }
1692
1693 /// Create a unique reference to this block with a shorter lifetime.
1694 pub fn reborrow(&mut self) -> VecMut<'_, T> {
1695 // SAFETY: Unique access is created by deriving it from our current pointer so the
1696 // provenance is the same, and temporally it can not overlap access through the current
1697 // value due to the lifetime enforcing a borrow relationship.
1698 VecMut {
1699 data: self.data,
1700 block: self.block,
1701 lifetime: PhantomData,
1702 }
1703 }
1704
1705 /// Modify the item type to a `Cell`, allowing interior mutability.
1706 ///
1707 /// This is the equivalent of [`Cell::from_mut`] over elements in this slice.
1708 pub fn as_cells(self) -> VecMut<'data, Cell<T>> {
1709 // SAFETY: `Cell<T>` has the same layout as `T`.
1710 VecMut {
1711 data: self.data.cast(),
1712 block: self.block,
1713 lifetime: PhantomData,
1714 }
1715 }
1716
1717 /// # Examples
1718 ///
1719 /// ```
1720 /// let data = &mut [
1721 /// [0, 1, 2],
1722 /// [3, 4, 5],
1723 /// [6, 7, 8],
1724 /// ];
1725 ///
1726 /// let mut block = matrix_slice::from_array_rows_mut(data);
1727 ///
1728 /// for item in block.reborrow().col(1) {
1729 /// *item *= 2;
1730 /// }
1731 ///
1732 /// assert!(block.col(1).iter().eq(&[2, 8, 14]));
1733 /// ```
1734 pub fn iter(self) -> IterVecMut<'data, T> {
1735 IterVecMut { vec: self }
1736 }
1737}
1738
1739impl<'data, T> VecMut<'data, Cell<T>> {
1740 /// Modify the item type from a `Cell` to its interior type.
1741 ///
1742 /// This is the equivalent of [`Cell::get_mut`] over elements in this slice.
1743 pub fn as_cell_items(self) -> VecMut<'data, T> {
1744 // SAFETY: `Cell<T>` has the same layout as `T`.
1745 VecMut {
1746 data: self.data.cast(),
1747 block: self.block,
1748 lifetime: PhantomData,
1749 }
1750 }
1751}
1752
1753impl<T> ops::Index<usize> for VecMut<'_, T> {
1754 type Output = T;
1755
1756 fn index(&self, index: usize) -> &Self::Output {
1757 let idx = self.block.in_bounds_offset(index);
1758 // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
1759 // provenance of the pointer.
1760 unsafe { &*self.data.as_ptr().add(idx) }
1761 }
1762}
1763
1764impl<T> ops::IndexMut<usize> for VecMut<'_, T> {
1765 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
1766 let idx = self.block.in_bounds_offset(index);
1767 // SAFETY: Index is bounded by `total_span` which itself is a lower estimate of the
1768 // provenance of the pointer. By construction the `VecMut` has exclusive access to all
1769 // elements reachable as multiples of its pitch. We access exactly one of them here.
1770 unsafe { &mut *self.data.as_ptr().add(idx) }
1771 }
1772}
1773
1774/// Iterate over the rows of a block in a matrix.
1775///
1776/// We assume row-major matrices here, a row is a contiguous slice of items.
1777pub struct IterVec<'a, T> {
1778 // FIXME: see `std::slice::Iter` which stores the end pointer instead of the full
1779 // representation. That way we do not update two fields each time, i.e. iterating only updates
1780 // a pointer and not a pointer _and_ a `count` field in `block`.
1781 vec: VecRef<'a, T>,
1782}
1783
1784impl<'data, T> IntoIterator for VecRef<'data, T> {
1785 type Item = &'data T;
1786 type IntoIter = IterVec<'data, T>;
1787
1788 fn into_iter(self) -> Self::IntoIter {
1789 self.iter()
1790 }
1791}
1792
1793// FIXME: if budget allows it we should implement common inner-iteration methods such as
1794// `for_each`, `collect`, `all` by doing pointer arithmetic on a range iterator which avoids all
1795// writes to the value's tracking state itself.
1796impl<'data, T> Iterator for IterVec<'data, T> {
1797 type Item = &'data T;
1798
1799 fn next(&mut self) -> Option<Self::Item> {
1800 let base = self.vec.split_off(..1)?;
1801 Some(unsafe { &*base.data.as_ptr() })
1802 }
1803
1804 fn size_hint(&self) -> (usize, Option<usize>) {
1805 let remain = self.vec.len();
1806 (remain, Some(remain))
1807 }
1808
1809 fn count(self) -> usize {
1810 self.vec.len()
1811 }
1812}
1813
1814impl<'data, T> core::iter::FusedIterator for IterVec<'data, T> {}
1815
1816/// Iterate over mutable rows of a block in a matrix.
1817///
1818/// We assume row-major matrices here, a row is a contiguous slice of items.
1819pub struct IterVecMut<'a, T> {
1820 vec: VecMut<'a, T>,
1821}
1822
1823impl<'data, T> IntoIterator for VecMut<'data, T> {
1824 type Item = &'data mut T;
1825 type IntoIter = IterVecMut<'data, T>;
1826
1827 fn into_iter(self) -> Self::IntoIter {
1828 self.iter()
1829 }
1830}
1831
1832// FIXME: if budget allows it we should implement common inner-iteration methods such as
1833// `for_each`, `collect`, `all` by doing pointer arithmetic on a range iterator which avoids all
1834// writes to the value's tracking state itself.
1835impl<'data, T> Iterator for IterVecMut<'data, T> {
1836 type Item = &'data mut T;
1837
1838 fn next(&mut self) -> Option<Self::Item> {
1839 let base = self.vec.split_off(..1)?;
1840 Some(unsafe { &mut *base.data.as_ptr() })
1841 }
1842
1843 fn size_hint(&self) -> (usize, Option<usize>) {
1844 let remain = self.vec.len();
1845 (remain, Some(remain))
1846 }
1847
1848 fn count(self) -> usize {
1849 self.vec.len()
1850 }
1851}
1852
1853impl<'data, T> core::iter::FusedIterator for IterVecMut<'data, T> {}
1854
1855/// Tests should also be ran under MIRI.
1856#[cfg(test)]
1857mod tests {
1858 // Verify that splitting as in the example works.
1859 #[test]
1860 fn well_defined_split() {
1861 let data = &[[0u32; 3]; 3];
1862 let block = super::from_array_rows(data);
1863 let (_, block) = block.split_at_row(1);
1864 let (_, block) = block.split_at_col(1);
1865
1866 block.split_at_row_checked(2).unwrap();
1867 }
1868 #[test]
1869 fn well_defined_split_mut() {
1870 let data = &mut [[0u32; 3]; 3];
1871 let block = super::from_array_rows_mut(data);
1872 let (_, block) = block.split_at_row(1);
1873 let (_, block) = block.split_at_col(1);
1874
1875 block.split_at_row_checked(2).unwrap();
1876 }
1877
1878 /// Check our pointer derivation does not cause retagging that would cause any block to lose
1879 /// provenance over its items. Access individual rows (derived slices) from an overlapping split
1880 /// concurrently.
1881 #[test]
1882 fn soundness_interleaved_block_access() {
1883 let data = &mut [[0u32; 4]; 4];
1884 let block = super::from_array_rows_mut(data);
1885
1886 let (mut lhs, rhs) = block.split_at_col(2);
1887
1888 for (left, right) in lhs.reborrow().iter_rows_mut().zip(rhs.iter_rows_mut()) {
1889 left[0] = right[0];
1890 left[1] = right[1];
1891 right.fill(1);
1892 }
1893
1894 // Check that this pointer is still valid.
1895 for row in lhs.iter_rows_mut() {
1896 row.fill(2);
1897 }
1898
1899 for row in data.iter() {
1900 assert_eq!(row, &[2, 2, 1, 1]);
1901 }
1902 }
1903}