Skip to main content

diskann_quantization/multi_vector/
matrix.rs

1/*
2 * Copyright (c) Microsoft Corporation.
3 * Licensed under the MIT license.
4 */
5
6//! Row-major matrix types for multi-vector representations.
7//!
8//! This module provides flexible matrix abstractions that support different underlying
9//! storage formats through the [`Repr`] trait. The primary types are:
10//!
11//! - [`Mat`]: An owning matrix that manages its own memory.
12//! - [`MatRef`]: An immutable borrowed view of matrix data.
13//! - [`MatMut`]: A mutable borrowed view of matrix data.
14//!
15//! # Representations
16//!
17//! Representation types interact with the [`Mat`] family of types using the following traits:
18//!
19//! - [`Repr`]: Read-only matrix representation.
20//! - [`ReprMut`]: Mutable matrix representation.
21//! - [`ReprOwned`]: Owning matrix representation.
22//!
23//! Each trait refinement has a corresponding constructor:
24//!
25//! - [`NewRef`]: Construct a read-only [`MatRef`] view over a slice.
26//! - [`NewMut`]: Construct a mutable [`MatMut`] matrix view over a slice.
27//! - [`NewOwned`]: Construct a new owning [`Mat`].
28//!
29
30use std::{alloc::Layout, iter::FusedIterator, marker::PhantomData, ptr::NonNull};
31
32use diskann_utils::{Reborrow, ReborrowMut, views::MatrixView};
33use thiserror::Error;
34
35use crate::utils;
36
37/// Representation trait describing the layout and access patterns for a matrix.
38///
39/// Implementations define how raw bytes are interpreted as typed rows. This enables
40/// matrices over different storage formats (dense, quantized, etc.) using a single
41/// generic [`Mat`] type.
42///
43/// # Associated Types
44///
45/// - `Row<'a>`: The immutable row type (e.g., `&[f32]`, `&[f16]`).
46///
47/// # Safety
48///
49/// Implementations must ensure:
50///
51/// - [`get_row`](Self::get_row) returns valid references for the given row index.
52///   This call **must** be memory safe for `i < self.nrows()`, provided the caller upholds
53///   the contract for the raw pointer.
54///
55/// - The objects implicitly managed by this representation inherit the `Send` and `Sync`
56///   attributes of `Repr`. That is, `Repr: Send` implies that the objects in backing memory
57///   are [`Send`], and likewise with `Sync`. This is necessary to apply [`Send`] and [`Sync`]
58///   bounds to [`Mat`], [`MatRef`], and [`MatMut`].
59pub unsafe trait Repr: Copy {
60    /// Immutable row reference type.
61    type Row<'a>
62    where
63        Self: 'a;
64
65    /// Returns the number of rows in the matrix.
66    ///
67    /// # Safety Contract
68    ///
69    /// This function must be loosely pure in the sense that for any given instance of
70    /// `self`, `self.nrows()` must return the same value.
71    fn nrows(&self) -> usize;
72
73    /// Returns the memory layout for an allocation containing [`Repr::nrows`] vectors.
74    ///
75    /// # Safety Contract
76    ///
77    /// The [`Layout`] returned from this method must be consistent with the contract of
78    /// [`Repr::get_row`].
79    fn layout(&self) -> Result<Layout, LayoutError>;
80
81    /// Returns an immutable reference to the `i`-th row.
82    ///
83    /// # Safety
84    ///
85    /// - `ptr` must point to a slice with a layout compatible with [`Repr::layout`].
86    /// - The entire range for this slice must be within a single allocation.
87    /// - `i` must be less than [`Repr::nrows`].
88    /// - The memory referenced by the returned [`Repr::Row`] must not be mutated for the
89    ///   duration of lifetime `'a`.
90    /// - The lifetime for the returned [`Repr::Row`] is inferred from its usage. Correct
91    ///   usage must properly tie the lifetime to a source.
92    unsafe fn get_row<'a>(self, ptr: NonNull<u8>, i: usize) -> Self::Row<'a>;
93}
94
95/// Extension of [`Repr`] that supports mutable row access.
96///
97/// # Associated Types
98///
99/// - `RowMut<'a>`: The mutable row type (e.g., `&mut [f32]`).
100///
101/// # Safety
102///
103/// Implementors must ensure:
104///
105/// - [`get_row_mut`](Self::get_row_mut) returns valid references for the given row index.
106///   This call **must** be memory safe for `i < self.nrows()`, provided the caller upholds
107///   the contract for the raw pointer.
108///
109///   Additionally, since the implementation of the [`RowsMut`] iterator can give out rows
110///   for all `i` in `0..self.nrows()`, the implementation of [`Self::get_row_mut`] must be
111///   such that the result for disjoint `i` must not interfere with one another.
112pub unsafe trait ReprMut: Repr {
113    /// Mutable row reference type.
114    type RowMut<'a>
115    where
116        Self: 'a;
117
118    /// Returns a mutable reference to the i-th row.
119    ///
120    /// # Safety
121    /// - `ptr` must point to a slice with a layout compatible with [`Repr::layout`].
122    /// - The entire range for this slice must be within a single allocation.
123    /// - `i` must be less than `self.nrows()`.
124    /// - The memory referenced by the returned [`ReprMut::RowMut`] must not be accessed
125    ///   through any other reference for the duration of lifetime `'a`.
126    /// - The lifetime for the returned [`ReprMut::RowMut`] is inferred from its usage.
127    ///   Correct usage must properly tie the lifetime to a source.
128    unsafe fn get_row_mut<'a>(self, ptr: NonNull<u8>, i: usize) -> Self::RowMut<'a>;
129}
130
131/// Extension trait for [`Repr`] that supports deallocation of owned matrices. This is used
132/// in conjunction with [`NewOwned`] to create matrices.
133///
134/// Requires [`ReprMut`] since owned matrices should support mutation.
135///
136/// # Safety
137///
138/// Implementors must ensure that `drop` properly deallocates the memory in a way compatible
139/// with all [`NewOwned`] implementations.
140pub unsafe trait ReprOwned: ReprMut {
141    /// Deallocates memory at `ptr` and drops `self`.
142    ///
143    /// # Safety
144    ///
145    /// - `ptr` must have been obtained via [`NewOwned`] with the same value of `self`.
146    /// - This method may only be called once for such a pointer.
147    /// - After calling this method, the memory behind `ptr` may not be dereferenced at all.
148    unsafe fn drop(self, ptr: NonNull<u8>);
149}
150
151/// A new-type version of `std::alloc::LayoutError` for cleaner error handling.
152///
153/// This is basically the same as [`std::alloc::LayoutError`], but constructible in
154/// use code to allow implementors of [`Repr::layout`] to return it for reasons other than
155/// those derived from `std::alloc::Layout`'s methods.
156#[derive(Debug, Clone, Copy)]
157#[non_exhaustive]
158pub struct LayoutError;
159
160impl LayoutError {
161    /// Construct a new opaque [`LayoutError`].
162    pub fn new() -> Self {
163        Self
164    }
165}
166
167impl Default for LayoutError {
168    fn default() -> Self {
169        Self::new()
170    }
171}
172
173impl std::fmt::Display for LayoutError {
174    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
175        write!(f, "LayoutError")
176    }
177}
178
179impl std::error::Error for LayoutError {}
180
181impl From<std::alloc::LayoutError> for LayoutError {
182    fn from(_: std::alloc::LayoutError) -> Self {
183        LayoutError
184    }
185}
186
187//////////////////
188// Constructors //
189//////////////////
190
191/// Create a new [`MatRef`] over a slice.
192///
193/// # Safety
194///
195/// Implementations must validate the length (and any other requirements) of the provided
196/// slice to ensure it is compatible with the implementation of [`Repr`].
197pub unsafe trait NewRef<T>: Repr {
198    /// Errors that can occur when initializing.
199    type Error;
200
201    /// Create a new [`MatRef`] over `slice`.
202    fn new_ref(self, slice: &[T]) -> Result<MatRef<'_, Self>, Self::Error>;
203}
204
205/// Create a new [`MatMut`] over a slice.
206///
207/// # Safety
208///
209/// Implementations must validate the length (and any other requirements) of the provided
210/// slice to ensure it is compatible with the implementation of [`ReprMut`].
211pub unsafe trait NewMut<T>: ReprMut {
212    /// Errors that can occur when initializing.
213    type Error;
214
215    /// Create a new [`MatMut`] over `slice`.
216    fn new_mut(self, slice: &mut [T]) -> Result<MatMut<'_, Self>, Self::Error>;
217}
218
219/// Create a new [`Mat`] from an initializer.
220///
221/// # Safety
222///
223/// Implementations must ensure that the returned [`Mat`] is compatible with
224/// `Self`'s implementation of [`ReprOwned`].
225pub unsafe trait NewOwned<T>: ReprOwned {
226    /// Errors that can occur when initializing.
227    type Error;
228
229    /// Create a new [`Mat`] initialized with `init`.
230    fn new_owned(self, init: T) -> Result<Mat<Self>, Self::Error>;
231}
232
233/// An initializer argument to [`NewOwned`] that uses a type's [`Default`] implementation
234/// to initialize a matrix.
235///
236/// ```rust
237/// use diskann_quantization::multi_vector::{Mat, Standard, Defaulted};
238/// let mat = Mat::new(Standard::<f32>::new(4, 3).unwrap(), Defaulted).unwrap();
239/// for i in 0..4 {
240///     assert!(mat.get_row(i).unwrap().iter().all(|&x| x == 0.0f32));
241/// }
242/// ```
243#[derive(Debug, Clone, Copy)]
244pub struct Defaulted;
245
246/// Create a new [`Mat`] cloned from a view.
247pub trait NewCloned: ReprOwned {
248    /// Clone the contents behind `v`, returning a new owning [`Mat`].
249    ///
250    /// Implementations should ensure the returned [`Mat`] is "semantically the same" as `v`.
251    fn new_cloned(v: MatRef<'_, Self>) -> Mat<Self>;
252}
253
254//////////////
255// Standard //
256//////////////
257
258/// Metadata for dense row-major matrices.
259///
260/// Rows are stored contiguously as `&[T]` slices. This is the default representation
261/// type for standard floating-point multi-vectors.
262///
263/// # Row Types
264///
265/// - `Row<'a>`: `&'a [T]`
266/// - `RowMut<'a>`: `&'a mut [T]`
267#[derive(Debug)]
268pub struct Standard<T> {
269    nrows: usize,
270    ncols: usize,
271    _elem: PhantomData<T>,
272}
273
274// Hand-written so `Standard<T>` is `Copy`/`Clone`/`PartialEq`/`Eq` for every `T`: it only
275// stores two `usize` and a `PhantomData<T>`, so derives would spuriously require the same
276// bound on `T` (and the `Repr: Copy` supertrait must hold regardless of the element type).
277impl<T> Copy for Standard<T> {}
278
279impl<T> Clone for Standard<T> {
280    fn clone(&self) -> Self {
281        *self
282    }
283}
284
285impl<T> PartialEq for Standard<T> {
286    fn eq(&self, other: &Self) -> bool {
287        self.nrows == other.nrows && self.ncols == other.ncols
288    }
289}
290
291impl<T> Eq for Standard<T> {}
292
293impl<T> Standard<T> {
294    /// Create a new `Standard` for data of type `T`.
295    ///
296    /// Successful construction requires:
297    ///
298    /// * The total number of elements determined by `nrows * ncols` does not exceed
299    ///   `usize::MAX`.
300    /// * The total memory footprint defined by `ncols * nrows * size_of::<T>()` does not
301    ///   exceed `isize::MAX`.
302    pub fn new(nrows: usize, ncols: usize) -> Result<Self, Overflow> {
303        Overflow::check::<T>(nrows, ncols)?;
304        Ok(Self {
305            nrows,
306            ncols,
307            _elem: PhantomData,
308        })
309    }
310
311    /// Returns the number of total elements (`rows x cols`) in this matrix.
312    pub fn num_elements(&self) -> usize {
313        // Since we've constructed `self` - we know we cannot overflow.
314        self.nrows() * self.ncols()
315    }
316
317    /// Returns `rows`, the number of rows in this matrix.
318    fn nrows(&self) -> usize {
319        self.nrows
320    }
321
322    /// Returns `ncols`, the number of elements in a row of this matrix.
323    fn ncols(&self) -> usize {
324        self.ncols
325    }
326
327    /// Checks the following:
328    ///
329    /// 1. Computation of the number of elements in `self` does not overflow.
330    /// 2. Argument `slice` has the expected number of elements.
331    fn check_slice(&self, slice: &[T]) -> Result<(), SliceError> {
332        let len = self.num_elements();
333
334        if slice.len() != len {
335            Err(SliceError::LengthMismatch {
336                expected: len,
337                found: slice.len(),
338            })
339        } else {
340            Ok(())
341        }
342    }
343
344    /// Create a new [`Mat`] around the contents of `b` **without** any checks.
345    ///
346    /// # Safety
347    ///
348    /// The length of `b` must be exactly [`Standard::num_elements`].
349    unsafe fn box_to_mat(self, b: Box<[T]>) -> Mat<Self> {
350        debug_assert_eq!(b.len(), self.num_elements(), "safety contract violated");
351
352        let ptr = utils::box_into_nonnull(b).cast::<u8>();
353
354        // SAFETY: `ptr` is properly aligned and points to a slice of the required length.
355        // Additionally, it is dropped via `Box::from_raw`, which is compatible with obtaining
356        // it from `Box::into_raw`.
357        unsafe { Mat::from_raw_parts(self, ptr) }
358    }
359}
360
361/// Error for [`Standard::new`].
362#[derive(Debug, Clone, Copy)]
363pub struct Overflow {
364    nrows: usize,
365    ncols: usize,
366    elsize: usize,
367}
368
369impl Overflow {
370    /// Construct an `Overflow` error for the given dimensions and element type.
371    pub(crate) fn for_type<T>(nrows: usize, ncols: usize) -> Self {
372        Self {
373            nrows,
374            ncols,
375            elsize: std::mem::size_of::<T>(),
376        }
377    }
378
379    /// Verify that `capacity` elements of type `T` fit within the `isize::MAX` byte
380    /// budget required by Rust's allocation APIs.
381    ///
382    /// On failure the error reports the original `(nrows, ncols)` dimensions rather
383    /// than the padded capacity.
384    pub(crate) fn check_byte_budget<T>(
385        capacity: usize,
386        nrows: usize,
387        ncols: usize,
388    ) -> Result<(), Self> {
389        let bytes = std::mem::size_of::<T>().saturating_mul(capacity);
390        if bytes <= isize::MAX as usize {
391            Ok(())
392        } else {
393            Err(Self::for_type::<T>(nrows, ncols))
394        }
395    }
396
397    pub(crate) fn check<T>(nrows: usize, ncols: usize) -> Result<(), Self> {
398        // Guard the element count itself so that `num_elements()` can never overflow.
399        let capacity = nrows
400            .checked_mul(ncols)
401            .ok_or_else(|| Self::for_type::<T>(nrows, ncols))?;
402
403        Self::check_byte_budget::<T>(capacity, nrows, ncols)
404    }
405}
406
407impl std::fmt::Display for Overflow {
408    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
409        if self.elsize == 0 {
410            write!(
411                f,
412                "ZST matrix with dimensions {} x {} has more than `usize::MAX` elements",
413                self.nrows, self.ncols,
414            )
415        } else {
416            write!(
417                f,
418                "a matrix of size {} x {} with element size {} would exceed isize::MAX bytes",
419                self.nrows, self.ncols, self.elsize,
420            )
421        }
422    }
423}
424
425impl std::error::Error for Overflow {}
426
427/// Error types for [`Standard`].
428#[derive(Debug, Clone, Copy, Error)]
429#[non_exhaustive]
430pub enum SliceError {
431    #[error("Length mismatch: expected {expected}, found {found}")]
432    LengthMismatch { expected: usize, found: usize },
433}
434
435// SAFETY: The implementation correctly computes row offsets as `i * ncols` and
436// constructs valid slices of the appropriate length. The `layout` method correctly
437// reports the memory layout requirements.
438unsafe impl<T> Repr for Standard<T> {
439    type Row<'a>
440        = &'a [T]
441    where
442        T: 'a;
443
444    fn nrows(&self) -> usize {
445        self.nrows
446    }
447
448    fn layout(&self) -> Result<Layout, LayoutError> {
449        Ok(Layout::array::<T>(self.num_elements())?)
450    }
451
452    unsafe fn get_row<'a>(self, ptr: NonNull<u8>, i: usize) -> Self::Row<'a> {
453        debug_assert!(ptr.cast::<T>().is_aligned());
454        debug_assert!(i < self.nrows);
455
456        // SAFETY: The caller asserts that `i` is less than `self.nrows()`. Since this type
457        // audits the constructors for `Mat` and friends, we know that there is room for at
458        // least `self.num_elements()` elements from the base pointer, so this access is safe.
459        let row_ptr = unsafe { ptr.as_ptr().cast::<T>().add(i * self.ncols) };
460
461        // SAFETY: The logic is the same as the previous `unsafe` block.
462        unsafe { std::slice::from_raw_parts(row_ptr, self.ncols) }
463    }
464}
465
466// SAFETY: The implementation correctly computes row offsets and constructs valid mutable
467// slices.
468unsafe impl<T> ReprMut for Standard<T> {
469    type RowMut<'a>
470        = &'a mut [T]
471    where
472        T: 'a;
473
474    unsafe fn get_row_mut<'a>(self, ptr: NonNull<u8>, i: usize) -> Self::RowMut<'a> {
475        debug_assert!(ptr.cast::<T>().is_aligned());
476        debug_assert!(i < self.nrows);
477
478        // SAFETY: The caller asserts that `i` is less than `self.nrows()`. Since this type
479        // audits the constructors for `Mat` and friends, we know that there is room for at
480        // least `self.num_elements()` elements from the base pointer, so this access is safe.
481        let row_ptr = unsafe { ptr.as_ptr().cast::<T>().add(i * self.ncols) };
482
483        // SAFETY: The logic is the same as the previous `unsafe` block. Further, the caller
484        // attests that creating a mutable reference is safe.
485        unsafe { std::slice::from_raw_parts_mut(row_ptr, self.ncols) }
486    }
487}
488
489// SAFETY: The drop implementation correctly reconstructs a Box from the raw pointer
490// using the same length (nrows * ncols) that was used for allocation, allowing Box
491// to properly deallocate the memory.
492unsafe impl<T> ReprOwned for Standard<T> {
493    unsafe fn drop(self, ptr: NonNull<u8>) {
494        // SAFETY: The caller guarantees that `ptr` was obtained from an implementation of
495        // `NewOwned` for an equivalent instance of `self`.
496        //
497        // We ensure that `NewOwned` goes through boxes, so here we reconstruct a Box to
498        // let it handle deallocation.
499        unsafe {
500            let slice_ptr = std::ptr::slice_from_raw_parts_mut(
501                ptr.cast::<T>().as_ptr(),
502                self.nrows * self.ncols,
503            );
504            let _ = Box::from_raw(slice_ptr);
505        }
506    }
507}
508
509// SAFETY: The implementation uses guarantees from `Box` to ensure that the pointer
510// initialized by it is non-null and properly aligned to the underlying type.
511unsafe impl<T> NewOwned<T> for Standard<T>
512where
513    T: Clone,
514{
515    type Error = crate::error::Infallible;
516    fn new_owned(self, value: T) -> Result<Mat<Self>, Self::Error> {
517        let b: Box<[T]> = std::iter::repeat_n(value, self.num_elements()).collect();
518
519        // SAFETY: By construction, `b` has length `self.num_elements()`.
520        Ok(unsafe { self.box_to_mat(b) })
521    }
522}
523
524// SAFETY: The implementation uses guarantees from `Box` to ensure that the pointer
525// initialized by it is non-null and properly aligned to the underlying type.
526unsafe impl<T> NewOwned<Defaulted> for Standard<T>
527where
528    T: Default,
529{
530    type Error = crate::error::Infallible;
531    fn new_owned(self, _: Defaulted) -> Result<Mat<Self>, Self::Error> {
532        let b: Box<[T]> = std::iter::repeat_with(T::default)
533            .take(self.num_elements())
534            .collect();
535
536        // SAFETY: By construction, `b` has length `self.num_elements()`.
537        Ok(unsafe { self.box_to_mat(b) })
538    }
539}
540
541// SAFETY: This checks that the slice has the correct length, which is all that is
542// required for [`Repr`].
543unsafe impl<T> NewRef<T> for Standard<T> {
544    type Error = SliceError;
545    fn new_ref(self, data: &[T]) -> Result<MatRef<'_, Self>, Self::Error> {
546        self.check_slice(data)?;
547
548        // SAFETY: The function `check_slice` verifies that `data` is compatible with
549        // the layout requirement of `Standard`.
550        //
551        // We've properly checked that the underlying pointer is okay.
552        Ok(unsafe { MatRef::from_raw_parts(self, utils::as_nonnull(data).cast::<u8>()) })
553    }
554}
555
556// SAFETY: This checks that the slice has the correct length, which is all that is
557// required for [`ReprMut`].
558unsafe impl<T> NewMut<T> for Standard<T> {
559    type Error = SliceError;
560    fn new_mut(self, data: &mut [T]) -> Result<MatMut<'_, Self>, Self::Error> {
561        self.check_slice(data)?;
562
563        // SAFETY: The function `check_slice` verifies that `data` is compatible with
564        // the layout requirement of `Standard`.
565        //
566        // We've properly checked that the underlying pointer is okay.
567        Ok(unsafe { MatMut::from_raw_parts(self, utils::as_nonnull_mut(data).cast::<u8>()) })
568    }
569}
570
571impl<T> NewCloned for Standard<T>
572where
573    T: Clone,
574{
575    fn new_cloned(v: MatRef<'_, Self>) -> Mat<Self> {
576        let b: Box<[T]> = v.as_slice().iter().cloned().collect();
577
578        // SAFETY: By construction, `b` has length `v.repr().num_elements()`.
579        unsafe { v.repr().box_to_mat(b) }
580    }
581}
582
583/////////
584// Mat //
585/////////
586
587/// An owning matrix that manages its own memory.
588///
589/// The matrix stores raw bytes interpreted according to representation type `T`.
590/// Memory is automatically deallocated when the matrix is dropped.
591#[derive(Debug)]
592pub struct Mat<T: ReprOwned> {
593    ptr: NonNull<u8>,
594    repr: T,
595    _invariant: PhantomData<fn(T) -> T>,
596}
597
598// SAFETY: [`Repr`] is required to propagate its `Send` bound.
599unsafe impl<T> Send for Mat<T> where T: ReprOwned + Send {}
600
601// SAFETY: [`Repr`] is required to propagate its `Sync` bound.
602unsafe impl<T> Sync for Mat<T> where T: ReprOwned + Sync {}
603
604impl<T: ReprOwned> Mat<T> {
605    /// Create a new matrix using `init` as the initializer.
606    pub fn new<U>(repr: T, init: U) -> Result<Self, <T as NewOwned<U>>::Error>
607    where
608        T: NewOwned<U>,
609    {
610        repr.new_owned(init)
611    }
612
613    /// Returns the number of rows (vectors) in the matrix.
614    #[inline]
615    pub fn num_vectors(&self) -> usize {
616        self.repr.nrows()
617    }
618
619    /// Returns a reference to the underlying representation.
620    pub fn repr(&self) -> &T {
621        &self.repr
622    }
623
624    /// Returns the `i`th row if `i < self.num_vectors()`.
625    #[must_use]
626    pub fn get_row(&self, i: usize) -> Option<T::Row<'_>> {
627        if i < self.num_vectors() {
628            // SAFETY: Bounds check passed, and the Mat was constructed
629            // with valid representation and pointer.
630            let row = unsafe { self.get_row_unchecked(i) };
631            Some(row)
632        } else {
633            None
634        }
635    }
636
637    pub(crate) unsafe fn get_row_unchecked(&self, i: usize) -> T::Row<'_> {
638        // SAFETY: Caller must ensure i < self.num_vectors(). The constructors for this type
639        // ensure that `ptr` is compatible with `T`.
640        unsafe { self.repr.get_row(self.ptr, i) }
641    }
642
643    /// Returns the `i`th mutable row if `i < self.num_vectors()`.
644    #[must_use]
645    pub fn get_row_mut(&mut self, i: usize) -> Option<T::RowMut<'_>> {
646        if i < self.num_vectors() {
647            // SAFETY: Bounds check passed, and we have exclusive access via &mut self.
648            Some(unsafe { self.get_row_mut_unchecked(i) })
649        } else {
650            None
651        }
652    }
653
654    pub(crate) unsafe fn get_row_mut_unchecked(&mut self, i: usize) -> T::RowMut<'_> {
655        // SAFETY: Caller asserts that `i < self.num_vectors()`. The constructors for this
656        // type ensure that `ptr` is compatible with `T`.
657        unsafe { self.repr.get_row_mut(self.ptr, i) }
658    }
659
660    /// Returns an immutable view of the matrix.
661    #[inline]
662    pub fn as_view(&self) -> MatRef<'_, T> {
663        MatRef {
664            ptr: self.ptr,
665            repr: self.repr,
666            _lifetime: PhantomData,
667        }
668    }
669
670    /// Returns a mutable view of the matrix.
671    #[inline]
672    pub fn as_view_mut(&mut self) -> MatMut<'_, T> {
673        MatMut {
674            ptr: self.ptr,
675            repr: self.repr,
676            _lifetime: PhantomData,
677        }
678    }
679
680    /// Returns an iterator over immutable row references.
681    pub fn rows(&self) -> Rows<'_, T> {
682        Rows::new(self.reborrow())
683    }
684
685    /// Returns an iterator over mutable row references.
686    pub fn rows_mut(&mut self) -> RowsMut<'_, T> {
687        RowsMut::new(self.reborrow_mut())
688    }
689
690    /// Construct a new [`Mat`] over the raw pointer and representation without performing
691    /// any validity checks.
692    ///
693    /// # Safety
694    ///
695    /// Argument `ptr` must be:
696    ///
697    /// 1. Point to memory compatible with [`Repr::layout`].
698    /// 2. Be compatible with the drop logic in [`ReprOwned`].
699    pub(crate) unsafe fn from_raw_parts(repr: T, ptr: NonNull<u8>) -> Self {
700        Self {
701            ptr,
702            repr,
703            _invariant: PhantomData,
704        }
705    }
706
707    /// Return the base pointer for the [`Mat`].
708    pub fn as_raw_ptr(&self) -> *const u8 {
709        self.ptr.as_ptr()
710    }
711
712    /// Return a mutable base pointer for the [`Mat`].
713    pub(crate) fn as_raw_mut_ptr(&mut self) -> *mut u8 {
714        self.ptr.as_ptr()
715    }
716}
717
718impl<T: ReprOwned> Drop for Mat<T> {
719    fn drop(&mut self) {
720        // SAFETY: `ptr` was correctly initialized according to `layout`
721        // and we are guaranteed exclusive access to the data due to Rust borrow rules.
722        unsafe { self.repr.drop(self.ptr) };
723    }
724}
725
726impl<T: NewCloned> Clone for Mat<T> {
727    fn clone(&self) -> Self {
728        T::new_cloned(self.as_view())
729    }
730}
731
732impl<T> Mat<Standard<T>> {
733    /// Construct a [`Mat`] by calling `f` once per element in row-major order.
734    pub fn from_fn<F: FnMut() -> T>(repr: Standard<T>, mut f: F) -> Self {
735        let b: Box<[T]> = (0..repr.num_elements()).map(|_| f()).collect();
736        // SAFETY: `b` has length `repr.num_elements()` by construction.
737        unsafe { repr.box_to_mat(b) }
738    }
739
740    /// Returns the raw dimension (columns) of the vectors in the matrix.
741    #[inline]
742    pub fn vector_dim(&self) -> usize {
743        self.repr.ncols()
744    }
745
746    /// Return the backing data as a contiguous slice of `T`.
747    ///
748    /// The returned slice has `num_vectors() * vector_dim()` elements in row-major order.
749    #[inline]
750    pub fn as_slice(&self) -> &[T] {
751        self.as_view().as_slice()
752    }
753
754    /// Return a [`MatrixView`] over the backing data.
755    #[inline]
756    pub fn as_matrix_view(&self) -> MatrixView<'_, T> {
757        self.as_view().as_matrix_view()
758    }
759}
760
761////////////
762// MatRef //
763////////////
764
765/// An immutable borrowed view of a matrix.
766///
767/// Provides read-only access to matrix data without ownership. Implements [`Copy`]
768/// and can be freely cloned.
769///
770/// # Type Parameter
771/// - `T`: A [`Repr`] implementation defining the row layout.
772///
773/// # Access
774/// - [`get_row`](Self::get_row): Get an immutable row by index.
775/// - [`rows`](Self::rows): Iterate over all rows.
776#[derive(Debug, Clone, Copy)]
777pub struct MatRef<'a, T: Repr> {
778    ptr: NonNull<u8>,
779    repr: T,
780    /// Marker to tie the lifetime to the borrowed data.
781    _lifetime: PhantomData<&'a T>,
782}
783
784// SAFETY: [`Repr`] is required to propagate its `Send` bound.
785unsafe impl<T> Send for MatRef<'_, T> where T: Repr + Send {}
786
787// SAFETY: [`Repr`] is required to propagate its `Sync` bound.
788unsafe impl<T> Sync for MatRef<'_, T> where T: Repr + Sync {}
789
790impl<'a, T: Repr> MatRef<'a, T> {
791    /// Construct a new [`MatRef`] over `data`.
792    pub fn new<U>(repr: T, data: &'a [U]) -> Result<Self, T::Error>
793    where
794        T: NewRef<U>,
795    {
796        repr.new_ref(data)
797    }
798
799    /// Returns the number of rows (vectors) in the matrix.
800    #[inline]
801    pub fn num_vectors(&self) -> usize {
802        self.repr.nrows()
803    }
804
805    /// Returns a reference to the underlying representation.
806    pub fn repr(&self) -> &T {
807        &self.repr
808    }
809
810    /// Returns an immutable reference to the i-th row, or `None` if out of bounds.
811    #[must_use]
812    pub fn get_row(&self, i: usize) -> Option<T::Row<'_>> {
813        if i < self.num_vectors() {
814            // SAFETY: Bounds check passed, and the MatRef was constructed
815            // with valid representation and pointer.
816            let row = unsafe { self.get_row_unchecked(i) };
817            Some(row)
818        } else {
819            None
820        }
821    }
822
823    /// Returns the i-th row without bounds checking.
824    ///
825    /// # Safety
826    ///
827    /// `i` must be less than `self.num_vectors()`.
828    #[inline]
829    pub(crate) unsafe fn get_row_unchecked(&self, i: usize) -> T::Row<'_> {
830        // SAFETY: Caller must ensure i < self.num_vectors().
831        unsafe { self.repr.get_row(self.ptr, i) }
832    }
833
834    /// Returns an iterator over immutable row references.
835    pub fn rows(&self) -> Rows<'_, T> {
836        Rows::new(*self)
837    }
838
839    /// Return a [`Mat`] with the same contents as `self`.
840    pub fn to_owned(&self) -> Mat<T>
841    where
842        T: NewCloned,
843    {
844        T::new_cloned(*self)
845    }
846
847    /// Construct a new [`MatRef`] over the raw pointer and representation without performing
848    /// any validity checks.
849    ///
850    /// # Safety
851    ///
852    /// Argument `ptr` must point to memory compatible with [`Repr::layout`] and pass any
853    /// validity checks required by `T`.
854    pub unsafe fn from_raw_parts(repr: T, ptr: NonNull<u8>) -> Self {
855        Self {
856            ptr,
857            repr,
858            _lifetime: PhantomData,
859        }
860    }
861
862    /// Return the base pointer for the [`MatRef`].
863    pub fn as_raw_ptr(&self) -> *const u8 {
864        self.ptr.as_ptr()
865    }
866}
867
868impl<'a, T> MatRef<'a, Standard<T>> {
869    /// Returns the raw dimension (columns) of the vectors in the matrix.
870    #[inline]
871    pub fn vector_dim(&self) -> usize {
872        self.repr.ncols()
873    }
874
875    /// Return the backing data as a contiguous slice of `T`.
876    ///
877    /// The returned slice has `num_vectors() * vector_dim()` elements in row-major order.
878    #[inline]
879    pub fn as_slice(&self) -> &'a [T] {
880        let len = self.repr.num_elements();
881        // SAFETY: `Standard<T>` guarantees `nrows * ncols` contiguous `T` elements
882        // starting at `self.ptr`. The lifetime `'a` is tied to the original data.
883        unsafe { std::slice::from_raw_parts(self.ptr.as_ptr().cast::<T>(), len) }
884    }
885
886    /// Return a [`MatrixView`] over the backing data.
887    #[allow(clippy::expect_used)]
888    #[inline]
889    pub fn as_matrix_view(&self) -> MatrixView<'a, T> {
890        // `Standard::new` validates that `nrows * ncols` does not overflow,
891        // so `try_from` is infallible here.
892        MatrixView::try_from(self.as_slice(), self.num_vectors(), self.vector_dim())
893            .expect("Standard<T> has valid dimensions")
894    }
895}
896
897// Reborrow: Mat -> MatRef
898impl<'this, T: ReprOwned> Reborrow<'this> for Mat<T> {
899    type Target = MatRef<'this, T>;
900
901    fn reborrow(&'this self) -> Self::Target {
902        self.as_view()
903    }
904}
905
906// ReborrowMut: Mat -> MatMut
907impl<'this, T: ReprOwned> ReborrowMut<'this> for Mat<T> {
908    type Target = MatMut<'this, T>;
909
910    fn reborrow_mut(&'this mut self) -> Self::Target {
911        self.as_view_mut()
912    }
913}
914
915// Reborrow: MatRef -> MatRef (with shorter lifetime)
916impl<'this, 'a, T: Repr> Reborrow<'this> for MatRef<'a, T> {
917    type Target = MatRef<'this, T>;
918
919    fn reborrow(&'this self) -> Self::Target {
920        MatRef {
921            ptr: self.ptr,
922            repr: self.repr,
923            _lifetime: PhantomData,
924        }
925    }
926}
927
928////////////
929// MatMut //
930////////////
931
932/// A mutable borrowed view of a matrix.
933///
934/// Provides read-write access to matrix data without ownership.
935///
936/// # Type Parameter
937/// - `T`: A [`ReprMut`] implementation defining the row layout.
938///
939/// # Access
940/// - [`get_row`](Self::get_row): Get an immutable row by index.
941/// - [`get_row_mut`](Self::get_row_mut): Get a mutable row by index.
942/// - [`as_view`](Self::as_view): Reborrow as immutable [`MatRef`].
943/// - [`rows`](Self::rows), [`rows_mut`](Self::rows_mut): Iterate over rows.
944#[derive(Debug)]
945pub struct MatMut<'a, T: ReprMut> {
946    ptr: NonNull<u8>,
947    repr: T,
948    /// Marker to tie the lifetime to the mutably borrowed data.
949    _lifetime: PhantomData<&'a mut T>,
950}
951
952// SAFETY: [`ReprMut`] is required to propagate its `Send` bound.
953unsafe impl<T> Send for MatMut<'_, T> where T: ReprMut + Send {}
954
955// SAFETY: [`ReprMut`] is required to propagate its `Sync` bound.
956unsafe impl<T> Sync for MatMut<'_, T> where T: ReprMut + Sync {}
957
958impl<'a, T: ReprMut> MatMut<'a, T> {
959    /// Construct a new [`MatMut`] over `data`.
960    pub fn new<U>(repr: T, data: &'a mut [U]) -> Result<Self, T::Error>
961    where
962        T: NewMut<U>,
963    {
964        repr.new_mut(data)
965    }
966
967    /// Returns the number of rows (vectors) in the matrix.
968    #[inline]
969    pub fn num_vectors(&self) -> usize {
970        self.repr.nrows()
971    }
972
973    /// Returns a reference to the underlying representation.
974    pub fn repr(&self) -> &T {
975        &self.repr
976    }
977
978    /// Returns an immutable reference to the i-th row, or `None` if out of bounds.
979    #[inline]
980    #[must_use]
981    pub fn get_row(&self, i: usize) -> Option<T::Row<'_>> {
982        if i < self.num_vectors() {
983            // SAFETY: Bounds check passed.
984            Some(unsafe { self.get_row_unchecked(i) })
985        } else {
986            None
987        }
988    }
989
990    /// Returns the i-th row without bounds checking.
991    ///
992    /// # Safety
993    ///
994    /// `i` must be less than `self.num_vectors()`.
995    #[inline]
996    pub(crate) unsafe fn get_row_unchecked(&self, i: usize) -> T::Row<'_> {
997        // SAFETY: Caller must ensure i < self.num_vectors().
998        unsafe { self.repr.get_row(self.ptr, i) }
999    }
1000
1001    /// Returns a mutable reference to the `i`-th row, or `None` if out of bounds.
1002    #[inline]
1003    #[must_use]
1004    pub fn get_row_mut(&mut self, i: usize) -> Option<T::RowMut<'_>> {
1005        if i < self.num_vectors() {
1006            // SAFETY: Bounds check passed.
1007            Some(unsafe { self.get_row_mut_unchecked(i) })
1008        } else {
1009            None
1010        }
1011    }
1012
1013    /// Returns a mutable reference to the i-th row without bounds checking.
1014    ///
1015    /// # Safety
1016    ///
1017    /// `i` must be less than [`num_vectors()`](Self::num_vectors).
1018    #[inline]
1019    pub(crate) unsafe fn get_row_mut_unchecked(&mut self, i: usize) -> T::RowMut<'_> {
1020        // SAFETY: Caller asserts that `i < self.num_vectors()`. The constructors for this
1021        // type ensure that `ptr` is compatible with `T`.
1022        unsafe { self.repr.get_row_mut(self.ptr, i) }
1023    }
1024
1025    /// Reborrows as an immutable [`MatRef`].
1026    pub fn as_view(&self) -> MatRef<'_, T> {
1027        MatRef {
1028            ptr: self.ptr,
1029            repr: self.repr,
1030            _lifetime: PhantomData,
1031        }
1032    }
1033
1034    /// Returns an iterator over immutable row references.
1035    pub fn rows(&self) -> Rows<'_, T> {
1036        Rows::new(self.reborrow())
1037    }
1038
1039    /// Returns an iterator over mutable row references.
1040    pub fn rows_mut(&mut self) -> RowsMut<'_, T> {
1041        RowsMut::new(self.reborrow_mut())
1042    }
1043
1044    /// Return a [`Mat`] with the same contents as `self`.
1045    pub fn to_owned(&self) -> Mat<T>
1046    where
1047        T: NewCloned,
1048    {
1049        T::new_cloned(self.as_view())
1050    }
1051
1052    /// Construct a new [`MatMut`] over the raw pointer and representation without performing
1053    /// any validity checks.
1054    ///
1055    /// # Safety
1056    ///
1057    /// Argument `ptr` must point to memory compatible with [`Repr::layout`].
1058    pub unsafe fn from_raw_parts(repr: T, ptr: NonNull<u8>) -> Self {
1059        Self {
1060            ptr,
1061            repr,
1062            _lifetime: PhantomData,
1063        }
1064    }
1065
1066    /// Return the base pointer for the [`MatMut`].
1067    pub fn as_raw_ptr(&self) -> *const u8 {
1068        self.ptr.as_ptr()
1069    }
1070
1071    /// Return a mutable base pointer for the [`MatMut`].
1072    pub(crate) fn as_raw_mut_ptr(&mut self) -> *mut u8 {
1073        self.ptr.as_ptr()
1074    }
1075}
1076
1077// Reborrow: MatMut -> MatRef
1078impl<'this, 'a, T: ReprMut> Reborrow<'this> for MatMut<'a, T> {
1079    type Target = MatRef<'this, T>;
1080
1081    fn reborrow(&'this self) -> Self::Target {
1082        self.as_view()
1083    }
1084}
1085
1086// ReborrowMut: MatMut -> MatMut (with shorter lifetime)
1087impl<'this, 'a, T: ReprMut> ReborrowMut<'this> for MatMut<'a, T> {
1088    type Target = MatMut<'this, T>;
1089
1090    fn reborrow_mut(&'this mut self) -> Self::Target {
1091        MatMut {
1092            ptr: self.ptr,
1093            repr: self.repr,
1094            _lifetime: PhantomData,
1095        }
1096    }
1097}
1098
1099impl<'a, T> MatMut<'a, Standard<T>> {
1100    /// Returns the raw dimension (columns) of the vectors in the matrix.
1101    #[inline]
1102    pub fn vector_dim(&self) -> usize {
1103        self.repr.ncols()
1104    }
1105
1106    /// Return the backing data as a contiguous slice of `T`.
1107    ///
1108    /// The returned slice has `num_vectors() * vector_dim()` elements in row-major order.
1109    #[inline]
1110    pub fn as_slice(&self) -> &[T] {
1111        self.as_view().as_slice()
1112    }
1113
1114    /// Return a [`MatrixView`] over the backing data.
1115    #[inline]
1116    pub fn as_matrix_view(&self) -> MatrixView<'_, T> {
1117        self.as_view().as_matrix_view()
1118    }
1119}
1120
1121//////////
1122// Rows //
1123//////////
1124
1125/// Iterator over immutable row references of a matrix.
1126///
1127/// Created by [`Mat::rows`], [`MatRef::rows`], or [`MatMut::rows`].
1128#[derive(Debug)]
1129pub struct Rows<'a, T: Repr> {
1130    matrix: MatRef<'a, T>,
1131    current: usize,
1132}
1133
1134impl<'a, T> Rows<'a, T>
1135where
1136    T: Repr,
1137{
1138    fn new(matrix: MatRef<'a, T>) -> Self {
1139        Self { matrix, current: 0 }
1140    }
1141}
1142
1143impl<'a, T> Iterator for Rows<'a, T>
1144where
1145    T: Repr + 'a,
1146{
1147    type Item = T::Row<'a>;
1148
1149    fn next(&mut self) -> Option<Self::Item> {
1150        let current = self.current;
1151        if current >= self.matrix.num_vectors() {
1152            None
1153        } else {
1154            self.current += 1;
1155            // SAFETY: We make sure through the above check that
1156            // the access is within bounds.
1157            //
1158            // Extending the lifetime to `'a` is safe because the underlying
1159            // MatRef has lifetime `'a`.
1160            Some(unsafe { self.matrix.repr.get_row(self.matrix.ptr, current) })
1161        }
1162    }
1163
1164    fn size_hint(&self) -> (usize, Option<usize>) {
1165        let remaining = self.matrix.num_vectors() - self.current;
1166        (remaining, Some(remaining))
1167    }
1168}
1169
1170impl<'a, T> ExactSizeIterator for Rows<'a, T> where T: Repr + 'a {}
1171impl<'a, T> FusedIterator for Rows<'a, T> where T: Repr + 'a {}
1172
1173/////////////
1174// RowsMut //
1175/////////////
1176
1177/// Iterator over mutable row references of a matrix.
1178///
1179/// Created by [`Mat::rows_mut`] or [`MatMut::rows_mut`].
1180#[derive(Debug)]
1181pub struct RowsMut<'a, T: ReprMut> {
1182    matrix: MatMut<'a, T>,
1183    current: usize,
1184}
1185
1186impl<'a, T> RowsMut<'a, T>
1187where
1188    T: ReprMut,
1189{
1190    fn new(matrix: MatMut<'a, T>) -> Self {
1191        Self { matrix, current: 0 }
1192    }
1193}
1194
1195impl<'a, T> Iterator for RowsMut<'a, T>
1196where
1197    T: ReprMut + 'a,
1198{
1199    type Item = T::RowMut<'a>;
1200
1201    fn next(&mut self) -> Option<Self::Item> {
1202        let current = self.current;
1203        if current >= self.matrix.num_vectors() {
1204            None
1205        } else {
1206            self.current += 1;
1207            // SAFETY: We make sure through the above check that
1208            // the access is within bounds.
1209            //
1210            // Extending the lifetime to `'a` is safe because:
1211            // 1. The underlying MatMut has lifetime `'a`.
1212            // 2. The iterator ensures that the mutable row indices are disjoint, so
1213            //    there is no aliasing as long as the implementation of `ReprMut` ensures
1214            //    there is not mutable sharing of the `RowMut` types.
1215            Some(unsafe { self.matrix.repr.get_row_mut(self.matrix.ptr, current) })
1216        }
1217    }
1218
1219    fn size_hint(&self) -> (usize, Option<usize>) {
1220        let remaining = self.matrix.num_vectors() - self.current;
1221        (remaining, Some(remaining))
1222    }
1223}
1224
1225impl<'a, T> ExactSizeIterator for RowsMut<'a, T> where T: ReprMut + 'a {}
1226impl<'a, T> FusedIterator for RowsMut<'a, T> where T: ReprMut + 'a {}
1227
1228///////////
1229// Tests //
1230///////////
1231
1232#[cfg(test)]
1233mod tests {
1234    use super::*;
1235
1236    use std::fmt::Display;
1237
1238    use diskann_utils::lazy_format;
1239
1240    /// Helper to assert a type is Copy.
1241    fn assert_copy<T: Copy>(_: &T) {}
1242
1243    // ── Variance assertions ──────────────────────────────────────
1244    //
1245    // These functions are never called. The test is that they compile:
1246    // covariant positions must accept subtype coercions.
1247    //
1248    // The negative (invariance) counterparts live in
1249    // `tests/compile-fail/multi/{mat,matmut}_invariant.rs`.
1250
1251    /// `MatRef` is covariant in `'a`: a longer borrow can shorten.
1252    fn _assert_matref_covariant_lifetime<'long: 'short, 'short, T: Repr>(
1253        v: MatRef<'long, T>,
1254    ) -> MatRef<'short, T> {
1255        v
1256    }
1257
1258    /// `MatRef` is covariant in `T`: `Standard<&'long u8>` → `Standard<&'short u8>`.
1259    fn _assert_matref_covariant_repr<'long: 'short, 'short, 'a>(
1260        v: MatRef<'a, Standard<&'long u8>>,
1261    ) -> MatRef<'a, Standard<&'short u8>> {
1262        v
1263    }
1264
1265    /// `MatMut` is covariant in `'a`: a longer borrow can shorten.
1266    fn _assert_matmut_covariant_lifetime<'long: 'short, 'short, T: ReprMut>(
1267        v: MatMut<'long, T>,
1268    ) -> MatMut<'short, T> {
1269        v
1270    }
1271
1272    fn edge_cases(nrows: usize) -> Vec<usize> {
1273        let max = usize::MAX;
1274
1275        vec![
1276            nrows,
1277            nrows + 1,
1278            nrows + 11,
1279            nrows + 20,
1280            max / 2,
1281            max.div_ceil(2),
1282            max - 1,
1283            max,
1284        ]
1285    }
1286
1287    fn fill_mat(x: &mut Mat<Standard<usize>>, repr: Standard<usize>) {
1288        assert_eq!(x.repr(), &repr);
1289        assert_eq!(x.num_vectors(), repr.nrows());
1290        assert_eq!(x.vector_dim(), repr.ncols());
1291
1292        for i in 0..x.num_vectors() {
1293            let row = x.get_row_mut(i).unwrap();
1294            assert_eq!(row.len(), repr.ncols());
1295            row.iter_mut()
1296                .enumerate()
1297                .for_each(|(j, r)| *r = 10 * i + j);
1298        }
1299
1300        for i in edge_cases(repr.nrows()).into_iter() {
1301            assert!(x.get_row_mut(i).is_none());
1302        }
1303    }
1304
1305    fn fill_mat_mut(mut x: MatMut<'_, Standard<usize>>, repr: Standard<usize>) {
1306        assert_eq!(x.repr(), &repr);
1307        assert_eq!(x.num_vectors(), repr.nrows());
1308        assert_eq!(x.vector_dim(), repr.ncols());
1309
1310        for i in 0..x.num_vectors() {
1311            let row = x.get_row_mut(i).unwrap();
1312            assert_eq!(row.len(), repr.ncols());
1313
1314            row.iter_mut()
1315                .enumerate()
1316                .for_each(|(j, r)| *r = 10 * i + j);
1317        }
1318
1319        for i in edge_cases(repr.nrows()).into_iter() {
1320            assert!(x.get_row_mut(i).is_none());
1321        }
1322    }
1323
1324    fn fill_rows_mut(x: RowsMut<'_, Standard<usize>>, repr: Standard<usize>) {
1325        assert_eq!(x.len(), repr.nrows());
1326        // Materialize all rows at once.
1327        let mut all_rows: Vec<_> = x.collect();
1328        assert_eq!(all_rows.len(), repr.nrows());
1329        for (i, row) in all_rows.iter_mut().enumerate() {
1330            assert_eq!(row.len(), repr.ncols());
1331            row.iter_mut()
1332                .enumerate()
1333                .for_each(|(j, r)| *r = 10 * i + j);
1334        }
1335    }
1336
1337    fn check_mat(x: &Mat<Standard<usize>>, repr: Standard<usize>, ctx: &dyn Display) {
1338        assert_eq!(x.repr(), &repr);
1339        assert_eq!(x.num_vectors(), repr.nrows());
1340        assert_eq!(x.vector_dim(), repr.ncols());
1341
1342        for i in 0..x.num_vectors() {
1343            let row = x.get_row(i).unwrap();
1344
1345            assert_eq!(row.len(), repr.ncols(), "ctx: {ctx}");
1346            row.iter().enumerate().for_each(|(j, r)| {
1347                assert_eq!(
1348                    *r,
1349                    10 * i + j,
1350                    "mismatched entry at row {}, col {} -- ctx: {}",
1351                    i,
1352                    j,
1353                    ctx
1354                )
1355            });
1356        }
1357
1358        for i in edge_cases(repr.nrows()).into_iter() {
1359            assert!(x.get_row(i).is_none(), "ctx: {ctx}");
1360        }
1361    }
1362
1363    fn check_mat_ref(x: MatRef<'_, Standard<usize>>, repr: Standard<usize>, ctx: &dyn Display) {
1364        assert_eq!(x.repr(), &repr);
1365        assert_eq!(x.num_vectors(), repr.nrows());
1366        assert_eq!(x.vector_dim(), repr.ncols());
1367
1368        assert_copy(&x);
1369        for i in 0..x.num_vectors() {
1370            let row = x.get_row(i).unwrap();
1371            assert_eq!(row.len(), repr.ncols(), "ctx: {ctx}");
1372
1373            row.iter().enumerate().for_each(|(j, r)| {
1374                assert_eq!(
1375                    *r,
1376                    10 * i + j,
1377                    "mismatched entry at row {}, col {} -- ctx: {}",
1378                    i,
1379                    j,
1380                    ctx
1381                )
1382            });
1383        }
1384
1385        for i in edge_cases(repr.nrows()).into_iter() {
1386            assert!(x.get_row(i).is_none(), "ctx: {ctx}");
1387        }
1388    }
1389
1390    fn check_mat_mut(x: MatMut<'_, Standard<usize>>, repr: Standard<usize>, ctx: &dyn Display) {
1391        assert_eq!(x.repr(), &repr);
1392        assert_eq!(x.num_vectors(), repr.nrows());
1393        assert_eq!(x.vector_dim(), repr.ncols());
1394
1395        for i in 0..x.num_vectors() {
1396            let row = x.get_row(i).unwrap();
1397            assert_eq!(row.len(), repr.ncols(), "ctx: {ctx}");
1398
1399            row.iter().enumerate().for_each(|(j, r)| {
1400                assert_eq!(
1401                    *r,
1402                    10 * i + j,
1403                    "mismatched entry at row {}, col {} -- ctx: {}",
1404                    i,
1405                    j,
1406                    ctx
1407                )
1408            });
1409        }
1410
1411        for i in edge_cases(repr.nrows()).into_iter() {
1412            assert!(x.get_row(i).is_none(), "ctx: {ctx}");
1413        }
1414    }
1415
1416    fn check_rows(x: Rows<'_, Standard<usize>>, repr: Standard<usize>, ctx: &dyn Display) {
1417        assert_eq!(x.len(), repr.nrows(), "ctx: {ctx}");
1418        let all_rows: Vec<_> = x.collect();
1419        assert_eq!(all_rows.len(), repr.nrows(), "ctx: {ctx}");
1420        for (i, row) in all_rows.iter().enumerate() {
1421            assert_eq!(row.len(), repr.ncols(), "ctx: {ctx}");
1422            row.iter().enumerate().for_each(|(j, r)| {
1423                assert_eq!(
1424                    *r,
1425                    10 * i + j,
1426                    "mismatched entry at row {}, col {} -- ctx: {}",
1427                    i,
1428                    j,
1429                    ctx
1430                )
1431            });
1432        }
1433    }
1434
1435    //////////////
1436    // Standard //
1437    //////////////
1438
1439    #[test]
1440    fn standard_representation() {
1441        let repr = Standard::<f32>::new(4, 3).unwrap();
1442        assert_eq!(repr.nrows(), 4);
1443        assert_eq!(repr.ncols(), 3);
1444
1445        let layout = repr.layout().unwrap();
1446        assert_eq!(layout.size(), 4 * 3 * std::mem::size_of::<f32>());
1447        assert_eq!(layout.align(), std::mem::align_of::<f32>());
1448    }
1449
1450    #[test]
1451    fn standard_zero_dimensions() {
1452        for (nrows, ncols) in [(0, 0), (0, 5), (5, 0)] {
1453            let repr = Standard::<u8>::new(nrows, ncols).unwrap();
1454            assert_eq!(repr.nrows(), nrows);
1455            assert_eq!(repr.ncols(), ncols);
1456            let layout = repr.layout().unwrap();
1457            assert_eq!(layout.size(), 0);
1458        }
1459    }
1460
1461    #[test]
1462    fn standard_check_slice() {
1463        let repr = Standard::<u32>::new(3, 4).unwrap();
1464
1465        // Correct length succeeds
1466        let data = vec![0u32; 12];
1467        assert!(repr.check_slice(&data).is_ok());
1468
1469        // Too short fails
1470        let short = vec![0u32; 11];
1471        assert!(matches!(
1472            repr.check_slice(&short),
1473            Err(SliceError::LengthMismatch {
1474                expected: 12,
1475                found: 11
1476            })
1477        ));
1478
1479        // Too long fails
1480        let long = vec![0u32; 13];
1481        assert!(matches!(
1482            repr.check_slice(&long),
1483            Err(SliceError::LengthMismatch {
1484                expected: 12,
1485                found: 13
1486            })
1487        ));
1488
1489        // Overflow case
1490        let overflow_repr = Standard::<u8>::new(usize::MAX, 2).unwrap_err();
1491        assert!(matches!(overflow_repr, Overflow { .. }));
1492    }
1493
1494    #[test]
1495    fn standard_new_rejects_element_count_overflow() {
1496        // nrows * ncols overflows usize even though per-element size is small.
1497        assert!(Standard::<u8>::new(usize::MAX, 2).is_err());
1498        assert!(Standard::<u8>::new(2, usize::MAX).is_err());
1499        assert!(Standard::<u8>::new(usize::MAX, usize::MAX).is_err());
1500    }
1501
1502    #[test]
1503    fn standard_new_rejects_byte_count_exceeding_isize_max() {
1504        // Element count fits in usize, but total bytes exceed isize::MAX.
1505        let half = (isize::MAX as usize / std::mem::size_of::<u64>()) + 1;
1506        assert!(Standard::<u64>::new(half, 1).is_err());
1507        assert!(Standard::<u64>::new(1, half).is_err());
1508    }
1509
1510    #[test]
1511    fn standard_new_accepts_boundary_below_isize_max() {
1512        // Largest allocation that still fits in isize::MAX bytes.
1513        let max_elems = isize::MAX as usize / std::mem::size_of::<u64>();
1514        let repr = Standard::<u64>::new(max_elems, 1).unwrap();
1515        assert_eq!(repr.num_elements(), max_elems);
1516    }
1517
1518    #[test]
1519    fn standard_new_zst_rejects_element_count_overflow() {
1520        // For ZSTs the byte count is always 0, but element-count overflow
1521        // must still be caught so that `num_elements()` never wraps.
1522        assert!(Standard::<()>::new(usize::MAX, 2).is_err());
1523        assert!(Standard::<()>::new(usize::MAX / 2 + 1, 3).is_err());
1524    }
1525
1526    #[test]
1527    fn standard_new_zst_accepts_large_non_overflowing() {
1528        // Large-but-valid ZST matrix: element count fits in usize.
1529        let repr = Standard::<()>::new(usize::MAX, 1).unwrap();
1530        assert_eq!(repr.num_elements(), usize::MAX);
1531        assert_eq!(repr.layout().unwrap().size(), 0);
1532    }
1533
1534    #[test]
1535    fn standard_new_overflow_error_display() {
1536        let err = Standard::<u32>::new(usize::MAX, 2).unwrap_err();
1537        let msg = err.to_string();
1538        assert!(msg.contains("would exceed isize::MAX bytes"), "{msg}");
1539
1540        let zst_err = Standard::<()>::new(usize::MAX, 2).unwrap_err();
1541        let zst_msg = zst_err.to_string();
1542        assert!(zst_msg.contains("ZST matrix"), "{zst_msg}");
1543        assert!(zst_msg.contains("usize::MAX"), "{zst_msg}");
1544    }
1545
1546    /////////
1547    // Mat //
1548    /////////
1549
1550    #[test]
1551    fn mat_new_and_basic_accessors() {
1552        let mat = Mat::new(Standard::<usize>::new(3, 4).unwrap(), 42usize).unwrap();
1553        let base: *const u8 = mat.as_raw_ptr();
1554
1555        assert_eq!(mat.num_vectors(), 3);
1556        assert_eq!(mat.vector_dim(), 4);
1557
1558        let repr = mat.repr();
1559        assert_eq!(repr.nrows(), 3);
1560        assert_eq!(repr.ncols(), 4);
1561
1562        for (i, r) in mat.rows().enumerate() {
1563            assert_eq!(r, &[42, 42, 42, 42]);
1564            let ptr = r.as_ptr().cast::<u8>();
1565            assert_eq!(
1566                ptr,
1567                base.wrapping_add(std::mem::size_of::<usize>() * mat.repr().ncols() * i),
1568            );
1569        }
1570    }
1571
1572    #[test]
1573    fn mat_new_with_default() {
1574        let mat = Mat::new(Standard::<usize>::new(2, 3).unwrap(), Defaulted).unwrap();
1575        let base: *const u8 = mat.as_raw_ptr();
1576
1577        assert_eq!(mat.num_vectors(), 2);
1578        for (i, row) in mat.rows().enumerate() {
1579            assert!(row.iter().all(|&v| v == 0));
1580
1581            let ptr = row.as_ptr().cast::<u8>();
1582            assert_eq!(
1583                ptr,
1584                base.wrapping_add(std::mem::size_of::<usize>() * mat.repr().ncols() * i),
1585            );
1586        }
1587    }
1588
1589    const ROWS: &[usize] = &[0, 1, 2, 3, 5, 10];
1590    const COLS: &[usize] = &[0, 1, 2, 3, 5, 10];
1591
1592    #[test]
1593    fn test_mat() {
1594        for nrows in ROWS {
1595            for ncols in COLS {
1596                let repr = Standard::<usize>::new(*nrows, *ncols).unwrap();
1597                let ctx = &lazy_format!("nrows = {}, ncols = {}", nrows, ncols);
1598
1599                // Populate the matrix using `&mut Mat`
1600                {
1601                    let ctx = &lazy_format!("{ctx} - direct");
1602                    let mut mat = Mat::new(repr, Defaulted).unwrap();
1603
1604                    assert_eq!(mat.num_vectors(), *nrows);
1605                    assert_eq!(mat.vector_dim(), *ncols);
1606
1607                    fill_mat(&mut mat, repr);
1608
1609                    check_mat(&mat, repr, ctx);
1610                    check_mat_ref(mat.reborrow(), repr, ctx);
1611                    check_mat_mut(mat.reborrow_mut(), repr, ctx);
1612                    check_rows(mat.rows(), repr, ctx);
1613
1614                    // Check reborrow preserves pointers.
1615                    assert_eq!(mat.as_raw_ptr(), mat.reborrow().as_raw_ptr());
1616                    assert_eq!(mat.as_raw_ptr(), mat.reborrow_mut().as_raw_ptr());
1617                }
1618
1619                // Populate the matrix using `MatMut`
1620                {
1621                    let ctx = &lazy_format!("{ctx} - matmut");
1622                    let mut mat = Mat::new(repr, Defaulted).unwrap();
1623                    let matmut = mat.reborrow_mut();
1624
1625                    assert_eq!(matmut.num_vectors(), *nrows);
1626                    assert_eq!(matmut.vector_dim(), *ncols);
1627
1628                    fill_mat_mut(matmut, repr);
1629
1630                    check_mat(&mat, repr, ctx);
1631                    check_mat_ref(mat.reborrow(), repr, ctx);
1632                    check_mat_mut(mat.reborrow_mut(), repr, ctx);
1633                    check_rows(mat.rows(), repr, ctx);
1634                }
1635
1636                // Populate the matrix using `RowsMut`
1637                {
1638                    let ctx = &lazy_format!("{ctx} - rows_mut");
1639                    let mut mat = Mat::new(repr, Defaulted).unwrap();
1640                    fill_rows_mut(mat.rows_mut(), repr);
1641
1642                    check_mat(&mat, repr, ctx);
1643                    check_mat_ref(mat.reborrow(), repr, ctx);
1644                    check_mat_mut(mat.reborrow_mut(), repr, ctx);
1645                    check_rows(mat.rows(), repr, ctx);
1646                }
1647            }
1648        }
1649    }
1650
1651    #[test]
1652    fn test_mat_clone() {
1653        for nrows in ROWS {
1654            for ncols in COLS {
1655                let repr = Standard::<usize>::new(*nrows, *ncols).unwrap();
1656                let ctx = &lazy_format!("nrows = {}, ncols = {}", nrows, ncols);
1657
1658                let mut mat = Mat::new(repr, Defaulted).unwrap();
1659                fill_mat(&mut mat, repr);
1660
1661                // Clone via Mat::clone
1662                {
1663                    let ctx = &lazy_format!("{ctx} - Mat::clone");
1664                    let cloned = mat.clone();
1665
1666                    assert_eq!(cloned.num_vectors(), *nrows);
1667                    assert_eq!(cloned.vector_dim(), *ncols);
1668
1669                    check_mat(&cloned, repr, ctx);
1670                    check_mat_ref(cloned.reborrow(), repr, ctx);
1671                    check_rows(cloned.rows(), repr, ctx);
1672
1673                    // Cloned allocation is independent.
1674                    if repr.num_elements() > 0 {
1675                        assert_ne!(mat.as_raw_ptr(), cloned.as_raw_ptr());
1676                    }
1677                }
1678
1679                // Clone via MatRef::to_owned
1680                {
1681                    let ctx = &lazy_format!("{ctx} - MatRef::to_owned");
1682                    let owned = mat.as_view().to_owned();
1683
1684                    check_mat(&owned, repr, ctx);
1685                    check_mat_ref(owned.reborrow(), repr, ctx);
1686                    check_rows(owned.rows(), repr, ctx);
1687
1688                    if repr.num_elements() > 0 {
1689                        assert_ne!(mat.as_raw_ptr(), owned.as_raw_ptr());
1690                    }
1691                }
1692
1693                // Clone via MatMut::to_owned
1694                {
1695                    let ctx = &lazy_format!("{ctx} - MatMut::to_owned");
1696                    let owned = mat.as_view_mut().to_owned();
1697
1698                    check_mat(&owned, repr, ctx);
1699                    check_mat_ref(owned.reborrow(), repr, ctx);
1700                    check_rows(owned.rows(), repr, ctx);
1701
1702                    if repr.num_elements() > 0 {
1703                        assert_ne!(mat.as_raw_ptr(), owned.as_raw_ptr());
1704                    }
1705                }
1706            }
1707        }
1708    }
1709
1710    #[test]
1711    fn test_mat_refmut() {
1712        for nrows in ROWS {
1713            for ncols in COLS {
1714                let repr = Standard::<usize>::new(*nrows, *ncols).unwrap();
1715                let ctx = &lazy_format!("nrows = {}, ncols = {}", nrows, ncols);
1716
1717                // Populate the matrix using `&mut Mat`
1718                {
1719                    let ctx = &lazy_format!("{ctx} - by matmut");
1720                    let mut b: Box<[_]> = (0..repr.num_elements()).map(|_| 0usize).collect();
1721                    let ptr = b.as_ptr().cast::<u8>();
1722                    let mut matmut = MatMut::new(repr, &mut b).unwrap();
1723
1724                    assert_eq!(
1725                        ptr,
1726                        matmut.as_raw_ptr(),
1727                        "underlying memory should be preserved",
1728                    );
1729
1730                    fill_mat_mut(matmut.reborrow_mut(), repr);
1731
1732                    check_mat_mut(matmut.reborrow_mut(), repr, ctx);
1733                    check_mat_ref(matmut.reborrow(), repr, ctx);
1734                    check_rows(matmut.rows(), repr, ctx);
1735                    check_rows(matmut.reborrow().rows(), repr, ctx);
1736
1737                    let matref = MatRef::new(repr, &b).unwrap();
1738                    check_mat_ref(matref, repr, ctx);
1739                    check_mat_ref(matref.reborrow(), repr, ctx);
1740                    check_rows(matref.rows(), repr, ctx);
1741                }
1742
1743                // Populate the matrix using `RowsMut`
1744                {
1745                    let ctx = &lazy_format!("{ctx} - by rows");
1746                    let mut b: Box<[_]> = (0..repr.num_elements()).map(|_| 0usize).collect();
1747                    let ptr = b.as_ptr().cast::<u8>();
1748                    let mut matmut = MatMut::new(repr, &mut b).unwrap();
1749
1750                    assert_eq!(
1751                        ptr,
1752                        matmut.as_raw_ptr(),
1753                        "underlying memory should be preserved",
1754                    );
1755
1756                    fill_rows_mut(matmut.rows_mut(), repr);
1757
1758                    check_mat_mut(matmut.reborrow_mut(), repr, ctx);
1759                    check_mat_ref(matmut.reborrow(), repr, ctx);
1760                    check_rows(matmut.rows(), repr, ctx);
1761                    check_rows(matmut.reborrow().rows(), repr, ctx);
1762
1763                    let matref = MatRef::new(repr, &b).unwrap();
1764                    check_mat_ref(matref, repr, ctx);
1765                    check_mat_ref(matref.reborrow(), repr, ctx);
1766                    check_rows(matref.rows(), repr, ctx);
1767                }
1768            }
1769        }
1770    }
1771
1772    //////////////////
1773    // Constructors //
1774    //////////////////
1775
1776    #[test]
1777    fn test_standard_new_owned() {
1778        let rows = [0, 1, 2, 3, 5, 10];
1779        let cols = [0, 1, 2, 3, 5, 10];
1780
1781        for nrows in rows {
1782            for ncols in cols {
1783                let m = Mat::new(Standard::new(nrows, ncols).unwrap(), 1usize).unwrap();
1784                let rows_iter = m.rows();
1785                let len = <_ as ExactSizeIterator>::len(&rows_iter);
1786                assert_eq!(len, nrows);
1787                for r in rows_iter {
1788                    assert_eq!(r.len(), ncols);
1789                    assert!(r.iter().all(|i| *i == 1usize));
1790                }
1791            }
1792        }
1793    }
1794
1795    #[test]
1796    fn test_mat_from_fn() {
1797        let rows = [0, 1, 2, 5];
1798        let cols = [0, 1, 3, 7];
1799
1800        for nrows in rows {
1801            for ncols in cols {
1802                let mut counter = 0u32;
1803                let m = Mat::from_fn(Standard::new(nrows, ncols).unwrap(), || {
1804                    let v = counter;
1805                    counter += 1;
1806                    v
1807                });
1808
1809                assert_eq!(counter as usize, nrows * ncols);
1810                for (i, row) in m.rows().enumerate() {
1811                    assert_eq!(row.len(), ncols);
1812                    for (j, &v) in row.iter().enumerate() {
1813                        assert_eq!(v, (i * ncols + j) as u32);
1814                    }
1815                }
1816            }
1817        }
1818    }
1819
1820    #[test]
1821    fn matref_new_slice_length_error() {
1822        let repr = Standard::<u32>::new(3, 4).unwrap();
1823
1824        // Correct length succeeds
1825        let data = vec![0u32; 12];
1826        assert!(MatRef::new(repr, &data).is_ok());
1827
1828        // Too short fails
1829        let short = vec![0u32; 11];
1830        assert!(matches!(
1831            MatRef::new(repr, &short),
1832            Err(SliceError::LengthMismatch {
1833                expected: 12,
1834                found: 11
1835            })
1836        ));
1837
1838        // Too long fails
1839        let long = vec![0u32; 13];
1840        assert!(matches!(
1841            MatRef::new(repr, &long),
1842            Err(SliceError::LengthMismatch {
1843                expected: 12,
1844                found: 13
1845            })
1846        ));
1847    }
1848
1849    #[test]
1850    fn matmut_new_slice_length_error() {
1851        let repr = Standard::<u32>::new(3, 4).unwrap();
1852
1853        // Correct length succeeds
1854        let mut data = vec![0u32; 12];
1855        assert!(MatMut::new(repr, &mut data).is_ok());
1856
1857        // Too short fails
1858        let mut short = vec![0u32; 11];
1859        assert!(matches!(
1860            MatMut::new(repr, &mut short),
1861            Err(SliceError::LengthMismatch {
1862                expected: 12,
1863                found: 11
1864            })
1865        ));
1866
1867        // Too long fails
1868        let mut long = vec![0u32; 13];
1869        assert!(matches!(
1870            MatMut::new(repr, &mut long),
1871            Err(SliceError::LengthMismatch {
1872                expected: 12,
1873                found: 13
1874            })
1875        ));
1876    }
1877
1878    #[test]
1879    fn as_matrix_view_roundtrip() {
1880        let data = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0];
1881
1882        // MatRef
1883        let matref = MatRef::new(Standard::new(2, 3).unwrap(), &data).unwrap();
1884        let view = matref.as_matrix_view();
1885        assert_eq!(view.nrows(), 2);
1886        assert_eq!(view.ncols(), 3);
1887        for row in 0..2 {
1888            for col in 0..3 {
1889                assert_eq!(view[(row, col)], data[row * 3 + col]);
1890            }
1891        }
1892        assert_eq!(matref.as_slice(), &data);
1893
1894        // Mat
1895        let mut mat = Mat::new(Standard::<f32>::new(2, 3).unwrap(), 0.0f32).unwrap();
1896        for i in 0..2 {
1897            let r = mat.get_row_mut(i).unwrap();
1898            for j in 0..3 {
1899                r[j] = data[i * 3 + j];
1900            }
1901        }
1902        let view = mat.as_matrix_view();
1903        assert_eq!(view.nrows(), 2);
1904        assert_eq!(view.ncols(), 3);
1905        for row in 0..2 {
1906            for col in 0..3 {
1907                assert_eq!(view[(row, col)], data[row * 3 + col]);
1908            }
1909        }
1910        assert_eq!(mat.as_slice(), &data);
1911
1912        // MatMut
1913        let mut buf = [1.0f32, 2.0, 3.0, 4.0, 5.0, 6.0];
1914        let matmut = MatMut::new(Standard::new(2, 3).unwrap(), &mut buf).unwrap();
1915        let view = matmut.as_matrix_view();
1916        assert_eq!(view.nrows(), 2);
1917        assert_eq!(view.ncols(), 3);
1918        for row in 0..2 {
1919            for col in 0..3 {
1920                assert_eq!(view[(row, col)], data[row * 3 + col]);
1921            }
1922        }
1923        assert_eq!(matmut.as_slice(), &data);
1924    }
1925
1926    #[test]
1927    fn test_standard_non_copy_element() {
1928        let repr = Standard::<String>::new(2, 3).unwrap();
1929
1930        // Owned fill via NewOwned<T> (Clone).
1931        let filled = Mat::new(repr, String::from("x")).unwrap();
1932        assert_eq!(filled.num_vectors(), 2);
1933        assert!(filled.rows().flatten().all(|s| s == "x"));
1934
1935        // NewOwned<Defaulted> (Clone + Default).
1936        let defaulted = Mat::new(repr, Defaulted).unwrap();
1937        assert!(defaulted.rows().flatten().all(String::is_empty));
1938
1939        // from_fn.
1940        let mut counter = 0usize;
1941        let mut mat = Mat::from_fn(repr, || {
1942            let s = counter.to_string();
1943            counter += 1;
1944            s
1945        });
1946        assert_eq!(counter, 6);
1947        assert_eq!(mat.get_row(1).unwrap()[0], "3");
1948
1949        // Mutation via get_row_mut.
1950        mat.get_row_mut(0).unwrap()[0] = String::from("mutated");
1951        assert_eq!(mat.get_row(0).unwrap()[0], "mutated");
1952
1953        // Clone via NewCloned (Clone): independent allocation, equal contents.
1954        let cloned = mat.clone();
1955        assert_ne!(mat.as_raw_ptr(), cloned.as_raw_ptr());
1956        assert_eq!(cloned.get_row(0).unwrap()[0], "mutated");
1957
1958        // Immutable view over a non-Copy slice (NewRef).
1959        let data = [String::from("a"), String::from("b")];
1960        let view = MatRef::new(Standard::new(2, 1).unwrap(), &data).unwrap();
1961        assert_eq!(view.get_row(1).unwrap()[0], "b");
1962
1963        // Mutable view over a non-Copy slice (NewMut).
1964        let mut data_mut = [String::from("a"), String::from("b")];
1965        let mut view_mut = MatMut::new(Standard::new(1, 2).unwrap(), &mut data_mut).unwrap();
1966        view_mut.get_row_mut(0).unwrap()[1] = String::from("z");
1967        assert_eq!(data_mut[1], "z");
1968    }
1969}