Skip to main content

diskann_utils/views/
rowmajor.rs

1/*
2 * Copyright (c) Microsoft Corporation.
3 * Licensed under the MIT license.
4 */
5
6use std::{marker::PhantomData, mem::ManuallyDrop, num::NonZeroUsize, ptr::NonNull};
7
8#[cfg(feature = "rayon")]
9use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
10use thiserror::Error;
11
12pub mod iter;
13
14use crate::{internal, Reborrow, ReborrowMut};
15
16////////////
17// Matrix //
18////////////
19
20/// Tools for treating contiguous regions of memory as a dense, row-major matrix.
21///
22/// See also: [`MatrixMut`], [`Owned`], [`Ref`], [`Mut`].
23///
24/// # Safety
25///
26/// For any shared reference `matrix: &Self`, the following must hold for the entire lifetime
27/// of that reference:
28///
29/// * Every call to `matrix.as_nonnull()` returns the same pointer.
30///
31/// * Every call to `matrix.layout()` returns the same layout.
32///
33/// * The pointer and layout describe the same valid initialized span throughout that lifetime.
34///   Given:
35///
36///   ```text
37///   let data = matrix.as_nonnull();
38///   let layout = matrix.layout();
39///   ```
40///
41///   constructing the following slice is valid:
42///
43///   ```text
44///   unsafe { std::slice::from_raw_parts(data.as_ptr().cast_const(), layout.num_elements()) };
45///   ```
46///
47///   In particular:
48///
49///   - `data` must be properly aligned, including when `layout.num_elements() == 0`.
50///
51///   - If both `layout.num_elements()` and `size_of::<Self::Element>()` are nonzero, the
52///     described span must lie within a single allocation.
53///
54///   - The span must contain `layout.num_elements()` consecutive, properly initialized
55///     values of type `Self::Element`.
56///
57///   - The referenced memory must not be mutated for the lifetime of `matrix`, except
58///     through an `UnsafeCell`.
59pub unsafe trait Matrix {
60    /// The type of the element stored in the matrix.
61    type Element;
62
63    /// Return the base pointer for the matrix.
64    fn as_nonnull(&self) -> NonNull<Self::Element>;
65
66    /// Return the [`Layout`] for the matrix.
67    fn layout(&self) -> Layout<Self::Element>;
68
69    //----------//
70    // Provided //
71    //----------//
72
73    /// Return the number of rows in the matrix.
74    fn nrows(&self) -> usize {
75        self.layout().nrows()
76    }
77
78    /// Return the number of columns in the matrix.
79    fn ncols(&self) -> usize {
80        self.layout().ncols()
81    }
82
83    /// Returns the requested row without bounds checking.
84    ///
85    /// # Safety
86    ///
87    /// The following conditions must hold to avoid undefined behavior:
88    ///
89    /// * `row < self.nrows()`.
90    unsafe fn row_unchecked(&self, row: usize) -> &[Self::Element] {
91        let layout = self.layout();
92        debug_assert!(row < layout.nrows());
93
94        // SAFETY: The caller guarantees that `row` is in-bounds. The validated layout
95        // therefore places this row entirely within the initialized span required by the
96        // `Matrix` invariant. The returned lifetime is tied to the borrow of `self`.
97        unsafe {
98            std::slice::from_raw_parts(self.as_ptr().add(layout.ncols() * row), layout.ncols())
99        }
100    }
101
102    /// Return a pointer to the base of the matrix.
103    fn as_ptr(&self) -> *const Self::Element {
104        self.as_nonnull().as_ptr().cast_const()
105    }
106
107    /// Return the underlying data as a slice.
108    fn as_slice(&self) -> &[Self::Element] {
109        // SAFETY: The `Matrix` invariant requires this pointer and length to describe a
110        // properly aligned, initialized span that remains immutable for this borrow.
111        unsafe { std::slice::from_raw_parts(self.as_ptr(), self.layout().num_elements()) }
112    }
113
114    /// Return row `row` as a slice.
115    ///
116    /// # Panic
117    ///
118    /// Panics if `row >= self.nrows()`.
119    fn row(&self, row: usize) -> &[Self::Element] {
120        assert!(
121            row < self.nrows(),
122            "tried to access row {row} of a matrix with {} rows",
123            self.nrows()
124        );
125
126        // SAFETY: `row` is in-bounds.
127        unsafe { self.row_unchecked(row) }
128    }
129
130    /// Return row `row` if `row < self.nrows()`. Otherwise, return `None`.
131    fn get_row(&self, row: usize) -> Option<&[Self::Element]> {
132        if row < self.nrows() {
133            // SAFETY: `row` is in-bounds.
134            Some(unsafe { self.row_unchecked(row) })
135        } else {
136            None
137        }
138    }
139
140    /// Return a iterator over all rows in the matrix.
141    ///
142    /// Rows are yielded sequentially beginning with row 0.
143    fn rows(&self) -> iter::Rows<'_, Self::Element> {
144        iter::Rows::new(self.as_view())
145    }
146
147    /// Returns a reference to an element without bounds checking.
148    ///
149    /// # Safety
150    ///
151    /// The following conditions must hold to avoid undefined behavior:
152    /// * `row < self.nrows()`.
153    /// * `col < self.ncols()`.
154    unsafe fn element_unchecked(&self, row: usize, col: usize) -> &Self::Element {
155        let layout = self.layout();
156        debug_assert!(row < layout.nrows());
157        debug_assert!(col < layout.ncols());
158
159        // SAFETY: The caller guarantees that both indices are in-bounds, so the validated
160        // layout places this element within the initialized span required by the `Matrix`
161        // invariant. The returned lifetime is tied to the borrow of `self`.
162        unsafe { &*self.as_ptr().add(row * layout.ncols() + col) }
163    }
164
165    /// Return the value at the specified `row` and `col`.
166    ///
167    /// If either index is out-of-bounds, return `None`.
168    fn get_element(&self, row: usize, col: usize) -> Option<&Self::Element> {
169        if row >= self.nrows() || col >= self.ncols() {
170            None
171        } else {
172            // SAFETY: We just verified that `row` and `col` are in-bounds.
173            Some(unsafe { self.element_unchecked(row, col) })
174        }
175    }
176
177    /// Return the value at the specified `row` and `col`.
178    ///
179    /// # Panics
180    ///
181    /// Panics if either `row` or `col` is out-of-bounds.
182    fn element(&self, row: usize, col: usize) -> &Self::Element {
183        assert!(
184            row < self.nrows(),
185            "row {row} is out of bounds (max: {})",
186            self.nrows()
187        );
188        assert!(
189            col < self.ncols(),
190            "col {col} is out of bounds (max: {})",
191            self.ncols()
192        );
193
194        // SAFETY: We just verified that `row` and `col` are in-bounds.
195        unsafe { self.element_unchecked(row, col) }
196    }
197
198    /// Return a view over the matrix.
199    fn as_view(&self) -> Ref<'_, Self::Element> {
200        Ref {
201            ptr: self.as_nonnull(),
202            layout: self.layout(),
203            _lifetime: PhantomData,
204        }
205    }
206
207    /// Return a view over the rows in `rows`, or `None` when the range is invalid.
208    fn subview(&self, rows: std::ops::Range<usize>) -> Option<Ref<'_, Self::Element>> {
209        if rows.start > rows.end || rows.end > self.nrows() {
210            return None;
211        }
212
213        let ncols = self.ncols();
214        // SAFETY: `rows.start <= self.nrows()`, so the validated parent layout makes the
215        // offset representable and places it within or one past the matrix span. Pointer
216        // arithmetic within that span preserves non-nullness.
217        let ptr =
218            unsafe { NonNull::new_unchecked(self.as_ptr().add(rows.start * ncols).cast_mut()) };
219        // SAFETY: The selected rows are a subset of the validated parent layout, with the
220        // same column count.
221        let layout = unsafe { Layout::new_unchecked(rows.end - rows.start, ncols) };
222        Some(Ref {
223            ptr,
224            layout,
225            _lifetime: PhantomData,
226        })
227    }
228
229    /// Return an iterator that divides the matrix into sub-matrices with (up to)
230    /// `batchsize` rows with `self.ncols()` columns.
231    ///
232    /// It is possible for yielded sub-matrices to have fewer than `batchsize` rows if the
233    /// number of rows in the parent matrix is not evenly divisible by `batchsize`.
234    fn window_iter(&self, batchsize: NonZeroUsize) -> iter::Windows<'_, Self::Element> {
235        iter::Windows::new(self.as_view(), batchsize)
236    }
237
238    /// Return an [`Owned`] with the same shape as `self` and cloned contents.
239    fn to_rowmajor_owned(&self) -> Owned<Self::Element>
240    where
241        Self::Element: Clone,
242    {
243        // SAFETY: The `Matrix` invariant makes `self.as_slice().len()` equal to
244        // `self.layout().num_elements()`.
245        unsafe { Owned::from_data_unchecked(self.as_slice().into(), self.layout()) }
246    }
247
248    /// Create a new [`Matrix`] by applying the closure `f` to each element.
249    ///
250    /// The returned matrix has the same shape as `self`.
251    fn try_map<F, R>(&self, f: F) -> Result<Owned<R>, LayoutError>
252    where
253        F: FnMut(&Self::Element) -> R,
254    {
255        let layout = self.layout().rebind::<R>()?;
256        let data: Box<[_]> = self.as_slice().iter().map(f).collect();
257
258        // SAFETY: Mapping preserves the element count, and `layout` is the source layout
259        // validated for the destination element type.
260        Ok(unsafe { Owned::from_data_unchecked(data, layout) })
261    }
262
263    /// Create a new [`Matrix`] by applying the closure `f` to each element.
264    ///
265    /// The returned matrix has the same shape as `self`.
266    ///
267    /// # Panics
268    ///
269    /// Panics if allocating space for [`Owned`] would overflow `isize::MAX`.
270    #[track_caller]
271    fn map<F, R>(&self, f: F) -> Owned<R>
272    where
273        F: FnMut(&Self::Element) -> R,
274    {
275        match self.try_map(f) {
276            Ok(owned) => owned,
277            Err(error) => panic!("`Matrix::map` failed: {error}"),
278        }
279    }
280
281    /// Transpose the elements in `self`.
282    fn transpose(&self) -> Owned<Self::Element>
283    where
284        Self::Element: Clone,
285    {
286        Owned::from_fn_with_layout(self.layout().transpose(), |RowCol { row, col }| {
287            // SAFETY: By construction, `col < self.nrows()` and `row < self.ncols()`.
288            unsafe { self.element_unchecked(col, row).clone() }
289        })
290    }
291
292    //-------//
293    // Rayon //
294    //-------//
295
296    /// Return a parallel iterator over the rows of the matrix.
297    #[cfg(feature = "rayon")]
298    fn par_rows(&self) -> impl IndexedParallelIterator<Item = &[Self::Element]>
299    where
300        Self::Element: Sync,
301    {
302        let r = self.as_view();
303
304        (0..r.nrows()).into_par_iter().map(move |row| {
305            // SAFETY: `row` comes from `0..r.nrows()`.
306            unsafe { r.into_row_unchecked(row) }
307        })
308    }
309
310    /// Return a parallel iterator that divides the matrix into sub-matrices with (up to)
311    /// `batchsize` rows with `self.ncols()` columns.
312    ///
313    /// This allows workers in parallel algorithms to work on dense subsets of the whole
314    /// matrix for better locality.
315    ///
316    /// It is possible for yielded sub-matrices to have fewer than `batchsize` rows if the
317    /// number of rows in the parent matrix is not evenly divisible by `batchsize`.
318    ///
319    /// # Panics
320    ///
321    /// Panics if `batchsize = 0`.
322    #[cfg(feature = "rayon")]
323    fn par_window_iter(
324        &self,
325        batchsize: usize,
326    ) -> impl IndexedParallelIterator<Item = Ref<'_, Self::Element>>
327    where
328        Self::Element: Sync,
329    {
330        assert!(batchsize != 0, "par_window_iter batchsize cannot be zero");
331
332        let r = self.as_view();
333        (0..r.nrows())
334            .into_par_iter()
335            .step_by(batchsize)
336            .map(move |start| {
337                let end = start.saturating_add(batchsize).min(r.nrows());
338
339                // SAFETY: `start` comes from `0..nrows` and `end` is clamped to `nrows`.
340                unsafe { r.into_subview_unchecked(start..end) }
341            })
342    }
343}
344
345///////////////
346// MatrixMut //
347///////////////
348
349/// Tools for treating contiguous regions of mutable memory as a dense, row-major matrix.
350///
351/// See also: [`Owned`], [`Ref`], [`Mut`].
352///
353/// # Safety
354///
355/// In addition to the requirements of [`Matrix`], implementations must ensure that for
356/// any **mutable** borrow `matrix: &mut Self`, it is valid to construct:
357///
358/// ```text
359/// let data = matrix.as_nonnull_mut();
360/// let layout = matrix.layout();
361///
362/// unsafe {
363///    std::slice::from_raw_parts_mut(data.as_ptr(), layout.num_elements())
364/// }
365/// ```
366///
367/// The resulting slice must have exclusive access to the described elements for its entire
368/// lifetime. No other reference may be used to access those elements during that lifetime.
369///
370/// Implementations may change their pointer or layout through exclusive access, such as when
371/// resizing or reallocating. They must not do so while any reference derived from the previous
372/// pointer and layout remains live.
373///
374/// For a given state of `matrix`, the pointers from `matrix.as_nonnull_mut()` and
375/// `matrix.as_nonnull()` must have the same address. However, the pointer obtained from
376/// `matrix.as_nonnull_mut()` must have provenance permitting mutable access to the span
377/// described by `matrix.layout()`.
378pub unsafe trait MatrixMut: Matrix {
379    /// Return the base pointer for the matrix.
380    ///
381    /// Calling this method must not change the matrix's pointer, layout, or contents.
382    ///
383    /// The returned pointer must have provenance permitting mutable access to the span
384    /// described by [`Matrix::layout`] and for a given matrix state, must have the same
385    /// address as [`Matrix::as_nonnull`].
386    fn as_nonnull_mut(&mut self) -> NonNull<Self::Element>;
387
388    //----------//
389    // Provided //
390    //----------//
391
392    /// Returns the requested row without bounds checking.
393    ///
394    /// # Safety
395    ///
396    /// The following conditions must hold to avoid undefined behavior:
397    ///
398    /// * `row < self.nrows()`.
399    unsafe fn row_unchecked_mut(&mut self, row: usize) -> &mut [Self::Element] {
400        let layout = self.layout();
401
402        debug_assert!(row < layout.nrows());
403
404        // SAFETY: The caller guarantees that `row` is in-bounds. The validated layout
405        // therefore places this row within the initialized span, and the `MatrixMut`
406        // invariant grants exclusive access for the returned borrow.
407        unsafe {
408            std::slice::from_raw_parts_mut(
409                self.as_mut_ptr().add(layout.ncols() * row),
410                layout.ncols(),
411            )
412        }
413    }
414
415    /// Return a pointer to the base of the matrix.
416    fn as_mut_ptr(&mut self) -> *mut Self::Element {
417        self.as_nonnull_mut().as_ptr()
418    }
419
420    /// Return the underlying data as a mutable slice.
421    fn as_mut_slice(&mut self) -> &mut [Self::Element] {
422        // SAFETY: The `MatrixMut` invariant requires this pointer and length to describe
423        // the initialized matrix span and grants exclusive access for this mutable borrow.
424        unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.layout().num_elements()) }
425    }
426
427    /// Return row `row` as a mutable slice.
428    ///
429    /// # Panics
430    ///
431    /// Panics if `row >= self.nrows()`.
432    fn row_mut(&mut self, row: usize) -> &mut [Self::Element] {
433        assert!(
434            row < self.nrows(),
435            "tried to access row {row} of a matrix with {} rows",
436            self.nrows()
437        );
438
439        // SAFETY: `row` is in-bounds.
440        unsafe { self.row_unchecked_mut(row) }
441    }
442
443    /// Return row `row` if `row < self.nrows()`. Otherwise, return `None`.
444    fn get_row_mut(&mut self, row: usize) -> Option<&mut [Self::Element]> {
445        if row < self.nrows() {
446            // SAFETY: `row` is in-bounds.
447            Some(unsafe { self.row_unchecked_mut(row) })
448        } else {
449            None
450        }
451    }
452
453    /// Return a mutable iterator over all rows in the matrix.
454    ///
455    /// Rows are yielded sequentially beginning with row 0.
456    fn rows_mut(&mut self) -> iter::RowsMut<'_, Self::Element> {
457        iter::RowsMut::new(self.as_view_mut())
458    }
459
460    /// Returns a mutable reference to an element without bounds checking.
461    ///
462    /// # Safety
463    ///
464    /// The following conditions must hold to avoid undefined behavior:
465    /// * `row < self.nrows()`.
466    /// * `col < self.ncols()`.
467    unsafe fn element_unchecked_mut(&mut self, row: usize, col: usize) -> &mut Self::Element {
468        let layout = self.layout();
469        debug_assert!(row < layout.nrows());
470        debug_assert!(col < layout.ncols());
471
472        // SAFETY: The caller guarantees that both indices are in-bounds, so the validated
473        // layout places this element within the initialized matrix span. The `MatrixMut`
474        // invariant grants exclusive access for the returned borrow.
475        unsafe { &mut *self.as_mut_ptr().add(row * layout.ncols() + col) }
476    }
477
478    /// Return the value at the specified `row` and `col`.
479    ///
480    /// If either index is out-of-bounds, return `None`.
481    fn get_element_mut(&mut self, row: usize, col: usize) -> Option<&mut Self::Element> {
482        if row >= self.nrows() || col >= self.ncols() {
483            None
484        } else {
485            // SAFETY: We just verified that `row` and `col` are in-bounds.
486            Some(unsafe { self.element_unchecked_mut(row, col) })
487        }
488    }
489
490    /// Return the value at the specified `row` and `col`.
491    ///
492    /// # Panics
493    ///
494    /// Panics if either `row` or `col` is out-of-bounds.
495    fn element_mut(&mut self, row: usize, col: usize) -> &mut Self::Element {
496        assert!(
497            row < self.nrows(),
498            "row {row} is out of bounds (max: {})",
499            self.nrows()
500        );
501        assert!(
502            col < self.ncols(),
503            "col {col} is out of bounds (max: {})",
504            self.ncols()
505        );
506
507        // SAFETY: We just verified that `row` and `col` are in-bounds.
508        unsafe { self.element_unchecked_mut(row, col) }
509    }
510
511    /// Return a view over the matrix.
512    fn as_view_mut(&mut self) -> Mut<'_, Self::Element> {
513        Mut {
514            ptr: self.as_nonnull_mut(),
515            layout: self.layout(),
516            _lifetime: PhantomData,
517        }
518    }
519
520    /// Return a mutable view over the rows in `rows`, or `None` when the range is invalid.
521    fn subview_mut(&mut self, rows: std::ops::Range<usize>) -> Option<Mut<'_, Self::Element>> {
522        if rows.start > rows.end || rows.end > self.nrows() {
523            return None;
524        }
525
526        let ncols = self.ncols();
527        // SAFETY: `rows.start <= self.nrows()`, so the validated parent layout makes the
528        // offset representable and places it within or one past the matrix span. Deriving
529        // from `as_nonnull_mut` preserves the mutable provenance required by `MatrixMut`.
530        let ptr = unsafe { self.as_nonnull_mut().add(rows.start * ncols) };
531        // SAFETY: The selected rows are a subset of the validated parent layout, with the
532        // same column count.
533        let layout = unsafe { Layout::new_unchecked(rows.end - rows.start, ncols) };
534        Some(Mut {
535            ptr,
536            layout,
537            _lifetime: PhantomData,
538        })
539    }
540
541    //-------//
542    // Rayon //
543    //-------//
544
545    /// Return a parallel iterator over the rows of the matrix.
546    ///
547    /// A matrix with zero columns yields one empty mutable slice per row.
548    #[cfg(feature = "rayon")]
549    fn par_rows_mut(&mut self) -> impl IndexedParallelIterator<Item = &mut [Self::Element]>
550    where
551        Self::Element: Send,
552    {
553        let matrix = iter::ParMut::new(self);
554        (0..matrix.nrows()).into_par_iter().map(move |row| {
555            // SAFETY: The range produces each in-bounds row exactly once. Distinct rows
556            // have disjoint element ranges; zero-column rows contain no elements.
557            unsafe { matrix.row_disjoint_unchecked(row) }
558        })
559    }
560
561    /// Return a parallel iterator that divides the matrix into mutable sub-matrices with
562    /// (up to) `batchsize` rows with `self.ncols()` columns.
563    ///
564    /// This allows workers in parallel algorithms to work on dense subsets of the whole
565    /// matrix for better locality.
566    ///
567    /// It is possible for yielded sub-matrices to have fewer than `batchsize` rows if the
568    /// number of rows in the parent matrix is not evenly divisible by `batchsize`.
569    ///
570    /// A matrix with zero columns yields zero-column sub-matrices containing up to
571    /// `batchsize` rows.
572    ///
573    /// # Panics
574    ///
575    /// Panics if `batchsize = 0`.
576    #[cfg(feature = "rayon")]
577    fn par_window_iter_mut(
578        &mut self,
579        batchsize: usize,
580    ) -> impl IndexedParallelIterator<Item = Mut<'_, Self::Element>>
581    where
582        Self::Element: Send,
583    {
584        assert!(
585            batchsize != 0,
586            "par_window_iter_mut batchsize cannot be zero"
587        );
588
589        let matrix = iter::ParMut::new(self);
590        let nrows = matrix.nrows();
591        (0..nrows)
592            .into_par_iter()
593            .step_by(batchsize)
594            .map(move |start| {
595                let end = start.saturating_add(batchsize).min(nrows);
596
597                // SAFETY: `start` comes from an in-bounds range and `end` is clamped to
598                // `nrows`. Stepping by `batchsize` makes the yielded ranges disjoint.
599                unsafe { matrix.window_disjoint_unchecked(start..end) }
600            })
601    }
602}
603
604///////////////////
605// Matrix Layout //
606///////////////////
607
608/// A validated layout for [`Matrix`] or [`MatrixMut`].
609///
610/// This type guarantees the following invariants:
611///
612/// * `self.nrows() * self.ncols()` does not exceed `usize::MAX`.
613/// * `self.nrows() * self.ncols() * std::mem::size_of::<T>()` does not exceed `isize::MAX`.
614pub struct Layout<T> {
615    nrows: usize,
616    ncols: usize,
617    _type: PhantomData<fn() -> T>,
618}
619
620impl<T> Layout<T> {
621    /// Construct a new [`Layout`], validating the following:
622    ///
623    /// * `nrows * ncols` does not exceed `usize::MAX`.
624    /// * `nrows * ncols * std::mem::size_of::<T>()` does not exceed `isize::MAX` (the maximum
625    ///   addressable byte span).
626    pub const fn new(nrows: usize, ncols: usize) -> Result<Self, LayoutError> {
627        match LayoutError::check::<T>(nrows, ncols) {
628            Ok(()) => Ok(Self {
629                nrows,
630                ncols,
631                _type: PhantomData,
632            }),
633            Err(err) => Err(err),
634        }
635    }
636
637    /// Construct a layout without validating its dimensions.
638    ///
639    /// # Safety
640    ///
641    /// `LayoutError::check::<T>(nrows, ncols)` must succeed.
642    unsafe fn new_unchecked(nrows: usize, ncols: usize) -> Self {
643        debug_assert!(LayoutError::check::<T>(nrows, ncols).is_ok());
644        Self {
645            nrows,
646            ncols,
647            _type: PhantomData,
648        }
649    }
650
651    /// Return the product `self.nrows() * self.ncols()`.
652    pub fn num_elements(&self) -> usize {
653        self.nrows() * self.ncols()
654    }
655
656    /// Return the number of rows.
657    pub fn nrows(&self) -> usize {
658        self.nrows
659    }
660
661    /// Return the number of columns.
662    pub fn ncols(&self) -> usize {
663        self.ncols
664    }
665
666    /// Rebind the element type to `U`.
667    ///
668    /// # Errors
669    ///
670    /// Returns an error if the rebound layout's byte size would exceed `isize::MAX`.
671    pub fn rebind<U>(&self) -> Result<Layout<U>, LayoutError> {
672        if std::mem::size_of::<U>() <= std::mem::size_of::<T>() {
673            // This branch is mainly to communicate to the compiler situations where an
674            // erroring branch can be avoided.
675            //
676            // SAFETY: `self` is validated, and rebinding to an equally sized or smaller
677            // element type cannot increase its byte span.
678            Ok(unsafe { Layout::new_unchecked(self.nrows(), self.ncols()) })
679        } else {
680            Layout::new(self.nrows(), self.ncols())
681        }
682    }
683
684    /// Swap the rows and columns.
685    pub fn transpose(&self) -> Layout<T> {
686        // SAFETY: Swapping the dimensions preserves both the element count and byte span
687        // of this validated layout.
688        unsafe { Layout::new_unchecked(self.ncols, self.nrows) }
689    }
690}
691
692impl<T> Clone for Layout<T> {
693    fn clone(&self) -> Self {
694        *self
695    }
696}
697
698impl<T> Copy for Layout<T> {}
699
700impl<T> std::fmt::Debug for Layout<T> {
701    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
702        f.debug_struct("Layout")
703            .field("nrows", &self.nrows)
704            .field("ncols", &self.ncols)
705            .field("elsize", &std::mem::size_of::<T>())
706            .finish()
707    }
708}
709
710impl<T> PartialEq for Layout<T> {
711    fn eq(&self, other: &Self) -> bool {
712        self.nrows == other.nrows && self.ncols == other.ncols
713    }
714}
715
716impl<T> Eq for Layout<T> {}
717
718/// Errors in the invariants guaranteed by [`Layout`].
719#[derive(Debug, Clone, Copy)]
720pub struct LayoutError {
721    nrows: usize,
722    ncols: usize,
723    elsize: Option<NonZeroUsize>,
724}
725
726impl LayoutError {
727    pub(crate) const fn check<T>(nrows: usize, ncols: usize) -> Result<(), Self> {
728        // Guard the element count itself so that `num_elements()` can never overflow.
729        let elsize = std::mem::size_of::<T>();
730        let num_elements = match nrows.checked_mul(ncols) {
731            Some(num_elements) => num_elements,
732            None => {
733                return Err(Self {
734                    nrows,
735                    ncols,
736                    elsize: None,
737                })
738            }
739        };
740
741        if let Some(len) = num_elements.checked_mul(std::mem::size_of::<T>()) {
742            if len <= isize::MAX as usize {
743                return Ok(());
744            }
745        }
746
747        Err(Self {
748            nrows,
749            ncols,
750            elsize: NonZeroUsize::new(elsize),
751        })
752    }
753}
754
755impl std::fmt::Display for LayoutError {
756    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
757        match self.elsize {
758            Some(elsize) => {
759                write!(
760                    f,
761                    "a matrix of size {}x{} with elements of size {} exceeds `isize::MAX` bytes",
762                    self.nrows, self.ncols, elsize
763                )
764            }
765            None => {
766                write!(
767                    f,
768                    "a matrix of size {}x{} has a length exceeding `usize::MAX`",
769                    self.nrows, self.ncols,
770                )
771            }
772        }
773    }
774}
775
776impl std::error::Error for LayoutError {}
777
778//---------------//
779// Helper Macros //
780//---------------//
781
782macro_rules! constructors {
783    ($element:ident, $data:ty) => {
784        /// Try to construct directly from `data`.
785        ///
786        /// Returns an error if [`Layout::new`] fails for `nrows` and `ncols` or `data.len()`
787        /// is not equal to `nrows * ncols`.
788        pub fn try_from_data(
789            data: $data,
790            nrows: usize,
791            ncols: usize,
792        ) -> Result<Self, TryFromError<$data>> {
793            let layout = match Layout::<$element>::new(nrows, ncols) {
794                Ok(layout) => layout,
795                Err(err) => return Err(TryFromError::layout(data, err)),
796            };
797
798            let len = data.len();
799            if len == layout.num_elements() {
800                // SAFETY: We've checked that `data.len() == layout.num_elements()`.
801                Ok(unsafe { Self::from_data_unchecked(data, layout) })
802            } else {
803                Err(TryFromError::mismatch(
804                    data,
805                    layout.nrows(),
806                    layout.ncols(),
807                    len,
808                ))
809            }
810        }
811
812        /// Construct a row vector directly from `data`.
813        pub fn row_vector(data: $data) -> Self {
814            // SAFETY: An existing slice's byte span cannot exceed `isize::MAX`, and
815            // `1 * data.len()` cannot overflow.
816            let layout = unsafe { Layout::new_unchecked(1, data.len()) };
817
818            // SAFETY: By construction, `data.len() == layout.num_elements()`.
819            unsafe { Self::from_data_unchecked(data, layout) }
820        }
821
822        /// Construct a column vector directly from `data`.
823        pub fn column_vector(data: $data) -> Self {
824            // SAFETY: An existing slice's byte span cannot exceed `isize::MAX`, and
825            // `data.len() * 1` cannot overflow.
826            let layout = unsafe { Layout::new_unchecked(data.len(), 1) };
827
828            // SAFETY: By construction, `data.len() == layout.num_elements()`.
829            unsafe { Self::from_data_unchecked(data, layout) }
830        }
831    };
832}
833
834///////////
835// Owned //
836///////////
837
838/// An initializer argument for the closure provided to [`Owned::from_fn`] and
839/// [`Owned::try_from_fn`] to remove ambiguity of the row and column being initialiazed.
840#[derive(Debug, Clone, Copy, PartialEq, Eq)]
841pub struct RowCol {
842    pub row: usize,
843    pub col: usize,
844}
845
846/// A [`Matrix`]/[`MatrixMut`] that owns its data.
847#[derive(Debug)]
848pub struct Owned<T> {
849    ptr: NonNull<T>,
850    layout: Layout<T>,
851}
852
853impl<T> Owned<T> {
854    constructors!(T, Box<[T]>);
855
856    // NOTE: For constructors, keep `from_fn` and `from_element` first.
857    //
858    // Rust suggests methods in their declaration order, so this keeps the most common
859    // methods as top suggestions.
860
861    /// Construct a new matrix using `init`.
862    ///
863    /// Elements are initialized in memory order.
864    ///
865    /// ```
866    /// use diskann_utils::views::rowmajor::{self, Matrix};
867    ///
868    /// let mat = rowmajor::Owned::from_fn(2, 3, |rc| 3 * rc.row + rc.col);
869    ///
870    /// assert_eq!(mat.row(0), &[0, 1, 2]);
871    /// assert_eq!(mat.row(1), &[3, 4, 5]);
872    /// ```
873    ///
874    /// # Panics
875    ///
876    /// Panics if `nrows * ncols` overflows `usize::MAX`, or if the allocation size exceeds
877    /// `isize::MAX`.
878    #[track_caller]
879    pub fn from_fn<F>(nrows: usize, ncols: usize, init: F) -> Self
880    where
881        F: FnMut(RowCol) -> T,
882    {
883        match Self::try_from_fn(nrows, ncols, init) {
884            Ok(matrix) => matrix,
885            Err(error) => panic!("Owned::from_fn failed with: {error}"),
886        }
887    }
888
889    /// Construct a new matrix using `init`.
890    ///
891    /// Elements are initialized in memory order.
892    ///
893    /// ```
894    /// use diskann_utils::views::rowmajor::{self, Matrix};
895    ///
896    /// let mat = rowmajor::Owned::try_from_fn(2, 3, |rc| 3 * rc.row + rc.col).unwrap();
897    ///
898    /// assert_eq!(mat.row(0), &[0, 1, 2]);
899    /// assert_eq!(mat.row(1), &[3, 4, 5]);
900    /// ```
901    ///
902    /// # Errors
903    ///
904    /// Returns an error if `nrows * ncols` overflows `usize::MAX`, or if the allocation size
905    /// exceeds `isize::MAX`.
906    pub fn try_from_fn<F>(nrows: usize, ncols: usize, init: F) -> Result<Self, LayoutError>
907    where
908        F: FnMut(RowCol) -> T,
909    {
910        let layout = Layout::new(nrows, ncols)?;
911        Ok(Self::from_fn_with_layout(layout, init))
912    }
913
914    /// Construct a new matrix by cloning `element`.
915    ///
916    /// Elements are initialized in memory order.
917    ///
918    /// ```
919    /// use diskann_utils::views::rowmajor::{self, Matrix};
920    ///
921    /// let mat = rowmajor::Owned::from_element(2, 3, 0u32);
922    ///
923    /// assert_eq!(mat.row(0), &[0, 0, 0]);
924    /// assert_eq!(mat.row(1), &[0, 0, 0]);
925    /// ```
926    ///
927    /// # Panics
928    ///
929    /// Panics if `nrows * ncols` overflows `usize::MAX`, or if the allocation size exceeds
930    /// `isize::MAX`.
931    #[track_caller]
932    pub fn from_element(nrows: usize, ncols: usize, element: T) -> Self
933    where
934        T: Clone,
935    {
936        match Self::try_from_element(nrows, ncols, element) {
937            Ok(matrix) => matrix,
938            Err(error) => panic!("Owned::from_element failed with: {error}"),
939        }
940    }
941
942    /// Construct a new matrix by cloning `element`.
943    ///
944    /// Elements are initialized in memory order.
945    ///
946    /// ```
947    /// use diskann_utils::views::rowmajor::{self, Matrix};
948    ///
949    /// let mat = rowmajor::Owned::try_from_element(2, 3, 0u32).unwrap();
950    ///
951    /// assert_eq!(mat.row(0), &[0, 0, 0]);
952    /// assert_eq!(mat.row(1), &[0, 0, 0]);
953    /// ```
954    ///
955    /// # Errors
956    ///
957    /// Returns an error if `nrows * ncols` overflows `usize::MAX`, or if the allocation size
958    /// exceeds `isize::MAX`.
959    pub fn try_from_element(nrows: usize, ncols: usize, element: T) -> Result<Self, LayoutError>
960    where
961        T: Clone,
962    {
963        let layout = Layout::new(nrows, ncols)?;
964        Ok(Self::from_element_with_layout(layout, element))
965    }
966
967    // Less common constructors.
968
969    /// Construct a new matrix using `init`.
970    ///
971    /// Elements are initialized in memory order.
972    pub fn from_fn_with_layout<F>(layout: Layout<T>, mut init: F) -> Self
973    where
974        F: FnMut(RowCol) -> T,
975    {
976        let mut row = 0;
977        let mut col = 0;
978
979        let data: Box<[T]> = (0..layout.num_elements())
980            .map(|_| {
981                let v = (init)(RowCol { row, col });
982                col += 1;
983                if col == layout.ncols() {
984                    col = 0;
985                    row += 1;
986                }
987                v
988            })
989            .collect();
990
991        // SAFETY: We constructed `data` to have length exactly `layout.num_elements()`.
992        unsafe { Self::from_data_unchecked(data, layout) }
993    }
994
995    /// Construct a new matrix by cloning `element`.
996    ///
997    /// Elements are initialized in memory order.
998    pub fn from_element_with_layout(layout: Layout<T>, element: T) -> Self
999    where
1000        T: Clone,
1001    {
1002        let data: Box<[T]> = std::iter::repeat_n(element, layout.num_elements()).collect();
1003
1004        // SAFETY: We constructed `data` to have length exactly `layout.num_elements()`.
1005        unsafe { Self::from_data_unchecked(data, layout) }
1006    }
1007
1008    /// # Safety
1009    ///
1010    /// `b.len()` must equal `layout.num_elements()`.
1011    unsafe fn from_data_unchecked(b: Box<[T]>, layout: Layout<T>) -> Self {
1012        debug_assert_eq!(b.len(), layout.num_elements());
1013        Self {
1014            ptr: internal::box_to_nonnull(b),
1015            layout,
1016        }
1017    }
1018
1019    /// Consume `self`, returning the unmodified contents as a boxed slice.
1020    ///
1021    /// ```
1022    /// use diskann_utils::views::rowmajor::{Matrix, Owned};
1023    ///
1024    /// let mat = Owned::from_fn(2, 3, |rc| rc.col);
1025    /// assert_eq!(mat.row(0), &[0, 1, 2]);
1026    /// assert_eq!(mat.row(1), &[0, 1, 2]);
1027    ///
1028    /// let b: Box<[usize]> = mat.into_inner();
1029    /// assert_eq!(&*b, &[0, 1, 2, 0, 1, 2]);
1030    /// ```
1031    pub fn into_inner(self) -> Box<[T]> {
1032        let me = ManuallyDrop::new(self);
1033
1034        // SAFETY: `me.ptr` came from exactly one `Box<[T]>` of this length. Suppressing
1035        // `Owned::drop` transfers that allocation back to the reconstructed box.
1036        unsafe { internal::nonnull_to_box(me.ptr, me.layout.num_elements()) }
1037    }
1038}
1039
1040// SAFETY: `Owned<T>` has the ownership semantics of `Box<[T]>`, which is `Send` when `T` is.
1041unsafe impl<T> Send for Owned<T> where T: Send {}
1042// SAFETY: Shared access to `Owned<T>` exposes only shared access to `T`.
1043unsafe impl<T> Sync for Owned<T> where T: Sync {}
1044
1045impl<T> Drop for Owned<T> {
1046    fn drop(&mut self) {
1047        // SAFETY: `self.ptr` came from exactly one `Box<[T]>` of this length, and `drop`
1048        // is the unique place that reconstructs it.
1049        let _ = unsafe { internal::nonnull_to_box(self.ptr, self.layout.num_elements()) };
1050    }
1051}
1052
1053impl<T> Clone for Owned<T>
1054where
1055    T: Clone,
1056{
1057    fn clone(&self) -> Self {
1058        // SAFETY: The constructed boxed slice has length exactly `self.layout.num_elements()`.
1059        unsafe { Owned::from_data_unchecked(self.as_slice().into(), self.layout()) }
1060    }
1061}
1062
1063// SAFETY: `Owned` keeps a stable pointer and layout to its initialized boxed slice.
1064unsafe impl<T> Matrix for Owned<T> {
1065    type Element = T;
1066
1067    fn as_nonnull(&self) -> NonNull<T> {
1068        self.ptr
1069    }
1070
1071    fn layout(&self) -> Layout<T> {
1072        self.layout
1073    }
1074}
1075
1076// SAFETY: A mutable borrow of `Owned` has exclusive access to its boxed slice.
1077unsafe impl<T> MatrixMut for Owned<T> {
1078    fn as_nonnull_mut(&mut self) -> NonNull<T> {
1079        self.ptr
1080    }
1081}
1082
1083impl<T> PartialEq for Owned<T>
1084where
1085    T: PartialEq,
1086{
1087    fn eq(&self, other: &Self) -> bool {
1088        Matrix::as_view(self).eq(&Matrix::as_view(other))
1089    }
1090}
1091
1092impl<'a, T> Reborrow<'a> for Owned<T> {
1093    type Target = Ref<'a, T>;
1094    fn reborrow(&'a self) -> Self::Target {
1095        Matrix::as_view(self)
1096    }
1097}
1098
1099impl<'a, T> ReborrowMut<'a> for Owned<T> {
1100    type Target = Mut<'a, T>;
1101    fn reborrow_mut(&'a mut self) -> Self::Target {
1102        MatrixMut::as_view_mut(self)
1103    }
1104}
1105
1106//-----------//
1107// Resizable //
1108//-----------//
1109
1110/// A row-major matrix that owns its storage and can change shape in place.
1111///
1112/// Use it as reusable scratch storage for matrices of different shapes.
1113/// [`Resizable::resize`] and [`Resizable::resize_with`] may reuse the existing
1114/// allocation. After a resize, every element holds a valid `T`, but the values
1115/// are unspecified: write the matrix before you read it.
1116///
1117/// ```
1118/// use diskann_utils::views::rowmajor::{Matrix, MatrixMut, Resizable};
1119///
1120/// let mut scratch = Resizable::<f32>::new();
1121/// scratch.resize(2, 3).unwrap();
1122/// scratch.as_mut_slice().fill(1.0);
1123/// assert_eq!((scratch.nrows(), scratch.ncols()), (2, 3));
1124/// assert_eq!(scratch.row(1), &[1.0, 1.0, 1.0]);
1125/// ```
1126#[derive(Debug, Clone)]
1127pub struct Resizable<T> {
1128    /// Invariant: `data.len() >= layout.num_elements()`. Elements past the
1129    /// current shape are kept for later resizes.
1130    data: Vec<T>,
1131    layout: Layout<T>,
1132}
1133
1134impl<T> Resizable<T> {
1135    /// Construct an empty `0 x 0` matrix. No memory is allocated.
1136    pub fn new() -> Self {
1137        Self::with_capacity(0)
1138    }
1139
1140    /// Construct an empty `0 x 0` matrix with room for at least `capacity`
1141    /// elements.
1142    pub fn with_capacity(capacity: usize) -> Self {
1143        Self {
1144            data: Vec::with_capacity(capacity),
1145            // SAFETY: A `0 x 0` layout has zero elements and passes `LayoutError::check`.
1146            layout: unsafe { Layout::new_unchecked(0, 0) },
1147        }
1148    }
1149
1150    /// The number of elements that the matrix can hold without allocating.
1151    pub fn capacity(&self) -> usize {
1152        self.data.capacity()
1153    }
1154
1155    /// Set the shape to `nrows x ncols`. The element values are unspecified.
1156    ///
1157    /// `f` creates the elements that the current storage cannot supply.
1158    ///
1159    /// Returns an error if `nrows x ncols` is not a valid [`Layout`]. The shape
1160    /// is then unchanged.
1161    pub fn resize_with<F>(&mut self, nrows: usize, ncols: usize, f: F) -> Result<(), LayoutError>
1162    where
1163        F: FnMut() -> T,
1164    {
1165        let layout = Layout::new(nrows, ncols)?;
1166        let len = layout.num_elements();
1167        if self.data.len() < len {
1168            self.data.resize_with(len, f);
1169        }
1170        self.layout = layout;
1171        Ok(())
1172    }
1173
1174    /// Set the shape to `nrows x ncols`. The element values are unspecified.
1175    ///
1176    /// Returns an error if `nrows x ncols` is not a valid [`Layout`]. The shape
1177    /// is then unchanged.
1178    pub fn resize(&mut self, nrows: usize, ncols: usize) -> Result<(), LayoutError>
1179    where
1180        T: Default,
1181    {
1182        self.resize_with(nrows, ncols, T::default)
1183    }
1184
1185    /// Set the shape to `0 x 0`. The allocation is kept.
1186    pub fn clear(&mut self) {
1187        // SAFETY: A `0 x 0` layout has zero elements and passes `LayoutError::check`.
1188        self.layout = unsafe { Layout::new_unchecked(0, 0) };
1189    }
1190
1191    /// Drop the elements past the current shape and release unused memory.
1192    pub fn shrink_to_fit(&mut self) {
1193        self.data.truncate(self.layout.num_elements());
1194        self.data.shrink_to_fit();
1195    }
1196}
1197
1198impl<T> Default for Resizable<T> {
1199    fn default() -> Self {
1200        Self::new()
1201    }
1202}
1203
1204impl<T> From<Owned<T>> for Resizable<T> {
1205    /// Take the storage of `matrix` without copying it.
1206    fn from(matrix: Owned<T>) -> Self {
1207        let layout = matrix.layout();
1208        Self {
1209            data: matrix.into_inner().into_vec(),
1210            layout,
1211        }
1212    }
1213}
1214
1215impl<T> From<Resizable<T>> for Owned<T> {
1216    /// Keep the elements of the current shape and drop the rest.
1217    fn from(mut matrix: Resizable<T>) -> Self {
1218        matrix.data.truncate(matrix.layout.num_elements());
1219        let layout = matrix.layout;
1220        // SAFETY: After the truncation, the length equals `layout.num_elements()`
1221        // because the invariant keeps `data.len() >= layout.num_elements()`.
1222        unsafe { Owned::from_data_unchecked(matrix.data.into_boxed_slice(), layout) }
1223    }
1224}
1225
1226impl<T> PartialEq for Resizable<T>
1227where
1228    T: PartialEq,
1229{
1230    /// Compare the shapes and the elements of the shapes.
1231    fn eq(&self, other: &Self) -> bool {
1232        Matrix::as_view(self).eq(&Matrix::as_view(other))
1233    }
1234}
1235
1236// SAFETY: The invariant keeps `data.len() >= layout.num_elements()`, so the
1237// first `layout.num_elements()` elements of the vector are initialized, within
1238// one allocation, and aligned. An empty vector gives a dangling, aligned pointer.
1239unsafe impl<T> Matrix for Resizable<T> {
1240    type Element = T;
1241
1242    fn as_nonnull(&self) -> NonNull<T> {
1243        NonNull::from(self.data.as_slice()).cast()
1244    }
1245
1246    fn layout(&self) -> Layout<T> {
1247        self.layout
1248    }
1249}
1250
1251// SAFETY: A mutable borrow of `Resizable` has exclusive access to its vector.
1252unsafe impl<T> MatrixMut for Resizable<T> {
1253    fn as_nonnull_mut(&mut self) -> NonNull<T> {
1254        NonNull::from(self.data.as_mut_slice()).cast()
1255    }
1256}
1257
1258impl<'a, T> Reborrow<'a> for Resizable<T> {
1259    type Target = Ref<'a, T>;
1260    fn reborrow(&'a self) -> Self::Target {
1261        Matrix::as_view(self)
1262    }
1263}
1264
1265impl<'a, T> ReborrowMut<'a> for Resizable<T> {
1266    type Target = Mut<'a, T>;
1267    fn reborrow_mut(&'a mut self) -> Self::Target {
1268        MatrixMut::as_view_mut(self)
1269    }
1270}
1271
1272//-----//
1273// Ref //
1274//-----//
1275
1276/// A [`Matrix`] implementation that references its data.
1277#[derive(Debug)]
1278pub struct Ref<'a, T> {
1279    ptr: NonNull<T>,
1280    layout: Layout<T>,
1281    _lifetime: PhantomData<&'a [T]>,
1282}
1283
1284// SAFETY: `Ref<'_, T>` has the ownership semantics of `&[T]`, which is `Send` when `T` is
1285// `Sync`.
1286unsafe impl<T> Send for Ref<'_, T> where T: Sync {}
1287// SAFETY: `Ref<'_, T>` exposes only shared access to `T`.
1288unsafe impl<T> Sync for Ref<'_, T> where T: Sync {}
1289
1290impl<'a, T> Ref<'a, T> {
1291    constructors!(T, &'a [T]);
1292
1293    /// # Safety
1294    ///
1295    /// `b.len()` must equal `layout.num_elements()`.
1296    unsafe fn from_data_unchecked(b: &'a [T], layout: Layout<T>) -> Self {
1297        debug_assert_eq!(b.len(), layout.num_elements());
1298        Self {
1299            ptr: internal::slice_to_nonnull(b),
1300            layout,
1301            _lifetime: PhantomData,
1302        }
1303    }
1304
1305    /// Return the contents of `self` as a slice.
1306    ///
1307    /// Unlike [`Matrix::as_slice`], the returned slices inherits the lifetime of the [`Ref`].
1308    pub fn into_slice(self) -> &'a [T] {
1309        // SAFETY: `Ref` represents a valid `&'a [T]` of exactly this length.
1310        unsafe { std::slice::from_raw_parts(self.as_ptr(), self.layout().num_elements()) }
1311    }
1312
1313    /// Get the indicated `row` with the lifetime `'a`.
1314    ///
1315    /// # Safety
1316    ///
1317    /// `row < self.nrows()`.
1318    #[cfg(feature = "rayon")]
1319    unsafe fn into_row_unchecked(self, row: usize) -> &'a [T] {
1320        let layout = self.layout();
1321        debug_assert!(row < layout.nrows());
1322
1323        // SAFETY: The caller guarantees that `row` is in-bounds, so the validated layout
1324        // places this row within the `&'a [T]` represented by `self`.
1325        unsafe {
1326            std::slice::from_raw_parts(self.as_ptr().add(layout.ncols() * row), layout.ncols())
1327        }
1328    }
1329
1330    /// Return a `Ref` containing the indicated rows with the lifetime `'a`.
1331    ///
1332    /// # Safety
1333    ///
1334    /// `rows.start <= rows.end` and `rows.end <= self.nrows()`.
1335    #[cfg(feature = "rayon")]
1336    unsafe fn into_subview_unchecked(self, rows: std::ops::Range<usize>) -> Ref<'a, T> {
1337        debug_assert!(rows.start <= rows.end);
1338        debug_assert!(rows.end <= self.nrows());
1339
1340        let ncols = self.ncols();
1341        Self {
1342            // SAFETY: The validated range starts within or one past the matrix span, and
1343            // the parent layout guarantees that the offset is representable.
1344            ptr: unsafe { self.ptr.add(rows.start * ncols) },
1345            // SAFETY: This layout is no larger than `self`'s layout.
1346            layout: unsafe { Layout::new_unchecked(rows.end - rows.start, ncols) },
1347            _lifetime: PhantomData,
1348        }
1349    }
1350}
1351
1352impl<T> Clone for Ref<'_, T> {
1353    fn clone(&self) -> Self {
1354        *self
1355    }
1356}
1357
1358impl<T> Copy for Ref<'_, T> {}
1359
1360// SAFETY: `Ref` keeps a stable pointer and layout to the initialized slice it borrows.
1361unsafe impl<T> Matrix for Ref<'_, T> {
1362    type Element = T;
1363
1364    fn as_nonnull(&self) -> NonNull<T> {
1365        self.ptr
1366    }
1367
1368    fn layout(&self) -> Layout<T> {
1369        self.layout
1370    }
1371}
1372
1373impl<'a, T> Reborrow<'a> for Ref<'_, T> {
1374    type Target = Ref<'a, T>;
1375    fn reborrow(&'a self) -> Self::Target {
1376        Matrix::as_view(self)
1377    }
1378}
1379
1380impl<T> PartialEq for Ref<'_, T>
1381where
1382    T: PartialEq,
1383{
1384    fn eq(&self, other: &Self) -> bool {
1385        self.layout() == other.layout() && self.as_slice() == other.as_slice()
1386    }
1387}
1388
1389//-----//
1390// Mut //
1391//-----//
1392
1393/// A [`Matrix`]/[`MatrixMut`] implementation that mutably references its data.
1394#[derive(Debug)]
1395pub struct Mut<'a, T> {
1396    ptr: NonNull<T>,
1397    layout: Layout<T>,
1398    _lifetime: PhantomData<&'a mut [T]>,
1399}
1400
1401// SAFETY: `Mut<'_, T>` has the ownership semantics of `&mut [T]`, which is `Send` when
1402// `T` is `Send`.
1403unsafe impl<T> Send for Mut<'_, T> where T: Send {}
1404// SAFETY: Shared access to `Mut<'_, T>` exposes only shared access to `T`.
1405unsafe impl<T> Sync for Mut<'_, T> where T: Sync {}
1406
1407impl<'a, T> Mut<'a, T> {
1408    constructors!(T, &'a mut [T]);
1409
1410    /// # Safety
1411    ///
1412    /// `b.len()` must equal `layout.num_elements()`.
1413    unsafe fn from_data_unchecked(b: &'a mut [T], layout: Layout<T>) -> Self {
1414        debug_assert_eq!(b.len(), layout.num_elements());
1415        Self {
1416            ptr: internal::mut_slice_to_nonnull(b),
1417            layout,
1418            _lifetime: PhantomData,
1419        }
1420    }
1421
1422    /// Consume `self` and return the underlying data as a mutable slice.
1423    pub fn into_mut_slice(self) -> &'a mut [T] {
1424        // SAFETY: `self.ptr` and `self.layout` together describe a valid `&'a mut [T]` of
1425        // length `self.layout.num_elements()`, per the invariants of `Mut`.
1426        unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.layout.num_elements()) }
1427    }
1428}
1429
1430// SAFETY: `Mut` keeps a stable pointer and layout to the initialized slice it borrows.
1431unsafe impl<T> Matrix for Mut<'_, T> {
1432    type Element = T;
1433
1434    fn as_nonnull(&self) -> NonNull<T> {
1435        self.ptr
1436    }
1437
1438    fn layout(&self) -> Layout<T> {
1439        self.layout
1440    }
1441}
1442
1443// SAFETY: A mutable borrow of `Mut` has exclusive access to its borrowed slice.
1444unsafe impl<T> MatrixMut for Mut<'_, T> {
1445    fn as_nonnull_mut(&mut self) -> NonNull<T> {
1446        self.ptr
1447    }
1448}
1449
1450impl<T> PartialEq for Mut<'_, T>
1451where
1452    T: PartialEq,
1453{
1454    fn eq(&self, other: &Self) -> bool {
1455        Matrix::as_view(self).eq(&Matrix::as_view(other))
1456    }
1457}
1458
1459impl<'a, T> Reborrow<'a> for Mut<'_, T> {
1460    type Target = Ref<'a, T>;
1461    fn reborrow(&'a self) -> Self::Target {
1462        Matrix::as_view(self)
1463    }
1464}
1465
1466impl<'a, T> ReborrowMut<'a> for Mut<'_, T> {
1467    type Target = Mut<'a, T>;
1468    fn reborrow_mut(&'a mut self) -> Self::Target {
1469        MatrixMut::as_view_mut(self)
1470    }
1471}
1472
1473//--------//
1474// Errors //
1475//--------//
1476
1477/// Errors from [`Owned::try_from_data`], [`Ref::try_from_data`], and [`Mut::try_from_data`].
1478pub struct TryFromError<T> {
1479    data: T,
1480    inner: TryFromErrorInner,
1481}
1482
1483impl<T> TryFromError<T> {
1484    /// Consume the error and return the base data.
1485    pub fn into_inner(self) -> T {
1486        self.data
1487    }
1488
1489    /// Return a variation of `Self` that is guaranteed to be `'static` by removing the
1490    /// data that was passed to the original constructor.
1491    pub fn as_static(&self) -> TryFromErrorLight {
1492        TryFromErrorLight(self.inner)
1493    }
1494
1495    //--------------//
1496    // Constructors //
1497    //--------------//
1498
1499    fn layout(data: T, error: LayoutError) -> Self {
1500        Self {
1501            data,
1502            inner: TryFromErrorInner::Layout(error),
1503        }
1504    }
1505
1506    fn mismatch(data: T, nrows: usize, ncols: usize, len: usize) -> Self {
1507        Self {
1508            data,
1509            inner: TryFromErrorInner::Mismatch { nrows, ncols, len },
1510        }
1511    }
1512}
1513
1514impl<T> std::fmt::Debug for TryFromError<T> {
1515    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1516        f.debug_struct("TryFromError")
1517            .field("data", &"<hidden>")
1518            .field("inner", &self.inner)
1519            .finish()
1520    }
1521}
1522
1523impl<T> std::fmt::Display for TryFromError<T> {
1524    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1525        self.inner.fmt(f)
1526    }
1527}
1528
1529impl<T> std::error::Error for TryFromError<T> {}
1530
1531/// A guaranteed `'static` version of [`TryFromError`].
1532#[derive(Debug, Error)]
1533#[error(transparent)]
1534pub struct TryFromErrorLight(TryFromErrorInner);
1535
1536#[derive(Debug, Error, Clone, Copy)]
1537enum TryFromErrorInner {
1538    #[error(transparent)]
1539    Layout(LayoutError),
1540    #[error(
1541        "tried to construct a {}x{} matrix over a span of length {}",
1542        nrows,
1543        ncols,
1544        len
1545    )]
1546    Mismatch {
1547        nrows: usize,
1548        ncols: usize,
1549        len: usize,
1550    },
1551}
1552
1553///////////
1554// Tests //
1555///////////
1556
1557#[cfg(test)]
1558mod tests {
1559    use super::*;
1560    use crate::{assert_contains, lazy_format};
1561
1562    #[test]
1563    fn resizable_takes_each_shape_and_reuses_its_storage() {
1564        let mut matrix = Resizable::<u32>::new();
1565        assert_eq!((matrix.nrows(), matrix.ncols()), (0, 0));
1566        assert_eq!(matrix.as_slice(), &[]);
1567
1568        // The views cover the current shape and see the written values.
1569        matrix.resize(2, 3).unwrap();
1570        for (i, x) in matrix.as_mut_slice().iter_mut().enumerate() {
1571            *x = i as u32;
1572        }
1573        assert_eq!((matrix.nrows(), matrix.ncols()), (2, 3));
1574        assert_eq!(matrix.row(1), &[3, 4, 5]);
1575        assert_eq!(matrix.as_view_mut().row_mut(0), &mut [0, 1, 2]);
1576
1577        // A smaller shape keeps the allocation.
1578        let capacity = matrix.capacity();
1579        matrix.resize(1, 2).unwrap();
1580        assert_eq!((matrix.nrows(), matrix.ncols()), (1, 2));
1581        assert_eq!(matrix.as_slice().len(), 2);
1582        assert_eq!(matrix.capacity(), capacity);
1583
1584        // A larger shape covers every element.
1585        matrix.resize(2, 4).unwrap();
1586        assert_eq!(matrix.as_slice().len(), 8);
1587    }
1588
1589    #[test]
1590    fn resizable_rejects_an_overflowing_shape_and_keeps_the_old_one() {
1591        let mut matrix = Resizable::<u32>::new();
1592        matrix.resize(2, 4).unwrap();
1593
1594        assert!(matrix.resize(usize::MAX, 2).is_err());
1595
1596        assert_eq!((matrix.nrows(), matrix.ncols()), (2, 4));
1597    }
1598
1599    #[test]
1600    fn resizable_holds_types_without_default() {
1601        // `NonZeroUsize` has no `Default`, so only `resize_with` can create elements.
1602        let one = NonZeroUsize::MIN;
1603        let mut matrix = Resizable::new();
1604
1605        matrix.resize_with(2, 2, || one).unwrap();
1606
1607        assert_eq!(matrix.as_slice(), &[one; 4]);
1608    }
1609
1610    #[test]
1611    fn resizable_clear_and_shrink_release_only_what_they_promise() {
1612        let mut matrix = Resizable::<u8>::with_capacity(16);
1613        assert!(matrix.capacity() >= 16);
1614        matrix.resize(2, 4).unwrap();
1615
1616        // Clearing keeps the allocation.
1617        let capacity = matrix.capacity();
1618        matrix.clear();
1619        assert_eq!((matrix.nrows(), matrix.ncols()), (0, 0));
1620        assert_eq!(matrix.capacity(), capacity);
1621
1622        // Shrinking keeps only the current shape.
1623        matrix.resize(1, 3).unwrap();
1624        matrix.shrink_to_fit();
1625        assert_eq!(matrix.as_slice().len(), 3);
1626        assert!(matrix.capacity() < capacity);
1627    }
1628
1629    #[test]
1630    fn resizable_converts_to_and_from_owned() {
1631        let owned = Owned::from_fn(2, 3, |rc| rc.row * 3 + rc.col);
1632
1633        let mut matrix = Resizable::from(owned.clone());
1634        assert_eq!(matrix.as_view(), owned.as_view());
1635
1636        // Only the elements of the current shape move into the owned matrix.
1637        matrix.resize(1, 3).unwrap();
1638        let back = Owned::from(matrix);
1639        assert_eq!((back.nrows(), back.ncols()), (1, 3));
1640        assert_eq!(back.as_slice(), &[0, 1, 2]);
1641    }
1642
1643    #[test]
1644    fn resizable_equality_compares_the_shape_and_its_elements() {
1645        let mut left = Resizable::from(Owned::from_element(2, 2, 7_u8));
1646        let mut right = Resizable::from(Owned::from_element(1, 4, 7_u8));
1647        // Same elements, different shapes.
1648        assert_ne!(left, right);
1649
1650        // Storage past the shape does not take part.
1651        right.resize(1, 2).unwrap();
1652        left.resize(1, 2).unwrap();
1653        assert_eq!(left, right);
1654    }
1655
1656    /// This function is only callable with copyable types.
1657    ///
1658    /// This lets us test for types we expect to be `Copy`.
1659    fn is_copyable<T: Copy>(_x: T) -> bool {
1660        true
1661    }
1662
1663    /// This function attests that `Ref` is covariant in the view lifetime.
1664    fn _matrix_view_is_covariant<'a, 'b>(m: Ref<'a, f32>) -> Ref<'b, f32>
1665    where
1666        'a: 'b,
1667    {
1668        m
1669    }
1670
1671    fn _matrix_view_is_covariant_in_t<'a, 'b, 'm>(m: Ref<'m, &'a f32>) -> Ref<'m, &'b f32>
1672    where
1673        'a: 'b,
1674    {
1675        m
1676    }
1677
1678    fn _matrix_is_covariant_in_t<'a, 'b, 'm>(m: &'m Owned<&'a f32>) -> &'m Owned<&'b f32>
1679    where
1680        'a: 'b,
1681    {
1682        m
1683    }
1684
1685    //--------//
1686    // Layout //
1687    //--------//
1688
1689    #[test]
1690    fn test_layout() {
1691        // Happy path
1692        for rows in 0..5 {
1693            for cols in 0..5 {
1694                let layout = Layout::<String>::new(rows, cols).unwrap();
1695                assert_eq!(layout.nrows(), rows);
1696                assert_eq!(layout.ncols(), cols);
1697                assert_eq!(layout.num_elements(), rows * cols);
1698
1699                let transpose = layout.transpose();
1700                assert_eq!(transpose.nrows(), cols);
1701                assert_eq!(transpose.ncols(), rows);
1702                assert_eq!(transpose.num_elements(), rows * cols);
1703
1704                let rebind = layout.rebind::<u32>().unwrap();
1705                assert_eq!(rebind.nrows(), rows);
1706                assert_eq!(rebind.ncols(), cols);
1707                assert_eq!(rebind.num_elements(), rows * cols);
1708
1709                is_copyable(layout);
1710            }
1711        }
1712
1713        #[expect(unused, reason = "we need this so the size is non-zero")]
1714        struct NotDebugOrEq(u32);
1715
1716        assert_eq!(
1717            Layout::<NotDebugOrEq>::new(10, 20).unwrap(),
1718            Layout::<NotDebugOrEq>::new(10, 20).unwrap(),
1719        );
1720
1721        assert_eq!(
1722            Layout::<NotDebugOrEq>::new(20, 0).unwrap(),
1723            Layout::<NotDebugOrEq>::new(20, 0).unwrap(),
1724        );
1725
1726        assert_ne!(
1727            Layout::<NotDebugOrEq>::new(10, 20).unwrap(),
1728            Layout::<NotDebugOrEq>::new(20, 0).unwrap(),
1729        );
1730
1731        let fmt = format!("{:?}", Layout::<NotDebugOrEq>::new(5, 6).unwrap());
1732        assert_eq!(fmt, "Layout { nrows: 5, ncols: 6, elsize: 4 }");
1733
1734        // Overflowing the element count returns an error.
1735        let error = Layout::<u8>::new(usize::MAX, 2).unwrap_err();
1736        assert_eq!(
1737            error.to_string(),
1738            format!(
1739                "a matrix of size {}x2 has a length exceeding `usize::MAX`",
1740                usize::MAX
1741            )
1742        );
1743
1744        // The largest possible byte span is valid without allocating it.
1745        let layout = Layout::<u8>::new(isize::MAX as usize, 1).unwrap();
1746        assert_eq!(layout.num_elements(), isize::MAX as usize);
1747
1748        let transpose = layout.transpose();
1749        assert_eq!(transpose.nrows(), 1);
1750        assert_eq!(transpose.ncols(), isize::MAX as usize);
1751        assert_eq!(transpose.num_elements(), layout.num_elements());
1752
1753        // One byte beyond the maximum span returns an error.
1754        let error = Layout::<u8>::new(isize::MAX as usize + 1, 1).unwrap_err();
1755        assert_eq!(
1756            error.to_string(),
1757            format!(
1758                "a matrix of size {}x1 with elements of size 1 exceeds `isize::MAX` bytes",
1759                isize::MAX as usize + 1
1760            )
1761        );
1762
1763        // Rebinding to a larger element type revalidates the byte span.
1764        let rebound = Layout::<u8>::new(3, 4).unwrap().rebind::<u16>().unwrap();
1765        assert_eq!(rebound.nrows(), 3);
1766        assert_eq!(rebound.ncols(), 4);
1767        assert_eq!(rebound.num_elements(), 12);
1768
1769        let error = layout.rebind::<u16>().unwrap_err();
1770        assert_eq!(
1771            error.to_string(),
1772            format!(
1773                "a matrix of size {}x1 with elements of size 2 exceeds `isize::MAX` bytes",
1774                isize::MAX
1775            )
1776        );
1777    }
1778
1779    ////////////
1780    // Matrix //
1781    ////////////
1782
1783    #[test]
1784    fn test_sizes() {
1785        let expected = 3 * std::mem::size_of::<usize>();
1786        assert_eq!(std::mem::size_of::<Owned<String>>(), expected);
1787        assert_eq!(std::mem::size_of::<Option<Owned<String>>>(), expected);
1788
1789        assert_eq!(std::mem::size_of::<Ref<'_, String>>(), expected);
1790        assert_eq!(std::mem::size_of::<Option<Ref<'_, String>>>(), expected);
1791
1792        assert_eq!(std::mem::size_of::<Mut<'_, String>>(), expected);
1793        assert_eq!(std::mem::size_of::<Option<Mut<'_, String>>>(), expected);
1794    }
1795
1796    #[test]
1797    fn fallible_matrix_constructors() {
1798        let err = Owned::try_from_element(usize::MAX, usize::MAX, 0u32).unwrap_err();
1799        let msg = err.to_string();
1800        assert_contains!(msg, "exceeding `usize::MAX`");
1801
1802        let err = Owned::try_from_element(isize::MAX as usize, 1, 0u32).unwrap_err();
1803        let msg = err.to_string();
1804        assert_contains!(msg, "exceeds `isize::MAX` bytes");
1805
1806        // Panicking
1807        let err = std::panic::catch_unwind(|| {
1808            Owned::from_element(usize::MAX, usize::MAX, 0u32);
1809        })
1810        .unwrap_err()
1811        .downcast::<String>()
1812        .unwrap();
1813
1814        let msg = err.to_string();
1815        assert_contains!(msg, "exceeding `usize::MAX`");
1816
1817        let err = std::panic::catch_unwind(|| {
1818            Owned::from_element(isize::MAX as usize, 1, 0u32);
1819        })
1820        .unwrap_err()
1821        .downcast::<String>()
1822        .unwrap();
1823        let msg = err.to_string();
1824        assert_contains!(msg, "exceeds `isize::MAX` bytes");
1825
1826        // Construction fails without invoking the generator.
1827        let err = Owned::try_from_fn(usize::MAX, usize::MAX, |_| panic!("boom")).unwrap_err();
1828        let msg = err.to_string();
1829        assert_contains!(msg, "exceeding `usize::MAX`");
1830
1831        let err = std::panic::catch_unwind(|| {
1832            Owned::from_fn(usize::MAX, usize::MAX, |_| {
1833                panic!("initializer must not run")
1834            });
1835        })
1836        .unwrap_err()
1837        .downcast::<String>()
1838        .unwrap();
1839        let msg = err.to_string();
1840        assert_contains!(msg, "Owned::from_fn failed");
1841        assert_contains!(msg, "exceeding `usize::MAX`");
1842    }
1843
1844    fn make_test_matrix() -> Vec<usize> {
1845        // Construct a matrix with 4 rows of length 3.
1846        // The expected layout is as follows:
1847        //
1848        // 0, 1, 2,
1849        // 1, 2, 3,
1850        // 2, 3, 4,
1851        // 3, 4, 5
1852        //
1853        vec![0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5]
1854    }
1855
1856    fn striped_matrix(nrows: usize, ncols: usize) -> Owned<usize> {
1857        Owned::from_fn(nrows, ncols, |rc| rc.row * 100 + rc.col)
1858    }
1859
1860    fn assert_exact_fused<I>(mut iter: I, expected: usize)
1861    where
1862        I: ExactSizeIterator + std::iter::FusedIterator,
1863    {
1864        assert_eq!(iter.len(), expected);
1865        assert_eq!(iter.size_hint(), (expected, Some(expected)));
1866
1867        for remaining in (0..expected).rev() {
1868            assert!(iter.next().is_some());
1869            assert_eq!(iter.len(), remaining);
1870            assert_eq!(iter.size_hint(), (remaining, Some(remaining)));
1871        }
1872
1873        assert!(iter.next().is_none());
1874        assert!(iter.next().is_none());
1875        assert_eq!(iter.len(), 0);
1876        assert_eq!(iter.size_hint(), (0, Some(0)));
1877    }
1878
1879    /// Assert that the collection of rows matches the rows in `m`.
1880    fn assert_rows_match_scalar(m: Ref<'_, usize>, rows: Vec<&[usize]>) {
1881        let context = lazy_format!("nrows = {}, ncols = {}", m.nrows(), m.ncols());
1882
1883        assert_eq!(rows.len(), m.nrows(), "{context}");
1884
1885        for (row_index, row) in rows.into_iter().enumerate() {
1886            assert_eq!(row.len(), m.ncols(), "row = {row_index} -- {context}");
1887            for (col_index, value) in row.iter().enumerate() {
1888                assert_eq!(
1889                    value,
1890                    m.element(row_index, col_index),
1891                    "row = {row_index}, col = {col_index} -- {context}"
1892                );
1893            }
1894        }
1895    }
1896
1897    fn assert_windows_match_scalar(
1898        m: Ref<'_, usize>,
1899        batchsize: usize,
1900        windows: Vec<Ref<'_, usize>>,
1901    ) {
1902        let context = lazy_format!(
1903            "nrows = {}, ncols = {}, batchsize = {batchsize}",
1904            m.nrows(),
1905            m.ncols()
1906        );
1907
1908        assert_eq!(windows.len(), m.nrows().div_ceil(batchsize), "{context}");
1909
1910        for (window_index, window) in windows.into_iter().enumerate() {
1911            let window_context = lazy_format!("window = {window_index} -- {context}");
1912            let first_row = window_index * batchsize;
1913            let expected_rows = batchsize.min(m.nrows() - first_row);
1914            assert_eq!(window.nrows(), expected_rows, "{window_context}");
1915            assert_eq!(window.ncols(), m.ncols(), "{window_context}");
1916
1917            for row_index in 0..window.nrows() {
1918                for col_index in 0..window.ncols() {
1919                    assert_eq!(
1920                        window.element(row_index, col_index),
1921                        m.element(first_row + row_index, col_index),
1922                        "row = {row_index}, col = {col_index} -- {window_context}"
1923                    );
1924                }
1925            }
1926        }
1927    }
1928
1929    #[cfg(all(not(miri), feature = "rayon"))]
1930    fn assert_parallel_rows_match_scalar(m: Ref<'_, usize>) {
1931        let rows: Vec<_> = m.par_rows().collect();
1932        assert_rows_match_scalar(m, rows);
1933    }
1934
1935    #[cfg(all(not(miri), feature = "rayon"))]
1936    fn assert_parallel_windows_match_scalar(m: Ref<'_, usize>, batchsize: usize) {
1937        let windows: Vec<_> = m.par_window_iter(batchsize).collect();
1938        assert_windows_match_scalar(m, batchsize, windows);
1939    }
1940
1941    /// This expects `m` to look like the result s of [`make_test_matrix`].
1942    fn test_basic_indexing<T>(m: &T)
1943    where
1944        T: Matrix<Element = usize> + Sync,
1945    {
1946        assert_eq!(m.nrows(), 4);
1947        assert_eq!(m.ncols(), 3);
1948
1949        // Basic indexing
1950        assert_eq!(*m.element(0, 0), 0);
1951        assert_eq!(*m.element(0, 1), 1);
1952        assert_eq!(*m.element(0, 2), 2);
1953
1954        assert_eq!(*m.element(1, 0), 1);
1955        assert_eq!(*m.element(1, 1), 2);
1956        assert_eq!(*m.element(1, 2), 3);
1957
1958        assert_eq!(*m.element(2, 0), 2);
1959        assert_eq!(*m.element(2, 1), 3);
1960        assert_eq!(*m.element(2, 2), 4);
1961
1962        assert_eq!(*m.element(3, 0), 3);
1963        assert_eq!(*m.element(3, 1), 4);
1964        assert_eq!(*m.element(3, 2), 5);
1965
1966        assert_eq!(*m.get_element(0, 0).unwrap(), 0);
1967        assert_eq!(*m.get_element(0, 1).unwrap(), 1);
1968        assert_eq!(*m.get_element(0, 2).unwrap(), 2);
1969
1970        assert_eq!(*m.get_element(1, 0).unwrap(), 1);
1971        assert_eq!(*m.get_element(1, 1).unwrap(), 2);
1972        assert_eq!(*m.get_element(1, 2).unwrap(), 3);
1973
1974        assert_eq!(*m.get_element(2, 0).unwrap(), 2);
1975        assert_eq!(*m.get_element(2, 1).unwrap(), 3);
1976        assert_eq!(*m.get_element(2, 2).unwrap(), 4);
1977
1978        assert_eq!(*m.get_element(3, 0).unwrap(), 3);
1979        assert_eq!(*m.get_element(3, 1).unwrap(), 4);
1980        assert_eq!(*m.get_element(3, 2).unwrap(), 5);
1981
1982        // Row indexing.
1983        assert_eq!(m.row(0), &[0, 1, 2]);
1984        assert_eq!(m.row(1), &[1, 2, 3]);
1985        assert_eq!(m.row(2), &[2, 3, 4]);
1986        assert_eq!(m.row(3), &[3, 4, 5]);
1987
1988        let rows: Vec<Vec<usize>> = m.rows().map(|x| x.to_vec()).collect();
1989        assert_eq!(m.row(0), &rows[0]);
1990        assert_eq!(m.row(1), &rows[1]);
1991        assert_eq!(m.row(2), &rows[2]);
1992        assert_eq!(m.row(3), &rows[3]);
1993
1994        // Window Iters.
1995        let batchsize = 2;
1996        m.window_iter(NonZeroUsize::new(batchsize).unwrap())
1997            .enumerate()
1998            .for_each(|(i, submatrix)| {
1999                assert_eq!(submatrix.nrows(), batchsize);
2000                assert_eq!(submatrix.ncols(), m.ncols());
2001
2002                // Make sure we are in the correct window of the original matrix.
2003                let base = i * batchsize;
2004                assert_eq!(*submatrix.element(0, 0), base);
2005                assert_eq!(*submatrix.element(0, 1), base + 1);
2006                assert_eq!(*submatrix.element(0, 2), base + 2);
2007
2008                assert_eq!(*submatrix.element(1, 0), base + 1);
2009                assert_eq!(*submatrix.element(1, 1), base + 2);
2010                assert_eq!(*submatrix.element(1, 2), base + 3);
2011            });
2012
2013        // Try again, but with a batch size of 3 to ensure that we correctly handle cases
2014        // where the last block is under-sized.
2015        let batchsize = 3;
2016        m.window_iter(NonZeroUsize::new(batchsize).unwrap())
2017            .enumerate()
2018            .for_each(|(i, submatrix)| {
2019                if i == 0 {
2020                    assert_eq!(submatrix.nrows(), batchsize);
2021                    assert_eq!(submatrix.ncols(), m.ncols());
2022
2023                    // Check indexing
2024                    assert_eq!(*submatrix.element(0, 0), 0);
2025                    assert_eq!(*submatrix.element(0, 1), 1);
2026                    assert_eq!(*submatrix.element(0, 2), 2);
2027
2028                    assert_eq!(*submatrix.element(1, 0), 1);
2029                    assert_eq!(*submatrix.element(1, 1), 2);
2030                    assert_eq!(*submatrix.element(1, 2), 3);
2031
2032                    assert_eq!(*submatrix.element(2, 0), 2);
2033                    assert_eq!(*submatrix.element(2, 1), 3);
2034                    assert_eq!(*submatrix.element(2, 2), 4);
2035                } else {
2036                    assert_eq!(submatrix.nrows(), 1);
2037                    assert_eq!(submatrix.ncols(), m.ncols());
2038
2039                    // Check indexing
2040                    assert_eq!(*submatrix.element(0, 0), 3);
2041                    assert_eq!(*submatrix.element(0, 1), 4);
2042                    assert_eq!(*submatrix.element(0, 2), 5);
2043                }
2044            });
2045    }
2046
2047    #[test]
2048    fn matrix_happy_path() {
2049        let data = make_test_matrix();
2050        let m = Owned::try_from_data(data.into(), 4, 3).unwrap();
2051        test_basic_indexing(&m);
2052
2053        // Get the base pointer of the matrix and make sure view-conversion preserves this
2054        // value.
2055        let ptr = m.as_ptr();
2056        let view = m.as_view();
2057        assert!(is_copyable(view));
2058        assert_eq!(view.as_ptr(), ptr);
2059        assert_eq!(view.nrows(), m.nrows());
2060        assert_eq!(view.ncols(), m.ncols());
2061        test_basic_indexing(&view);
2062    }
2063
2064    #[test]
2065    fn matrix_try_from_construction_error() {
2066        let data = make_test_matrix();
2067        let ptr = data.as_ptr();
2068        let len = data.len();
2069
2070        let m = Owned::try_from_data(data.into(), 5, 4);
2071        assert!(m.is_err());
2072        let err = m.unwrap_err();
2073        assert_eq!(
2074            err.to_string(),
2075            "tried to construct a 5x4 matrix over a span of length 12"
2076        );
2077
2078        // Make sure that we can retrieve the original allocation from the interior.
2079        let data = err.into_inner();
2080        assert_eq!(data.as_ptr(), ptr);
2081        assert_eq!(data.len(), len);
2082
2083        let m = Ref::try_from_data(&data, 5, 4);
2084        assert!(m.is_err());
2085        assert_eq!(
2086            m.unwrap_err().to_string(),
2087            "tried to construct a 5x4 matrix over a span of length 12"
2088        );
2089    }
2090
2091    #[test]
2092    fn mutable_matrix_direct_construction() {
2093        let mut data = make_test_matrix();
2094
2095        {
2096            let mut m = Mut::try_from_data(data.as_mut_slice(), 4, 3).unwrap();
2097            *m.element_mut(1, 2) = 30;
2098        }
2099        assert_eq!(data[5], 30);
2100
2101        let err = Mut::try_from_data(data.as_mut_slice(), 5, 4).unwrap_err();
2102        assert_eq!(
2103            err.to_string(),
2104            "tried to construct a 5x4 matrix over a span of length 12"
2105        );
2106        let recovered = err.into_inner();
2107        recovered[0] = 10;
2108        assert_eq!(data[0], 10);
2109    }
2110
2111    #[test]
2112    fn matrix_mut_view() {
2113        let mut m = Owned::<usize>::from_element(4, 3, 0);
2114        assert_eq!(m.nrows(), 4);
2115        assert_eq!(m.ncols(), 3);
2116        assert!(m.as_slice().iter().all(|&i| i == 0));
2117        let ptr = m.as_ptr();
2118        let mut_ptr = m.as_mut_ptr();
2119        assert_eq!(ptr, mut_ptr);
2120
2121        let mut view = m.as_view_mut();
2122        assert_eq!(view.nrows(), 4);
2123        assert_eq!(view.ncols(), 3);
2124        assert_eq!(view.as_ptr(), ptr);
2125        assert_eq!(view.as_mut_ptr(), mut_ptr);
2126
2127        // Construct the test matrix manually.
2128        for i in 0..view.nrows() {
2129            for j in 0..view.ncols() {
2130                *view.element_mut(i, j) = i + j;
2131            }
2132        }
2133
2134        // Drop the view and test the original matrix.
2135        test_basic_indexing(&m);
2136
2137        // Check `PartialEq`.
2138        let mut m_clone = m.clone();
2139        assert_eq!(m.as_view_mut(), m_clone.as_view_mut());
2140
2141        let inner = m.into_inner();
2142        assert_eq!(inner.as_ptr(), ptr);
2143        assert_eq!(inner.len(), 4 * 3);
2144    }
2145
2146    #[test]
2147    fn matrix_view_zero_sizes() {
2148        let data: Vec<usize> = vec![];
2149        // Zero rows, but non-zero columns.
2150        let m = Ref::try_from_data(data.as_slice(), 0, 10).unwrap();
2151        assert_eq!(m.nrows(), 0);
2152        assert_eq!(m.ncols(), 10);
2153
2154        // Non-zero rows, but zero columns.
2155        let m = Ref::try_from_data(data.as_slice(), 3, 0).unwrap();
2156        assert_eq!(m.nrows(), 3);
2157        assert_eq!(m.ncols(), 0);
2158        let empty: &[usize] = &[];
2159        assert_eq!(m.row(0), empty);
2160        assert_eq!(m.row(1), empty);
2161        assert_eq!(m.row(2), empty);
2162
2163        // Zero rows and columns.
2164        let m = Ref::try_from_data(data.as_slice(), 0, 0).unwrap();
2165        assert_eq!(m.nrows(), 0);
2166        assert_eq!(m.ncols(), 0);
2167    }
2168
2169    #[test]
2170    fn matrix_construction_by_row() {
2171        let mut m = Owned::<usize>::from_element(4, 3, 0);
2172        assert!(m.as_slice().iter().all(|i| *i == 0));
2173
2174        let ncols = m.ncols();
2175        for i in 0..m.nrows() {
2176            let row = m.row_mut(i);
2177            assert_eq!(row.len(), ncols);
2178            row[0] = i;
2179            row[1] = i + 1;
2180            row[2] = i + 2;
2181        }
2182        test_basic_indexing(&m);
2183    }
2184
2185    // Panics
2186    #[test]
2187    #[should_panic(expected = "tried to access row 3 of a matrix with 3 rows")]
2188    fn test_get_row_panics() {
2189        let m = Owned::<usize>::from_element(3, 7, 0);
2190        m.row(3);
2191    }
2192
2193    #[test]
2194    #[should_panic(expected = "tried to access row 3 of a matrix with 3 rows")]
2195    fn test_get_row_mut_panics() {
2196        let mut m = Owned::<usize>::from_element(3, 7, 0);
2197        m.row_mut(3);
2198    }
2199
2200    #[test]
2201    #[should_panic(expected = "row 3 is out of bounds (max: 3)")]
2202    fn test_element_panics_row() {
2203        let m = Owned::<usize>::from_element(3, 7, 0);
2204        assert!(m.get_element(3, 2).is_none());
2205        let _ = m.element(3, 2);
2206    }
2207
2208    #[test]
2209    #[should_panic(expected = "col 7 is out of bounds (max: 7)")]
2210    fn test_element_panics_col() {
2211        let m = Owned::<usize>::from_element(3, 7, 0);
2212        assert!(m.get_element(2, 7).is_none());
2213        let _ = m.element(2, 7);
2214    }
2215
2216    #[test]
2217    #[should_panic(expected = "row 3 is out of bounds (max: 3)")]
2218    fn test_element_mut_panics_row() {
2219        let mut m = Owned::<usize>::from_element(3, 7, 0);
2220        assert!(m.get_element_mut(3, 2).is_none());
2221        *m.element_mut(3, 2) = 1;
2222    }
2223
2224    #[test]
2225    #[should_panic(expected = "col 7 is out of bounds (max: 7)")]
2226    fn test_element_mut_panics_col() {
2227        let mut m = Owned::<usize>::from_element(3, 7, 0);
2228        assert!(m.get_element_mut(2, 7).is_none());
2229        *m.element_mut(2, 7) = 1;
2230    }
2231
2232    #[test]
2233    #[cfg(feature = "rayon")]
2234    #[should_panic(expected = "par_window_iter batchsize cannot be zero")]
2235    fn test_par_window_iter_panics() {
2236        let m = Owned::<usize>::from_element(4, 4, 0);
2237        let _ = m.par_window_iter(0);
2238    }
2239
2240    #[test]
2241    #[cfg(feature = "rayon")]
2242    #[should_panic(expected = "par_window_iter_mut batchsize cannot be zero")]
2243    fn test_par_window_iter_mut_panics() {
2244        let mut m = Owned::<usize>::from_element(4, 4, 0);
2245        let _ = m.par_window_iter_mut(0);
2246    }
2247
2248    // Additional tests for better coverage
2249
2250    #[test]
2251    fn test_try_from_error_light() {
2252        // Incorrect slice
2253        let data = vec![1, 2, 3];
2254        let err = Ref::try_from_data(data.as_slice(), 2, 3).unwrap_err();
2255
2256        // Test `as_static` method
2257        let err_static = err.as_static();
2258        let msg = err_static.to_string();
2259        assert_contains!(
2260            msg,
2261            "tried to construct a 2x3 matrix over a span of length 3",
2262        );
2263        // Test `into_inner` method
2264        let recovered_data = err.into_inner();
2265        assert_eq!(recovered_data, data.as_slice());
2266
2267        // Invalid length.
2268        let err = Ref::try_from_data(data.as_slice(), 2, usize::MAX).unwrap_err();
2269        let msg = err.to_string();
2270        assert_contains!(msg, "usize::MAX");
2271
2272        assert_eq!(data.as_slice(), err.into_inner());
2273    }
2274
2275    #[test]
2276    fn test_map_errors() {
2277        #[derive(Debug, Clone, Copy)]
2278        struct Zst;
2279
2280        // Create a large ZST slice without taking forever on debug builds.
2281        let b = Box::<[Zst]>::new_uninit_slice((isize::MAX as usize) + 1);
2282
2283        // SAFETY: `b` has zero-sized elements, so all elements are initialized.
2284        let b = unsafe { b.assume_init() };
2285
2286        let m = Owned::column_vector(b);
2287        let err = m.try_map(|_: &Zst| 0u8).unwrap_err();
2288        let msg = err.to_string();
2289        assert!(msg.contains("isize::MAX"), "{msg}");
2290
2291        // Panicking variant.
2292        let err = std::panic::catch_unwind(|| m.map(|_: &Zst| 0u8))
2293            .unwrap_err()
2294            .downcast::<String>()
2295            .unwrap();
2296        let msg = err.to_string();
2297        assert!(msg.contains("isize::MAX"), "{msg}");
2298    }
2299
2300    #[test]
2301    fn test_get_row_optional() {
2302        let data = make_test_matrix();
2303        let mut m = Owned::try_from_data(data.into(), 4, 3).unwrap();
2304
2305        assert_eq!(m.get_row(0), Some(&[0, 1, 2][..]));
2306        assert_eq!(m.get_row(1), Some(&[1, 2, 3][..]));
2307        assert_eq!(m.get_row(3), Some(&[3, 4, 5][..]));
2308        assert_eq!(m.get_row(4), None);
2309        assert_eq!(m.get_row(100), None);
2310
2311        let row = m.get_row_mut(1).unwrap();
2312        assert_eq!(row, &[1, 2, 3]);
2313        row[0] = 10;
2314        assert_eq!(m.row(1), &[10, 2, 3]);
2315        assert!(m.get_row_mut(4).is_none());
2316        assert!(m.get_row_mut(100).is_none());
2317    }
2318
2319    #[test]
2320    fn test_unsafe_get_unchecked_methods() {
2321        let data = make_test_matrix();
2322        let mut m = Owned::try_from_data(data.into(), 4, 3).unwrap();
2323
2324        // Safety: derives from known size of matrix and access element ids
2325        unsafe {
2326            assert_eq!(*m.element_unchecked(0, 0), 0);
2327            assert_eq!(*m.element_unchecked(1, 2), 3);
2328            assert_eq!(*m.element_unchecked(3, 1), 4);
2329        }
2330
2331        // Safety: derives from known size of matrix and access element ids
2332        unsafe {
2333            *m.element_unchecked_mut(0, 0) = 100;
2334            *m.element_unchecked_mut(1, 2) = 200;
2335        }
2336
2337        assert_eq!(*m.element(0, 0), 100);
2338        assert_eq!(*m.element(1, 2), 200);
2339
2340        // Safety: derives from known size of matrix and access element ids
2341        unsafe {
2342            let row0 = m.row_unchecked(0);
2343            assert_eq!(row0[0], 100);
2344            assert_eq!(row0[1], 1);
2345            assert_eq!(row0[2], 2);
2346        }
2347
2348        // Safety: derives from known size of matrix and access element ids
2349        unsafe {
2350            let row1 = m.row_unchecked_mut(1);
2351            row1[0] = 300;
2352        }
2353
2354        assert_eq!(*m.element(1, 0), 300);
2355    }
2356
2357    #[test]
2358    fn test_to_owned() {
2359        let data = make_test_matrix();
2360        let view = Ref::try_from_data(data.as_slice(), 4, 3).unwrap();
2361
2362        // Test to_owned creates a proper clone
2363        let owned: Owned<_> = view.to_rowmajor_owned();
2364        assert_eq!(owned.nrows(), view.nrows());
2365        assert_eq!(owned.ncols(), view.ncols());
2366        assert_eq!(owned.as_slice(), view.as_slice());
2367
2368        // Verify it's actually owned (different memory location)
2369        assert_ne!(owned.as_ptr(), view.as_ptr());
2370
2371        // Test the owned matrix works properly
2372        test_basic_indexing(&owned);
2373    }
2374
2375    #[test]
2376    fn test_matrix_from_conversions() {
2377        let data = make_test_matrix();
2378        let m = Owned::try_from_data(data.into(), 4, 3).unwrap();
2379
2380        // Test Ref to slice conversion
2381        let view = m.as_view();
2382        let slice: &[usize] = view.into_slice();
2383        assert_eq!(slice.len(), 12);
2384        assert_eq!(slice[0], 0);
2385        assert_eq!(slice[11], 5);
2386
2387        // Test Mut to mutable slice conversion.
2388        let data2 = make_test_matrix();
2389        let mut m2 = Owned::try_from_data(data2.into(), 4, 3).unwrap();
2390        let mut_view = m2.as_view_mut();
2391        let slice2: &mut [usize] = mut_view.into_mut_slice();
2392        assert_eq!(slice2.len(), 12);
2393        assert_eq!(slice2[0], 0);
2394        assert_eq!(slice2[11], 5);
2395        slice2[11] = 6;
2396        assert_eq!(*m2.element(3, 2), 6);
2397    }
2398
2399    #[test]
2400    fn test_row_vector() {
2401        let data = vec![1, 2, 3];
2402        let m = Ref::row_vector(data.as_slice());
2403        assert_eq!(m.nrows(), 1);
2404        assert_eq!(m.ncols(), 3);
2405        assert_eq!(m.as_slice(), &[1, 2, 3]);
2406        assert_eq!(m.row(0), &[1, 2, 3]);
2407
2408        // Empty
2409        let empty: &[i32] = &[];
2410        let m = Ref::row_vector(empty);
2411        assert_eq!(m.nrows(), 1);
2412        assert_eq!(m.ncols(), 0);
2413
2414        // Owned
2415        let m = Owned::row_vector(vec![10u64, 20].into_boxed_slice());
2416        assert_eq!(m.nrows(), 1);
2417        assert_eq!(m.ncols(), 2);
2418        assert_eq!(*m.element(0, 0), 10);
2419        assert_eq!(*m.element(0, 1), 20);
2420    }
2421
2422    #[test]
2423    fn test_column_vector() {
2424        let data = vec![1, 2, 3];
2425        let m = Ref::column_vector(data.as_slice());
2426        assert_eq!(m.nrows(), 3);
2427        assert_eq!(m.ncols(), 1);
2428        assert_eq!(m.as_slice(), &[1, 2, 3]);
2429        assert_eq!(*m.element(0, 0), 1);
2430        assert_eq!(*m.element(1, 0), 2);
2431        assert_eq!(*m.element(2, 0), 3);
2432        assert_eq!(m.row(0), &[1]);
2433        assert_eq!(m.row(1), &[2]);
2434        assert_eq!(m.row(2), &[3]);
2435
2436        // Empty
2437        let empty: &[i32] = &[];
2438        let m = Ref::column_vector(empty);
2439        assert_eq!(m.nrows(), 0);
2440        assert_eq!(m.ncols(), 1);
2441
2442        // Owned
2443        let m = Owned::column_vector(vec![10u64, 20].into_boxed_slice());
2444        assert_eq!(m.nrows(), 2);
2445        assert_eq!(m.ncols(), 1);
2446        assert_eq!(*m.element(0, 0), 10);
2447        assert_eq!(*m.element(1, 0), 20);
2448    }
2449
2450    #[test]
2451    fn test_map() {
2452        let m = Owned::try_from_data(vec![1u32, 2, 3, 4].into(), 2, 2).unwrap();
2453        let doubled = m.map(|&x| x * 2);
2454        assert_eq!(doubled.as_slice(), &[2, 4, 6, 8]);
2455        assert_eq!(doubled.nrows(), 2);
2456        assert_eq!(doubled.ncols(), 2);
2457
2458        // Type-changing map
2459        let as_f64 = m.map(|&x| x as f64);
2460        assert_eq!(as_f64.as_slice(), &[1.0, 2.0, 3.0, 4.0]);
2461    }
2462
2463    #[test]
2464    fn test_get_element() {
2465        let mut m = Owned::try_from_data(vec![1, 2, 3, 4, 5, 6].into(), 2, 3).unwrap();
2466        assert_eq!(m.get_element(0, 0), Some(&1));
2467        assert_eq!(m.get_element(1, 2), Some(&6));
2468        assert_eq!(m.get_element(2, 0), None);
2469        assert_eq!(m.get_element(0, 3), None);
2470
2471        *m.get_element_mut(1, 2).unwrap() = 7;
2472        assert_eq!(m.get_element(1, 2), Some(&7));
2473        assert_eq!(m.get_element_mut(2, 0), None);
2474        assert_eq!(m.get_element_mut(0, 3), None);
2475    }
2476
2477    /// Return `m.subview(rows)` after checking that `m.subview_mut(rows)` selects the same
2478    /// span of `m`.
2479    fn check_subviews<T>(m: &mut Owned<T>, rows: std::ops::Range<usize>) -> Option<Ref<'_, T>> {
2480        let expected = m
2481            .subview_mut(rows.clone())
2482            .map(|v| (v.as_ptr(), v.layout()));
2483        let subview = m.subview(rows);
2484        assert_eq!(subview.map(|v| (v.as_ptr(), v.layout())), expected);
2485        subview
2486    }
2487
2488    #[test]
2489    fn test_subviews() {
2490        let data = make_test_matrix();
2491        let mut m = Owned::try_from_data(data.into(), 4, 3).unwrap();
2492
2493        // Create a subview of the first two rows
2494        {
2495            let subview = check_subviews(&mut m, 0..4).unwrap();
2496            assert_eq!(subview.nrows(), 4);
2497            assert_eq!(subview.ncols(), 3);
2498
2499            assert_eq!(subview.row(0), &[0, 1, 2]);
2500            assert_eq!(subview.row(1), &[1, 2, 3]);
2501            assert_eq!(subview.row(2), &[2, 3, 4]);
2502            assert_eq!(subview.row(3), &[3, 4, 5]);
2503            assert!(subview.get_row(4).is_none());
2504        }
2505
2506        // Sub view over a subset that touches the end.
2507        {
2508            let subview = check_subviews(&mut m, 1..4).unwrap();
2509            assert_eq!(subview.nrows(), 3);
2510            assert_eq!(subview.ncols(), 3);
2511
2512            assert_eq!(subview.row(0), &[1, 2, 3]);
2513            assert_eq!(subview.row(1), &[2, 3, 4]);
2514            assert_eq!(subview.row(2), &[3, 4, 5]);
2515            assert!(subview.get_row(3).is_none());
2516        }
2517
2518        // Empty subview in the middle.
2519        {
2520            let subview = check_subviews(&mut m, 2..2).unwrap();
2521            assert_eq!(subview.nrows(), 0);
2522            assert_eq!(subview.ncols(), 3);
2523        }
2524
2525        // Empty subviews at both boundaries.
2526        {
2527            let subview = check_subviews(&mut m, 0..0).unwrap();
2528            assert_eq!(subview.nrows(), 0);
2529            assert_eq!(subview.ncols(), 3);
2530
2531            let subview = check_subviews(&mut m, 4..4).unwrap();
2532            assert_eq!(subview.nrows(), 0);
2533            assert_eq!(subview.ncols(), 3);
2534        }
2535
2536        // Empty out-of-bounds subview
2537        assert!(check_subviews(&mut m, 5..5).is_none());
2538
2539        // End is out of bounds.
2540        assert!(check_subviews(&mut m, 2..10).is_none());
2541
2542        // Reversed bounds.
2543        #[expect(
2544            clippy::reversed_empty_ranges,
2545            reason = "we want to make sure it doesn't work"
2546        )]
2547        let empty = 3..2;
2548        assert!(check_subviews(&mut m, empty).is_none());
2549
2550        // Extreme out-of-bounds values do not overflow internal calculations.
2551        assert!(check_subviews(&mut m, usize::MAX - 1..usize::MAX).is_none());
2552
2553        // Writes through (nested) mutable subviews land only in the selected parent rows.
2554        {
2555            let mut outer = m.subview_mut(1..4).unwrap();
2556            outer.row_mut(0).copy_from_slice(&[10, 11, 12]);
2557
2558            let mut inner = outer.subview_mut(1..2).unwrap();
2559            assert_eq!(inner.row(0), &[2, 3, 4]);
2560            inner.as_mut_slice().fill(7);
2561        }
2562        assert_eq!(m.as_slice(), &[0, 1, 2, 10, 11, 12, 7, 7, 7, 3, 4, 5]);
2563    }
2564
2565    #[expect(
2566        clippy::reversed_empty_ranges,
2567        reason = "we want to make sure it doesn't work"
2568    )]
2569    #[test]
2570    fn test_subview_zero_cols() {
2571        let mut m = Owned::from_element(10, 0, 0u32);
2572
2573        // A fully disjoint range is rejected.
2574        assert!(check_subviews(&mut m, 100..200).is_none());
2575
2576        // A range extending one row beyond the matrix is rejected.
2577        assert!(check_subviews(&mut m, 10..11).is_none());
2578
2579        // Reversed bounds are rejected.
2580        assert!(check_subviews(&mut m, 5..4).is_none());
2581
2582        // An in-bounds suffix preserves its logical shape.
2583        let v = check_subviews(&mut m, 5..10).unwrap();
2584        assert_eq!(v.nrows(), 5);
2585        assert_eq!(v.ncols(), 0);
2586
2587        // An empty range at the end is valid.
2588        let v = check_subviews(&mut m, 10..10).unwrap();
2589        assert_eq!(v.nrows(), 0);
2590        assert_eq!(v.ncols(), 0);
2591
2592        // The full range preserves all logical rows despite having no elements.
2593        let v = check_subviews(&mut m, 0..10).unwrap();
2594        assert_eq!(v.nrows(), 10);
2595        assert_eq!(v.ncols(), 0);
2596    }
2597
2598    #[test]
2599    #[cfg(all(not(miri), feature = "rayon"))]
2600    fn parallel_immutable_iterators_match_scalar_indexing() {
2601        for (nrows, ncols) in [(0, 0), (0, 4), (3, 0), (1, 1), (1, 4), (4, 1), (5, 3)] {
2602            let m = striped_matrix(nrows, ncols);
2603            let view = m.as_view();
2604
2605            assert_parallel_rows_match_scalar(view);
2606            for batchsize in [1, 2, 3, usize::MAX] {
2607                assert_parallel_windows_match_scalar(view, batchsize);
2608            }
2609        }
2610    }
2611
2612    #[test]
2613    #[cfg(all(not(miri), feature = "rayon"))]
2614    fn parallel_mutable_iterators_match_scalar_indexing() {
2615        use rayon::prelude::*;
2616
2617        for (nrows, ncols) in [(0, 0), (0, 4), (3, 0), (1, 1), (1, 4), (4, 1), (5, 3)] {
2618            let context = lazy_format!("nrows = {nrows}, ncols = {ncols}");
2619
2620            let original = striped_matrix(nrows, ncols);
2621            let mut rows = original.clone();
2622
2623            let row_views: Vec<_> = rows.par_rows_mut().collect();
2624            assert_eq!(row_views.len(), nrows, "{context}");
2625            for (row_index, row) in row_views.into_iter().enumerate() {
2626                assert_eq!(row.len(), ncols, "row = {row_index} -- {context}");
2627                for value in row {
2628                    *value = value.wrapping_add(row_index);
2629                }
2630            }
2631
2632            for row in 0..nrows {
2633                for col in 0..ncols {
2634                    assert_eq!(
2635                        *rows.element(row, col),
2636                        original.element(row, col).wrapping_add(row),
2637                        "row = {}, col = {} -- {}",
2638                        row,
2639                        col,
2640                        context,
2641                    );
2642                }
2643            }
2644
2645            for batchsize in [1, 2, 3, usize::MAX] {
2646                let context = lazy_format!("{context}, batchsize = {batchsize}");
2647
2648                let mut windows = original.clone();
2649                let window_views: Vec<_> = windows.par_window_iter_mut(batchsize).collect();
2650                assert_eq!(window_views.len(), nrows.div_ceil(batchsize), "{context}");
2651                for (window_index, mut window) in window_views.into_iter().enumerate() {
2652                    let first_row = window_index * batchsize;
2653                    assert_eq!(
2654                        window.nrows(),
2655                        batchsize.min(nrows - first_row),
2656                        "window = {window_index} -- {context}"
2657                    );
2658                    assert_eq!(
2659                        window.ncols(),
2660                        ncols,
2661                        "window = {window_index} -- {context}"
2662                    );
2663                    for value in window.as_mut_slice() {
2664                        *value = value.wrapping_add(window_index);
2665                    }
2666                }
2667
2668                for row in 0..nrows {
2669                    for col in 0..ncols {
2670                        assert_eq!(
2671                            *windows.element(row, col),
2672                            original.element(row, col).wrapping_add(row / batchsize),
2673                            "row = {}, col = {} -- {}",
2674                            row,
2675                            col,
2676                            context,
2677                        );
2678                    }
2679                }
2680            }
2681        }
2682    }
2683
2684    #[test]
2685    fn matrix_iterators_match_scalar_indexing() {
2686        for (nrows, ncols) in [(0, 0), (0, 4), (3, 0), (1, 1), (1, 4), (4, 1), (5, 3)] {
2687            let original = striped_matrix(nrows, ncols);
2688            let view = original.as_view();
2689
2690            let rows = view.rows().collect();
2691            assert_rows_match_scalar(view, rows);
2692            for batchsize in [1, 2, 3, usize::MAX] {
2693                let windows = view
2694                    .window_iter(NonZeroUsize::new(batchsize).unwrap())
2695                    .collect();
2696                assert_windows_match_scalar(view, batchsize, windows);
2697            }
2698
2699            let context = lazy_format!("nrows = {nrows}, ncols = {ncols}");
2700            let mut mutable = original.clone();
2701            let rows: Vec<_> = mutable.rows_mut().collect();
2702            assert_eq!(rows.len(), nrows, "{context}");
2703
2704            for (row_index, row) in rows.into_iter().enumerate() {
2705                assert_eq!(row.len(), ncols, "row = {row_index} -- {context}");
2706                for (col_index, value) in row.iter_mut().enumerate() {
2707                    assert_eq!(
2708                        *value,
2709                        *original.element(row_index, col_index),
2710                        "row = {row_index}, col = {col_index} -- {context}"
2711                    );
2712                    *value = value.wrapping_add(1);
2713                }
2714            }
2715
2716            for row in 0..nrows {
2717                for col in 0..ncols {
2718                    assert_eq!(
2719                        *mutable.element(row, col),
2720                        original.element(row, col).wrapping_add(1),
2721                        "row = {row}, col = {col} -- {context}"
2722                    );
2723                }
2724            }
2725        }
2726    }
2727
2728    #[test]
2729    fn matrix_iterators_track_exact_remaining_lengths() {
2730        for (nrows, ncols) in [(0, 0), (0, 4), (3, 0), (5, 3)] {
2731            let mut m = striped_matrix(nrows, ncols);
2732
2733            assert_exact_fused(m.rows(), nrows);
2734            assert_exact_fused(m.rows_mut(), nrows);
2735
2736            for batchsize in [1, 2, usize::MAX] {
2737                assert_exact_fused(
2738                    m.window_iter(NonZeroUsize::new(batchsize).unwrap()),
2739                    nrows.div_ceil(batchsize),
2740                );
2741            }
2742        }
2743    }
2744
2745    #[test]
2746    fn matrix_transformations_preserve_empty_shapes() {
2747        for (nrows, ncols) in [(0, 0), (0, 4), (3, 0)] {
2748            let m = striped_matrix(nrows, ncols);
2749
2750            let owned = m.to_rowmajor_owned();
2751            assert_eq!(owned.nrows(), nrows);
2752            assert_eq!(owned.ncols(), ncols);
2753
2754            let mapped = m.map(|_| -> u8 { unreachable!("empty matrix has no elements") });
2755            assert_eq!(mapped.nrows(), nrows);
2756            assert_eq!(mapped.ncols(), ncols);
2757        }
2758    }
2759
2760    #[test]
2761    fn owned_from_fn_initializes_in_memory_order() {
2762        let mut value = 0;
2763        let m = Owned::from_fn(2, 3, |_| {
2764            let result = value;
2765            value += 1;
2766            result
2767        });
2768
2769        assert_eq!(*m.element(0, 0), 0);
2770        assert_eq!(*m.element(0, 1), 1);
2771        assert_eq!(*m.element(0, 2), 2);
2772        assert_eq!(*m.element(1, 0), 3);
2773        assert_eq!(*m.element(1, 1), 4);
2774        assert_eq!(*m.element(1, 2), 5);
2775    }
2776
2777    #[test]
2778    fn test_transpose() {
2779        {
2780            let v = Owned::from_element(0, 0, 0);
2781            let t = v.transpose();
2782            assert_eq!(t.nrows(), 0);
2783            assert_eq!(t.ncols(), 0);
2784        }
2785
2786        {
2787            let v = Owned::from_element(0, 10, 0);
2788            let t = v.transpose();
2789            assert_eq!(t.nrows(), 10);
2790            assert_eq!(t.ncols(), 0);
2791        }
2792
2793        {
2794            let v = Owned::from_element(10, 0, 0);
2795            let t = v.transpose();
2796            assert_eq!(t.nrows(), 0);
2797            assert_eq!(t.ncols(), 10);
2798        }
2799
2800        {
2801            let v = Owned::<usize>::try_from_data(Box::new([1, 2, 3, 4, 5, 6]), 2, 3).unwrap();
2802            let t = v.transpose();
2803
2804            assert_eq!(t.row(0), &[1, 4]);
2805            assert_eq!(t.row(1), &[2, 5]);
2806            assert_eq!(t.row(2), &[3, 6]);
2807        }
2808    }
2809
2810    #[test]
2811    fn test_debug_error_formatting() {
2812        // Test Debug implementation for TryFromError
2813        let data = vec![1, 2, 3];
2814        let err = Owned::try_from_data(data.into(), 2, 3).unwrap_err();
2815        let debug_str = format!("{:?}", err);
2816        assert_contains!(debug_str, "TryFromError");
2817
2818        // Ensure Debug doesn't require T: Debug by using a non-Debug type
2819        #[derive(Clone)]
2820        struct NonDebug(#[expect(dead_code)] i32);
2821
2822        let non_debug_data: Box<[NonDebug]> = vec![NonDebug(1), NonDebug(2)].into();
2823        let non_debug_err = match Owned::try_from_data(non_debug_data, 1, 3) {
2824            Ok(_) => panic!("should not have succeeded!"),
2825            Err(err) => err,
2826        };
2827        let debug_str = format!("{:?}", non_debug_err);
2828        assert_contains!(debug_str, "TryFromError");
2829    }
2830}