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