1use std::{marker::PhantomData, mem::ManuallyDrop, num::NonZeroUsize, ptr::NonNull};
7
8#[cfg(feature = "rayon")]
9use rayon::prelude::{IndexedParallelIterator, IntoParallelIterator, ParallelIterator};
10use thiserror::Error;
11
12pub mod iter;
13
14use crate::{internal, Reborrow, ReborrowMut};
15
16pub unsafe trait Matrix {
60 type Element;
62
63 fn as_nonnull(&self) -> NonNull<Self::Element>;
65
66 fn layout(&self) -> Layout<Self::Element>;
68
69 fn nrows(&self) -> usize {
75 self.layout().nrows()
76 }
77
78 fn ncols(&self) -> usize {
80 self.layout().ncols()
81 }
82
83 unsafe fn row_unchecked(&self, row: usize) -> &[Self::Element] {
91 let layout = self.layout();
92 debug_assert!(row < layout.nrows());
93
94 unsafe {
98 std::slice::from_raw_parts(self.as_ptr().add(layout.ncols() * row), layout.ncols())
99 }
100 }
101
102 fn as_ptr(&self) -> *const Self::Element {
104 self.as_nonnull().as_ptr().cast_const()
105 }
106
107 fn as_slice(&self) -> &[Self::Element] {
109 unsafe { std::slice::from_raw_parts(self.as_ptr(), self.layout().num_elements()) }
112 }
113
114 fn row(&self, row: usize) -> &[Self::Element] {
120 assert!(
121 row < self.nrows(),
122 "tried to access row {row} of a matrix with {} rows",
123 self.nrows()
124 );
125
126 unsafe { self.row_unchecked(row) }
128 }
129
130 fn get_row(&self, row: usize) -> Option<&[Self::Element]> {
132 if row < self.nrows() {
133 Some(unsafe { self.row_unchecked(row) })
135 } else {
136 None
137 }
138 }
139
140 fn rows(&self) -> iter::Rows<'_, Self::Element> {
144 iter::Rows::new(self.as_view())
145 }
146
147 unsafe fn element_unchecked(&self, row: usize, col: usize) -> &Self::Element {
155 let layout = self.layout();
156 debug_assert!(row < layout.nrows());
157 debug_assert!(col < layout.ncols());
158
159 unsafe { &*self.as_ptr().add(row * layout.ncols() + col) }
163 }
164
165 fn get_element(&self, row: usize, col: usize) -> Option<&Self::Element> {
169 if row >= self.nrows() || col >= self.ncols() {
170 None
171 } else {
172 Some(unsafe { self.element_unchecked(row, col) })
174 }
175 }
176
177 fn element(&self, row: usize, col: usize) -> &Self::Element {
183 assert!(
184 row < self.nrows(),
185 "row {row} is out of bounds (max: {})",
186 self.nrows()
187 );
188 assert!(
189 col < self.ncols(),
190 "col {col} is out of bounds (max: {})",
191 self.ncols()
192 );
193
194 unsafe { self.element_unchecked(row, col) }
196 }
197
198 fn as_view(&self) -> Ref<'_, Self::Element> {
200 Ref {
201 ptr: self.as_nonnull(),
202 layout: self.layout(),
203 _lifetime: PhantomData,
204 }
205 }
206
207 fn subview(&self, rows: std::ops::Range<usize>) -> Option<Ref<'_, Self::Element>> {
209 if rows.start > rows.end || rows.end > self.nrows() {
210 return None;
211 }
212
213 let ncols = self.ncols();
214 let ptr =
218 unsafe { NonNull::new_unchecked(self.as_ptr().add(rows.start * ncols).cast_mut()) };
219 let layout = unsafe { Layout::new_unchecked(rows.end - rows.start, ncols) };
222 Some(Ref {
223 ptr,
224 layout,
225 _lifetime: PhantomData,
226 })
227 }
228
229 fn window_iter(&self, batchsize: NonZeroUsize) -> iter::Windows<'_, Self::Element> {
235 iter::Windows::new(self.as_view(), batchsize)
236 }
237
238 fn to_rowmajor_owned(&self) -> Owned<Self::Element>
240 where
241 Self::Element: Clone,
242 {
243 unsafe { Owned::from_data_unchecked(self.as_slice().into(), self.layout()) }
246 }
247
248 fn try_map<F, R>(&self, f: F) -> Result<Owned<R>, LayoutError>
252 where
253 F: FnMut(&Self::Element) -> R,
254 {
255 let layout = self.layout().rebind::<R>()?;
256 let data: Box<[_]> = self.as_slice().iter().map(f).collect();
257
258 Ok(unsafe { Owned::from_data_unchecked(data, layout) })
261 }
262
263 #[track_caller]
271 fn map<F, R>(&self, f: F) -> Owned<R>
272 where
273 F: FnMut(&Self::Element) -> R,
274 {
275 match self.try_map(f) {
276 Ok(owned) => owned,
277 Err(error) => panic!("`Matrix::map` failed: {error}"),
278 }
279 }
280
281 fn transpose(&self) -> Owned<Self::Element>
283 where
284 Self::Element: Clone,
285 {
286 Owned::from_fn_with_layout(self.layout().transpose(), |RowCol { row, col }| {
287 unsafe { self.element_unchecked(col, row).clone() }
289 })
290 }
291
292 #[cfg(feature = "rayon")]
298 fn par_rows(&self) -> impl IndexedParallelIterator<Item = &[Self::Element]>
299 where
300 Self::Element: Sync,
301 {
302 let r = self.as_view();
303
304 (0..r.nrows()).into_par_iter().map(move |row| {
305 unsafe { r.into_row_unchecked(row) }
307 })
308 }
309
310 #[cfg(feature = "rayon")]
323 fn par_window_iter(
324 &self,
325 batchsize: usize,
326 ) -> impl IndexedParallelIterator<Item = Ref<'_, Self::Element>>
327 where
328 Self::Element: Sync,
329 {
330 assert!(batchsize != 0, "par_window_iter batchsize cannot be zero");
331
332 let r = self.as_view();
333 (0..r.nrows())
334 .into_par_iter()
335 .step_by(batchsize)
336 .map(move |start| {
337 let end = start.saturating_add(batchsize).min(r.nrows());
338
339 unsafe { r.into_subview_unchecked(start..end) }
341 })
342 }
343}
344
345pub unsafe trait MatrixMut: Matrix {
379 fn as_nonnull_mut(&mut self) -> NonNull<Self::Element>;
387
388 unsafe fn row_unchecked_mut(&mut self, row: usize) -> &mut [Self::Element] {
400 let layout = self.layout();
401
402 debug_assert!(row < layout.nrows());
403
404 unsafe {
408 std::slice::from_raw_parts_mut(
409 self.as_mut_ptr().add(layout.ncols() * row),
410 layout.ncols(),
411 )
412 }
413 }
414
415 fn as_mut_ptr(&mut self) -> *mut Self::Element {
417 self.as_nonnull_mut().as_ptr()
418 }
419
420 fn as_mut_slice(&mut self) -> &mut [Self::Element] {
422 unsafe { std::slice::from_raw_parts_mut(self.as_mut_ptr(), self.layout().num_elements()) }
425 }
426
427 fn row_mut(&mut self, row: usize) -> &mut [Self::Element] {
433 assert!(
434 row < self.nrows(),
435 "tried to access row {row} of a matrix with {} rows",
436 self.nrows()
437 );
438
439 unsafe { self.row_unchecked_mut(row) }
441 }
442
443 fn get_row_mut(&mut self, row: usize) -> Option<&mut [Self::Element]> {
445 if row < self.nrows() {
446 Some(unsafe { self.row_unchecked_mut(row) })
448 } else {
449 None
450 }
451 }
452
453 fn rows_mut(&mut self) -> iter::RowsMut<'_, Self::Element> {
457 iter::RowsMut::new(self.as_view_mut())
458 }
459
460 unsafe fn element_unchecked_mut(&mut self, row: usize, col: usize) -> &mut Self::Element {
468 let layout = self.layout();
469 debug_assert!(row < layout.nrows());
470 debug_assert!(col < layout.ncols());
471
472 unsafe { &mut *self.as_mut_ptr().add(row * layout.ncols() + col) }
476 }
477
478 fn get_element_mut(&mut self, row: usize, col: usize) -> Option<&mut Self::Element> {
482 if row >= self.nrows() || col >= self.ncols() {
483 None
484 } else {
485 Some(unsafe { self.element_unchecked_mut(row, col) })
487 }
488 }
489
490 fn element_mut(&mut self, row: usize, col: usize) -> &mut Self::Element {
496 assert!(
497 row < self.nrows(),
498 "row {row} is out of bounds (max: {})",
499 self.nrows()
500 );
501 assert!(
502 col < self.ncols(),
503 "col {col} is out of bounds (max: {})",
504 self.ncols()
505 );
506
507 unsafe { self.element_unchecked_mut(row, col) }
509 }
510
511 fn as_view_mut(&mut self) -> Mut<'_, Self::Element> {
513 Mut {
514 ptr: self.as_nonnull_mut(),
515 layout: self.layout(),
516 _lifetime: PhantomData,
517 }
518 }
519
520 fn subview_mut(&mut self, rows: std::ops::Range<usize>) -> Option<Mut<'_, Self::Element>> {
522 if rows.start > rows.end || rows.end > self.nrows() {
523 return None;
524 }
525
526 let ncols = self.ncols();
527 let ptr = unsafe { self.as_nonnull_mut().add(rows.start * ncols) };
531 let layout = unsafe { Layout::new_unchecked(rows.end - rows.start, ncols) };
534 Some(Mut {
535 ptr,
536 layout,
537 _lifetime: PhantomData,
538 })
539 }
540
541 #[cfg(feature = "rayon")]
549 fn par_rows_mut(&mut self) -> impl IndexedParallelIterator<Item = &mut [Self::Element]>
550 where
551 Self::Element: Send,
552 {
553 let matrix = iter::ParMut::new(self);
554 (0..matrix.nrows()).into_par_iter().map(move |row| {
555 unsafe { matrix.row_disjoint_unchecked(row) }
558 })
559 }
560
561 #[cfg(feature = "rayon")]
577 fn par_window_iter_mut(
578 &mut self,
579 batchsize: usize,
580 ) -> impl IndexedParallelIterator<Item = Mut<'_, Self::Element>>
581 where
582 Self::Element: Send,
583 {
584 assert!(
585 batchsize != 0,
586 "par_window_iter_mut batchsize cannot be zero"
587 );
588
589 let matrix = iter::ParMut::new(self);
590 let nrows = matrix.nrows();
591 (0..nrows)
592 .into_par_iter()
593 .step_by(batchsize)
594 .map(move |start| {
595 let end = start.saturating_add(batchsize).min(nrows);
596
597 unsafe { matrix.window_disjoint_unchecked(start..end) }
600 })
601 }
602}
603
604pub struct Layout<T> {
615 nrows: usize,
616 ncols: usize,
617 _type: PhantomData<fn() -> T>,
618}
619
620impl<T> Layout<T> {
621 pub const fn new(nrows: usize, ncols: usize) -> Result<Self, LayoutError> {
627 match LayoutError::check::<T>(nrows, ncols) {
628 Ok(()) => Ok(Self {
629 nrows,
630 ncols,
631 _type: PhantomData,
632 }),
633 Err(err) => Err(err),
634 }
635 }
636
637 unsafe fn new_unchecked(nrows: usize, ncols: usize) -> Self {
643 debug_assert!(LayoutError::check::<T>(nrows, ncols).is_ok());
644 Self {
645 nrows,
646 ncols,
647 _type: PhantomData,
648 }
649 }
650
651 pub fn num_elements(&self) -> usize {
653 self.nrows() * self.ncols()
654 }
655
656 pub fn nrows(&self) -> usize {
658 self.nrows
659 }
660
661 pub fn ncols(&self) -> usize {
663 self.ncols
664 }
665
666 pub fn rebind<U>(&self) -> Result<Layout<U>, LayoutError> {
672 if std::mem::size_of::<U>() <= std::mem::size_of::<T>() {
673 Ok(unsafe { Layout::new_unchecked(self.nrows(), self.ncols()) })
679 } else {
680 Layout::new(self.nrows(), self.ncols())
681 }
682 }
683
684 pub fn transpose(&self) -> Layout<T> {
686 unsafe { Layout::new_unchecked(self.ncols, self.nrows) }
689 }
690}
691
692impl<T> Clone for Layout<T> {
693 fn clone(&self) -> Self {
694 *self
695 }
696}
697
698impl<T> Copy for Layout<T> {}
699
700impl<T> std::fmt::Debug for Layout<T> {
701 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
702 f.debug_struct("Layout")
703 .field("nrows", &self.nrows)
704 .field("ncols", &self.ncols)
705 .field("elsize", &std::mem::size_of::<T>())
706 .finish()
707 }
708}
709
710impl<T> PartialEq for Layout<T> {
711 fn eq(&self, other: &Self) -> bool {
712 self.nrows == other.nrows && self.ncols == other.ncols
713 }
714}
715
716impl<T> Eq for Layout<T> {}
717
718#[derive(Debug, Clone, Copy)]
720pub struct LayoutError {
721 nrows: usize,
722 ncols: usize,
723 elsize: Option<NonZeroUsize>,
724}
725
726impl LayoutError {
727 pub(crate) const fn check<T>(nrows: usize, ncols: usize) -> Result<(), Self> {
728 let elsize = std::mem::size_of::<T>();
730 let num_elements = match nrows.checked_mul(ncols) {
731 Some(num_elements) => num_elements,
732 None => {
733 return Err(Self {
734 nrows,
735 ncols,
736 elsize: None,
737 })
738 }
739 };
740
741 if let Some(len) = num_elements.checked_mul(std::mem::size_of::<T>()) {
742 if len <= isize::MAX as usize {
743 return Ok(());
744 }
745 }
746
747 Err(Self {
748 nrows,
749 ncols,
750 elsize: NonZeroUsize::new(elsize),
751 })
752 }
753}
754
755impl std::fmt::Display for LayoutError {
756 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
757 match self.elsize {
758 Some(elsize) => {
759 write!(
760 f,
761 "a matrix of size {}x{} with elements of size {} exceeds `isize::MAX` bytes",
762 self.nrows, self.ncols, elsize
763 )
764 }
765 None => {
766 write!(
767 f,
768 "a matrix of size {}x{} has a length exceeding `usize::MAX`",
769 self.nrows, self.ncols,
770 )
771 }
772 }
773 }
774}
775
776impl std::error::Error for LayoutError {}
777
778macro_rules! constructors {
783 ($element:ident, $data:ty) => {
784 pub fn try_from_data(
789 data: $data,
790 nrows: usize,
791 ncols: usize,
792 ) -> Result<Self, TryFromError<$data>> {
793 let layout = match Layout::<$element>::new(nrows, ncols) {
794 Ok(layout) => layout,
795 Err(err) => return Err(TryFromError::layout(data, err)),
796 };
797
798 let len = data.len();
799 if len == layout.num_elements() {
800 Ok(unsafe { Self::from_data_unchecked(data, layout) })
802 } else {
803 Err(TryFromError::mismatch(
804 data,
805 layout.nrows(),
806 layout.ncols(),
807 len,
808 ))
809 }
810 }
811
812 pub fn row_vector(data: $data) -> Self {
814 let layout = unsafe { Layout::new_unchecked(1, data.len()) };
817
818 unsafe { Self::from_data_unchecked(data, layout) }
820 }
821
822 pub fn column_vector(data: $data) -> Self {
824 let layout = unsafe { Layout::new_unchecked(data.len(), 1) };
827
828 unsafe { Self::from_data_unchecked(data, layout) }
830 }
831 };
832}
833
834#[derive(Debug, Clone, Copy, PartialEq, Eq)]
841pub struct RowCol {
842 pub row: usize,
843 pub col: usize,
844}
845
846#[derive(Debug)]
848pub struct Owned<T> {
849 ptr: NonNull<T>,
850 layout: Layout<T>,
851}
852
853impl<T> Owned<T> {
854 constructors!(T, Box<[T]>);
855
856 #[track_caller]
879 pub fn from_fn<F>(nrows: usize, ncols: usize, init: F) -> Self
880 where
881 F: FnMut(RowCol) -> T,
882 {
883 match Self::try_from_fn(nrows, ncols, init) {
884 Ok(matrix) => matrix,
885 Err(error) => panic!("Owned::from_fn failed with: {error}"),
886 }
887 }
888
889 pub fn try_from_fn<F>(nrows: usize, ncols: usize, init: F) -> Result<Self, LayoutError>
907 where
908 F: FnMut(RowCol) -> T,
909 {
910 let layout = Layout::new(nrows, ncols)?;
911 Ok(Self::from_fn_with_layout(layout, init))
912 }
913
914 #[track_caller]
932 pub fn from_element(nrows: usize, ncols: usize, element: T) -> Self
933 where
934 T: Clone,
935 {
936 match Self::try_from_element(nrows, ncols, element) {
937 Ok(matrix) => matrix,
938 Err(error) => panic!("Owned::from_element failed with: {error}"),
939 }
940 }
941
942 pub fn try_from_element(nrows: usize, ncols: usize, element: T) -> Result<Self, LayoutError>
960 where
961 T: Clone,
962 {
963 let layout = Layout::new(nrows, ncols)?;
964 Ok(Self::from_element_with_layout(layout, element))
965 }
966
967 pub fn from_fn_with_layout<F>(layout: Layout<T>, mut init: F) -> Self
973 where
974 F: FnMut(RowCol) -> T,
975 {
976 let mut row = 0;
977 let mut col = 0;
978
979 let data: Box<[T]> = (0..layout.num_elements())
980 .map(|_| {
981 let v = (init)(RowCol { row, col });
982 col += 1;
983 if col == layout.ncols() {
984 col = 0;
985 row += 1;
986 }
987 v
988 })
989 .collect();
990
991 unsafe { Self::from_data_unchecked(data, layout) }
993 }
994
995 pub fn from_element_with_layout(layout: Layout<T>, element: T) -> Self
999 where
1000 T: Clone,
1001 {
1002 let data: Box<[T]> = std::iter::repeat_n(element, layout.num_elements()).collect();
1003
1004 unsafe { Self::from_data_unchecked(data, layout) }
1006 }
1007
1008 unsafe fn from_data_unchecked(b: Box<[T]>, layout: Layout<T>) -> Self {
1012 debug_assert_eq!(b.len(), layout.num_elements());
1013 Self {
1014 ptr: internal::box_to_nonnull(b),
1015 layout,
1016 }
1017 }
1018
1019 pub fn into_inner(self) -> Box<[T]> {
1032 let me = ManuallyDrop::new(self);
1033
1034 unsafe { internal::nonnull_to_box(me.ptr, me.layout.num_elements()) }
1037 }
1038}
1039
1040unsafe impl<T> Send for Owned<T> where T: Send {}
1042unsafe impl<T> Sync for Owned<T> where T: Sync {}
1044
1045impl<T> Drop for Owned<T> {
1046 fn drop(&mut self) {
1047 let _ = unsafe { internal::nonnull_to_box(self.ptr, self.layout.num_elements()) };
1050 }
1051}
1052
1053impl<T> Clone for Owned<T>
1054where
1055 T: Clone,
1056{
1057 fn clone(&self) -> Self {
1058 unsafe { Owned::from_data_unchecked(self.as_slice().into(), self.layout()) }
1060 }
1061}
1062
1063unsafe impl<T> Matrix for Owned<T> {
1065 type Element = T;
1066
1067 fn as_nonnull(&self) -> NonNull<T> {
1068 self.ptr
1069 }
1070
1071 fn layout(&self) -> Layout<T> {
1072 self.layout
1073 }
1074}
1075
1076unsafe impl<T> MatrixMut for Owned<T> {
1078 fn as_nonnull_mut(&mut self) -> NonNull<T> {
1079 self.ptr
1080 }
1081}
1082
1083impl<T> PartialEq for Owned<T>
1084where
1085 T: PartialEq,
1086{
1087 fn eq(&self, other: &Self) -> bool {
1088 Matrix::as_view(self).eq(&Matrix::as_view(other))
1089 }
1090}
1091
1092impl<'a, T> Reborrow<'a> for Owned<T> {
1093 type Target = Ref<'a, T>;
1094 fn reborrow(&'a self) -> Self::Target {
1095 Matrix::as_view(self)
1096 }
1097}
1098
1099impl<'a, T> ReborrowMut<'a> for Owned<T> {
1100 type Target = Mut<'a, T>;
1101 fn reborrow_mut(&'a mut self) -> Self::Target {
1102 MatrixMut::as_view_mut(self)
1103 }
1104}
1105
1106#[derive(Debug, Clone)]
1127pub struct Resizable<T> {
1128 data: Vec<T>,
1131 layout: Layout<T>,
1132}
1133
1134impl<T> Resizable<T> {
1135 pub fn new() -> Self {
1137 Self::with_capacity(0)
1138 }
1139
1140 pub fn with_capacity(capacity: usize) -> Self {
1143 Self {
1144 data: Vec::with_capacity(capacity),
1145 layout: unsafe { Layout::new_unchecked(0, 0) },
1147 }
1148 }
1149
1150 pub fn capacity(&self) -> usize {
1152 self.data.capacity()
1153 }
1154
1155 pub fn resize_with<F>(&mut self, nrows: usize, ncols: usize, f: F) -> Result<(), LayoutError>
1162 where
1163 F: FnMut() -> T,
1164 {
1165 let layout = Layout::new(nrows, ncols)?;
1166 let len = layout.num_elements();
1167 if self.data.len() < len {
1168 self.data.resize_with(len, f);
1169 }
1170 self.layout = layout;
1171 Ok(())
1172 }
1173
1174 pub fn resize(&mut self, nrows: usize, ncols: usize) -> Result<(), LayoutError>
1179 where
1180 T: Default,
1181 {
1182 self.resize_with(nrows, ncols, T::default)
1183 }
1184
1185 pub fn clear(&mut self) {
1187 self.layout = unsafe { Layout::new_unchecked(0, 0) };
1189 }
1190
1191 pub fn shrink_to_fit(&mut self) {
1193 self.data.truncate(self.layout.num_elements());
1194 self.data.shrink_to_fit();
1195 }
1196}
1197
1198impl<T> Default for Resizable<T> {
1199 fn default() -> Self {
1200 Self::new()
1201 }
1202}
1203
1204impl<T> From<Owned<T>> for Resizable<T> {
1205 fn from(matrix: Owned<T>) -> Self {
1207 let layout = matrix.layout();
1208 Self {
1209 data: matrix.into_inner().into_vec(),
1210 layout,
1211 }
1212 }
1213}
1214
1215impl<T> From<Resizable<T>> for Owned<T> {
1216 fn from(mut matrix: Resizable<T>) -> Self {
1218 matrix.data.truncate(matrix.layout.num_elements());
1219 let layout = matrix.layout;
1220 unsafe { Owned::from_data_unchecked(matrix.data.into_boxed_slice(), layout) }
1223 }
1224}
1225
1226impl<T> PartialEq for Resizable<T>
1227where
1228 T: PartialEq,
1229{
1230 fn eq(&self, other: &Self) -> bool {
1232 Matrix::as_view(self).eq(&Matrix::as_view(other))
1233 }
1234}
1235
1236unsafe impl<T> Matrix for Resizable<T> {
1240 type Element = T;
1241
1242 fn as_nonnull(&self) -> NonNull<T> {
1243 NonNull::from(self.data.as_slice()).cast()
1244 }
1245
1246 fn layout(&self) -> Layout<T> {
1247 self.layout
1248 }
1249}
1250
1251unsafe impl<T> MatrixMut for Resizable<T> {
1253 fn as_nonnull_mut(&mut self) -> NonNull<T> {
1254 NonNull::from(self.data.as_mut_slice()).cast()
1255 }
1256}
1257
1258impl<'a, T> Reborrow<'a> for Resizable<T> {
1259 type Target = Ref<'a, T>;
1260 fn reborrow(&'a self) -> Self::Target {
1261 Matrix::as_view(self)
1262 }
1263}
1264
1265impl<'a, T> ReborrowMut<'a> for Resizable<T> {
1266 type Target = Mut<'a, T>;
1267 fn reborrow_mut(&'a mut self) -> Self::Target {
1268 MatrixMut::as_view_mut(self)
1269 }
1270}
1271
1272#[derive(Debug)]
1278pub struct Ref<'a, T> {
1279 ptr: NonNull<T>,
1280 layout: Layout<T>,
1281 _lifetime: PhantomData<&'a [T]>,
1282}
1283
1284unsafe impl<T> Send for Ref<'_, T> where T: Sync {}
1287unsafe impl<T> Sync for Ref<'_, T> where T: Sync {}
1289
1290impl<'a, T> Ref<'a, T> {
1291 constructors!(T, &'a [T]);
1292
1293 unsafe fn from_data_unchecked(b: &'a [T], layout: Layout<T>) -> Self {
1297 debug_assert_eq!(b.len(), layout.num_elements());
1298 Self {
1299 ptr: internal::slice_to_nonnull(b),
1300 layout,
1301 _lifetime: PhantomData,
1302 }
1303 }
1304
1305 pub fn into_slice(self) -> &'a [T] {
1309 unsafe { std::slice::from_raw_parts(self.as_ptr(), self.layout().num_elements()) }
1311 }
1312
1313 #[cfg(feature = "rayon")]
1319 unsafe fn into_row_unchecked(self, row: usize) -> &'a [T] {
1320 let layout = self.layout();
1321 debug_assert!(row < layout.nrows());
1322
1323 unsafe {
1326 std::slice::from_raw_parts(self.as_ptr().add(layout.ncols() * row), layout.ncols())
1327 }
1328 }
1329
1330 #[cfg(feature = "rayon")]
1336 unsafe fn into_subview_unchecked(self, rows: std::ops::Range<usize>) -> Ref<'a, T> {
1337 debug_assert!(rows.start <= rows.end);
1338 debug_assert!(rows.end <= self.nrows());
1339
1340 let ncols = self.ncols();
1341 Self {
1342 ptr: unsafe { self.ptr.add(rows.start * ncols) },
1345 layout: unsafe { Layout::new_unchecked(rows.end - rows.start, ncols) },
1347 _lifetime: PhantomData,
1348 }
1349 }
1350}
1351
1352impl<T> Clone for Ref<'_, T> {
1353 fn clone(&self) -> Self {
1354 *self
1355 }
1356}
1357
1358impl<T> Copy for Ref<'_, T> {}
1359
1360unsafe impl<T> Matrix for Ref<'_, T> {
1362 type Element = T;
1363
1364 fn as_nonnull(&self) -> NonNull<T> {
1365 self.ptr
1366 }
1367
1368 fn layout(&self) -> Layout<T> {
1369 self.layout
1370 }
1371}
1372
1373impl<'a, T> Reborrow<'a> for Ref<'_, T> {
1374 type Target = Ref<'a, T>;
1375 fn reborrow(&'a self) -> Self::Target {
1376 Matrix::as_view(self)
1377 }
1378}
1379
1380impl<T> PartialEq for Ref<'_, T>
1381where
1382 T: PartialEq,
1383{
1384 fn eq(&self, other: &Self) -> bool {
1385 self.layout() == other.layout() && self.as_slice() == other.as_slice()
1386 }
1387}
1388
1389#[derive(Debug)]
1395pub struct Mut<'a, T> {
1396 ptr: NonNull<T>,
1397 layout: Layout<T>,
1398 _lifetime: PhantomData<&'a mut [T]>,
1399}
1400
1401unsafe impl<T> Send for Mut<'_, T> where T: Send {}
1404unsafe impl<T> Sync for Mut<'_, T> where T: Sync {}
1406
1407impl<'a, T> Mut<'a, T> {
1408 constructors!(T, &'a mut [T]);
1409
1410 unsafe fn from_data_unchecked(b: &'a mut [T], layout: Layout<T>) -> Self {
1414 debug_assert_eq!(b.len(), layout.num_elements());
1415 Self {
1416 ptr: internal::mut_slice_to_nonnull(b),
1417 layout,
1418 _lifetime: PhantomData,
1419 }
1420 }
1421
1422 pub fn into_mut_slice(self) -> &'a mut [T] {
1424 unsafe { std::slice::from_raw_parts_mut(self.ptr.as_ptr(), self.layout.num_elements()) }
1427 }
1428}
1429
1430unsafe impl<T> Matrix for Mut<'_, T> {
1432 type Element = T;
1433
1434 fn as_nonnull(&self) -> NonNull<T> {
1435 self.ptr
1436 }
1437
1438 fn layout(&self) -> Layout<T> {
1439 self.layout
1440 }
1441}
1442
1443unsafe impl<T> MatrixMut for Mut<'_, T> {
1445 fn as_nonnull_mut(&mut self) -> NonNull<T> {
1446 self.ptr
1447 }
1448}
1449
1450impl<T> PartialEq for Mut<'_, T>
1451where
1452 T: PartialEq,
1453{
1454 fn eq(&self, other: &Self) -> bool {
1455 Matrix::as_view(self).eq(&Matrix::as_view(other))
1456 }
1457}
1458
1459impl<'a, T> Reborrow<'a> for Mut<'_, T> {
1460 type Target = Ref<'a, T>;
1461 fn reborrow(&'a self) -> Self::Target {
1462 Matrix::as_view(self)
1463 }
1464}
1465
1466impl<'a, T> ReborrowMut<'a> for Mut<'_, T> {
1467 type Target = Mut<'a, T>;
1468 fn reborrow_mut(&'a mut self) -> Self::Target {
1469 MatrixMut::as_view_mut(self)
1470 }
1471}
1472
1473pub struct TryFromError<T> {
1479 data: T,
1480 inner: TryFromErrorInner,
1481}
1482
1483impl<T> TryFromError<T> {
1484 pub fn into_inner(self) -> T {
1486 self.data
1487 }
1488
1489 pub fn as_static(&self) -> TryFromErrorLight {
1492 TryFromErrorLight(self.inner)
1493 }
1494
1495 fn layout(data: T, error: LayoutError) -> Self {
1500 Self {
1501 data,
1502 inner: TryFromErrorInner::Layout(error),
1503 }
1504 }
1505
1506 fn mismatch(data: T, nrows: usize, ncols: usize, len: usize) -> Self {
1507 Self {
1508 data,
1509 inner: TryFromErrorInner::Mismatch { nrows, ncols, len },
1510 }
1511 }
1512}
1513
1514impl<T> std::fmt::Debug for TryFromError<T> {
1515 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1516 f.debug_struct("TryFromError")
1517 .field("data", &"<hidden>")
1518 .field("inner", &self.inner)
1519 .finish()
1520 }
1521}
1522
1523impl<T> std::fmt::Display for TryFromError<T> {
1524 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1525 self.inner.fmt(f)
1526 }
1527}
1528
1529impl<T> std::error::Error for TryFromError<T> {}
1530
1531#[derive(Debug, Error)]
1533#[error(transparent)]
1534pub struct TryFromErrorLight(TryFromErrorInner);
1535
1536#[derive(Debug, Error, Clone, Copy)]
1537enum TryFromErrorInner {
1538 #[error(transparent)]
1539 Layout(LayoutError),
1540 #[error(
1541 "tried to construct a {}x{} matrix over a span of length {}",
1542 nrows,
1543 ncols,
1544 len
1545 )]
1546 Mismatch {
1547 nrows: usize,
1548 ncols: usize,
1549 len: usize,
1550 },
1551}
1552
1553#[cfg(test)]
1558mod tests {
1559 use super::*;
1560 use crate::{assert_contains, lazy_format};
1561
1562 #[test]
1563 fn resizable_takes_each_shape_and_reuses_its_storage() {
1564 let mut matrix = Resizable::<u32>::new();
1565 assert_eq!((matrix.nrows(), matrix.ncols()), (0, 0));
1566 assert_eq!(matrix.as_slice(), &[]);
1567
1568 matrix.resize(2, 3).unwrap();
1570 for (i, x) in matrix.as_mut_slice().iter_mut().enumerate() {
1571 *x = i as u32;
1572 }
1573 assert_eq!((matrix.nrows(), matrix.ncols()), (2, 3));
1574 assert_eq!(matrix.row(1), &[3, 4, 5]);
1575 assert_eq!(matrix.as_view_mut().row_mut(0), &mut [0, 1, 2]);
1576
1577 let capacity = matrix.capacity();
1579 matrix.resize(1, 2).unwrap();
1580 assert_eq!((matrix.nrows(), matrix.ncols()), (1, 2));
1581 assert_eq!(matrix.as_slice().len(), 2);
1582 assert_eq!(matrix.capacity(), capacity);
1583
1584 matrix.resize(2, 4).unwrap();
1586 assert_eq!(matrix.as_slice().len(), 8);
1587 }
1588
1589 #[test]
1590 fn resizable_rejects_an_overflowing_shape_and_keeps_the_old_one() {
1591 let mut matrix = Resizable::<u32>::new();
1592 matrix.resize(2, 4).unwrap();
1593
1594 assert!(matrix.resize(usize::MAX, 2).is_err());
1595
1596 assert_eq!((matrix.nrows(), matrix.ncols()), (2, 4));
1597 }
1598
1599 #[test]
1600 fn resizable_holds_types_without_default() {
1601 let one = NonZeroUsize::MIN;
1603 let mut matrix = Resizable::new();
1604
1605 matrix.resize_with(2, 2, || one).unwrap();
1606
1607 assert_eq!(matrix.as_slice(), &[one; 4]);
1608 }
1609
1610 #[test]
1611 fn resizable_clear_and_shrink_release_only_what_they_promise() {
1612 let mut matrix = Resizable::<u8>::with_capacity(16);
1613 assert!(matrix.capacity() >= 16);
1614 matrix.resize(2, 4).unwrap();
1615
1616 let capacity = matrix.capacity();
1618 matrix.clear();
1619 assert_eq!((matrix.nrows(), matrix.ncols()), (0, 0));
1620 assert_eq!(matrix.capacity(), capacity);
1621
1622 matrix.resize(1, 3).unwrap();
1624 matrix.shrink_to_fit();
1625 assert_eq!(matrix.as_slice().len(), 3);
1626 assert!(matrix.capacity() < capacity);
1627 }
1628
1629 #[test]
1630 fn resizable_converts_to_and_from_owned() {
1631 let owned = Owned::from_fn(2, 3, |rc| rc.row * 3 + rc.col);
1632
1633 let mut matrix = Resizable::from(owned.clone());
1634 assert_eq!(matrix.as_view(), owned.as_view());
1635
1636 matrix.resize(1, 3).unwrap();
1638 let back = Owned::from(matrix);
1639 assert_eq!((back.nrows(), back.ncols()), (1, 3));
1640 assert_eq!(back.as_slice(), &[0, 1, 2]);
1641 }
1642
1643 #[test]
1644 fn resizable_equality_compares_the_shape_and_its_elements() {
1645 let mut left = Resizable::from(Owned::from_element(2, 2, 7_u8));
1646 let mut right = Resizable::from(Owned::from_element(1, 4, 7_u8));
1647 assert_ne!(left, right);
1649
1650 right.resize(1, 2).unwrap();
1652 left.resize(1, 2).unwrap();
1653 assert_eq!(left, right);
1654 }
1655
1656 fn is_copyable<T: Copy>(_x: T) -> bool {
1660 true
1661 }
1662
1663 fn _matrix_view_is_covariant<'a, 'b>(m: Ref<'a, f32>) -> Ref<'b, f32>
1665 where
1666 'a: 'b,
1667 {
1668 m
1669 }
1670
1671 fn _matrix_view_is_covariant_in_t<'a, 'b, 'm>(m: Ref<'m, &'a f32>) -> Ref<'m, &'b f32>
1672 where
1673 'a: 'b,
1674 {
1675 m
1676 }
1677
1678 fn _matrix_is_covariant_in_t<'a, 'b, 'm>(m: &'m Owned<&'a f32>) -> &'m Owned<&'b f32>
1679 where
1680 'a: 'b,
1681 {
1682 m
1683 }
1684
1685 #[test]
1690 fn test_layout() {
1691 for rows in 0..5 {
1693 for cols in 0..5 {
1694 let layout = Layout::<String>::new(rows, cols).unwrap();
1695 assert_eq!(layout.nrows(), rows);
1696 assert_eq!(layout.ncols(), cols);
1697 assert_eq!(layout.num_elements(), rows * cols);
1698
1699 let transpose = layout.transpose();
1700 assert_eq!(transpose.nrows(), cols);
1701 assert_eq!(transpose.ncols(), rows);
1702 assert_eq!(transpose.num_elements(), rows * cols);
1703
1704 let rebind = layout.rebind::<u32>().unwrap();
1705 assert_eq!(rebind.nrows(), rows);
1706 assert_eq!(rebind.ncols(), cols);
1707 assert_eq!(rebind.num_elements(), rows * cols);
1708
1709 is_copyable(layout);
1710 }
1711 }
1712
1713 #[expect(unused, reason = "we need this so the size is non-zero")]
1714 struct NotDebugOrEq(u32);
1715
1716 assert_eq!(
1717 Layout::<NotDebugOrEq>::new(10, 20).unwrap(),
1718 Layout::<NotDebugOrEq>::new(10, 20).unwrap(),
1719 );
1720
1721 assert_eq!(
1722 Layout::<NotDebugOrEq>::new(20, 0).unwrap(),
1723 Layout::<NotDebugOrEq>::new(20, 0).unwrap(),
1724 );
1725
1726 assert_ne!(
1727 Layout::<NotDebugOrEq>::new(10, 20).unwrap(),
1728 Layout::<NotDebugOrEq>::new(20, 0).unwrap(),
1729 );
1730
1731 let fmt = format!("{:?}", Layout::<NotDebugOrEq>::new(5, 6).unwrap());
1732 assert_eq!(fmt, "Layout { nrows: 5, ncols: 6, elsize: 4 }");
1733
1734 let error = Layout::<u8>::new(usize::MAX, 2).unwrap_err();
1736 assert_eq!(
1737 error.to_string(),
1738 format!(
1739 "a matrix of size {}x2 has a length exceeding `usize::MAX`",
1740 usize::MAX
1741 )
1742 );
1743
1744 let layout = Layout::<u8>::new(isize::MAX as usize, 1).unwrap();
1746 assert_eq!(layout.num_elements(), isize::MAX as usize);
1747
1748 let transpose = layout.transpose();
1749 assert_eq!(transpose.nrows(), 1);
1750 assert_eq!(transpose.ncols(), isize::MAX as usize);
1751 assert_eq!(transpose.num_elements(), layout.num_elements());
1752
1753 let error = Layout::<u8>::new(isize::MAX as usize + 1, 1).unwrap_err();
1755 assert_eq!(
1756 error.to_string(),
1757 format!(
1758 "a matrix of size {}x1 with elements of size 1 exceeds `isize::MAX` bytes",
1759 isize::MAX as usize + 1
1760 )
1761 );
1762
1763 let rebound = Layout::<u8>::new(3, 4).unwrap().rebind::<u16>().unwrap();
1765 assert_eq!(rebound.nrows(), 3);
1766 assert_eq!(rebound.ncols(), 4);
1767 assert_eq!(rebound.num_elements(), 12);
1768
1769 let error = layout.rebind::<u16>().unwrap_err();
1770 assert_eq!(
1771 error.to_string(),
1772 format!(
1773 "a matrix of size {}x1 with elements of size 2 exceeds `isize::MAX` bytes",
1774 isize::MAX
1775 )
1776 );
1777 }
1778
1779 #[test]
1784 fn test_sizes() {
1785 let expected = 3 * std::mem::size_of::<usize>();
1786 assert_eq!(std::mem::size_of::<Owned<String>>(), expected);
1787 assert_eq!(std::mem::size_of::<Option<Owned<String>>>(), expected);
1788
1789 assert_eq!(std::mem::size_of::<Ref<'_, String>>(), expected);
1790 assert_eq!(std::mem::size_of::<Option<Ref<'_, String>>>(), expected);
1791
1792 assert_eq!(std::mem::size_of::<Mut<'_, String>>(), expected);
1793 assert_eq!(std::mem::size_of::<Option<Mut<'_, String>>>(), expected);
1794 }
1795
1796 #[test]
1797 fn fallible_matrix_constructors() {
1798 let err = Owned::try_from_element(usize::MAX, usize::MAX, 0u32).unwrap_err();
1799 let msg = err.to_string();
1800 assert_contains!(msg, "exceeding `usize::MAX`");
1801
1802 let err = Owned::try_from_element(isize::MAX as usize, 1, 0u32).unwrap_err();
1803 let msg = err.to_string();
1804 assert_contains!(msg, "exceeds `isize::MAX` bytes");
1805
1806 let err = std::panic::catch_unwind(|| {
1808 Owned::from_element(usize::MAX, usize::MAX, 0u32);
1809 })
1810 .unwrap_err()
1811 .downcast::<String>()
1812 .unwrap();
1813
1814 let msg = err.to_string();
1815 assert_contains!(msg, "exceeding `usize::MAX`");
1816
1817 let err = std::panic::catch_unwind(|| {
1818 Owned::from_element(isize::MAX as usize, 1, 0u32);
1819 })
1820 .unwrap_err()
1821 .downcast::<String>()
1822 .unwrap();
1823 let msg = err.to_string();
1824 assert_contains!(msg, "exceeds `isize::MAX` bytes");
1825
1826 let err = Owned::try_from_fn(usize::MAX, usize::MAX, |_| panic!("boom")).unwrap_err();
1828 let msg = err.to_string();
1829 assert_contains!(msg, "exceeding `usize::MAX`");
1830
1831 let err = std::panic::catch_unwind(|| {
1832 Owned::from_fn(usize::MAX, usize::MAX, |_| {
1833 panic!("initializer must not run")
1834 });
1835 })
1836 .unwrap_err()
1837 .downcast::<String>()
1838 .unwrap();
1839 let msg = err.to_string();
1840 assert_contains!(msg, "Owned::from_fn failed");
1841 assert_contains!(msg, "exceeding `usize::MAX`");
1842 }
1843
1844 fn make_test_matrix() -> Vec<usize> {
1845 vec![0, 1, 2, 1, 2, 3, 2, 3, 4, 3, 4, 5]
1854 }
1855
1856 fn striped_matrix(nrows: usize, ncols: usize) -> Owned<usize> {
1857 Owned::from_fn(nrows, ncols, |rc| rc.row * 100 + rc.col)
1858 }
1859
1860 fn assert_exact_fused<I>(mut iter: I, expected: usize)
1861 where
1862 I: ExactSizeIterator + std::iter::FusedIterator,
1863 {
1864 assert_eq!(iter.len(), expected);
1865 assert_eq!(iter.size_hint(), (expected, Some(expected)));
1866
1867 for remaining in (0..expected).rev() {
1868 assert!(iter.next().is_some());
1869 assert_eq!(iter.len(), remaining);
1870 assert_eq!(iter.size_hint(), (remaining, Some(remaining)));
1871 }
1872
1873 assert!(iter.next().is_none());
1874 assert!(iter.next().is_none());
1875 assert_eq!(iter.len(), 0);
1876 assert_eq!(iter.size_hint(), (0, Some(0)));
1877 }
1878
1879 fn assert_rows_match_scalar(m: Ref<'_, usize>, rows: Vec<&[usize]>) {
1881 let context = lazy_format!("nrows = {}, ncols = {}", m.nrows(), m.ncols());
1882
1883 assert_eq!(rows.len(), m.nrows(), "{context}");
1884
1885 for (row_index, row) in rows.into_iter().enumerate() {
1886 assert_eq!(row.len(), m.ncols(), "row = {row_index} -- {context}");
1887 for (col_index, value) in row.iter().enumerate() {
1888 assert_eq!(
1889 value,
1890 m.element(row_index, col_index),
1891 "row = {row_index}, col = {col_index} -- {context}"
1892 );
1893 }
1894 }
1895 }
1896
1897 fn assert_windows_match_scalar(
1898 m: Ref<'_, usize>,
1899 batchsize: usize,
1900 windows: Vec<Ref<'_, usize>>,
1901 ) {
1902 let context = lazy_format!(
1903 "nrows = {}, ncols = {}, batchsize = {batchsize}",
1904 m.nrows(),
1905 m.ncols()
1906 );
1907
1908 assert_eq!(windows.len(), m.nrows().div_ceil(batchsize), "{context}");
1909
1910 for (window_index, window) in windows.into_iter().enumerate() {
1911 let window_context = lazy_format!("window = {window_index} -- {context}");
1912 let first_row = window_index * batchsize;
1913 let expected_rows = batchsize.min(m.nrows() - first_row);
1914 assert_eq!(window.nrows(), expected_rows, "{window_context}");
1915 assert_eq!(window.ncols(), m.ncols(), "{window_context}");
1916
1917 for row_index in 0..window.nrows() {
1918 for col_index in 0..window.ncols() {
1919 assert_eq!(
1920 window.element(row_index, col_index),
1921 m.element(first_row + row_index, col_index),
1922 "row = {row_index}, col = {col_index} -- {window_context}"
1923 );
1924 }
1925 }
1926 }
1927 }
1928
1929 #[cfg(all(not(miri), feature = "rayon"))]
1930 fn assert_parallel_rows_match_scalar(m: Ref<'_, usize>) {
1931 let rows: Vec<_> = m.par_rows().collect();
1932 assert_rows_match_scalar(m, rows);
1933 }
1934
1935 #[cfg(all(not(miri), feature = "rayon"))]
1936 fn assert_parallel_windows_match_scalar(m: Ref<'_, usize>, batchsize: usize) {
1937 let windows: Vec<_> = m.par_window_iter(batchsize).collect();
1938 assert_windows_match_scalar(m, batchsize, windows);
1939 }
1940
1941 fn test_basic_indexing<T>(m: &T)
1943 where
1944 T: Matrix<Element = usize> + Sync,
1945 {
1946 assert_eq!(m.nrows(), 4);
1947 assert_eq!(m.ncols(), 3);
1948
1949 assert_eq!(*m.element(0, 0), 0);
1951 assert_eq!(*m.element(0, 1), 1);
1952 assert_eq!(*m.element(0, 2), 2);
1953
1954 assert_eq!(*m.element(1, 0), 1);
1955 assert_eq!(*m.element(1, 1), 2);
1956 assert_eq!(*m.element(1, 2), 3);
1957
1958 assert_eq!(*m.element(2, 0), 2);
1959 assert_eq!(*m.element(2, 1), 3);
1960 assert_eq!(*m.element(2, 2), 4);
1961
1962 assert_eq!(*m.element(3, 0), 3);
1963 assert_eq!(*m.element(3, 1), 4);
1964 assert_eq!(*m.element(3, 2), 5);
1965
1966 assert_eq!(*m.get_element(0, 0).unwrap(), 0);
1967 assert_eq!(*m.get_element(0, 1).unwrap(), 1);
1968 assert_eq!(*m.get_element(0, 2).unwrap(), 2);
1969
1970 assert_eq!(*m.get_element(1, 0).unwrap(), 1);
1971 assert_eq!(*m.get_element(1, 1).unwrap(), 2);
1972 assert_eq!(*m.get_element(1, 2).unwrap(), 3);
1973
1974 assert_eq!(*m.get_element(2, 0).unwrap(), 2);
1975 assert_eq!(*m.get_element(2, 1).unwrap(), 3);
1976 assert_eq!(*m.get_element(2, 2).unwrap(), 4);
1977
1978 assert_eq!(*m.get_element(3, 0).unwrap(), 3);
1979 assert_eq!(*m.get_element(3, 1).unwrap(), 4);
1980 assert_eq!(*m.get_element(3, 2).unwrap(), 5);
1981
1982 assert_eq!(m.row(0), &[0, 1, 2]);
1984 assert_eq!(m.row(1), &[1, 2, 3]);
1985 assert_eq!(m.row(2), &[2, 3, 4]);
1986 assert_eq!(m.row(3), &[3, 4, 5]);
1987
1988 let rows: Vec<Vec<usize>> = m.rows().map(|x| x.to_vec()).collect();
1989 assert_eq!(m.row(0), &rows[0]);
1990 assert_eq!(m.row(1), &rows[1]);
1991 assert_eq!(m.row(2), &rows[2]);
1992 assert_eq!(m.row(3), &rows[3]);
1993
1994 let batchsize = 2;
1996 m.window_iter(NonZeroUsize::new(batchsize).unwrap())
1997 .enumerate()
1998 .for_each(|(i, submatrix)| {
1999 assert_eq!(submatrix.nrows(), batchsize);
2000 assert_eq!(submatrix.ncols(), m.ncols());
2001
2002 let base = i * batchsize;
2004 assert_eq!(*submatrix.element(0, 0), base);
2005 assert_eq!(*submatrix.element(0, 1), base + 1);
2006 assert_eq!(*submatrix.element(0, 2), base + 2);
2007
2008 assert_eq!(*submatrix.element(1, 0), base + 1);
2009 assert_eq!(*submatrix.element(1, 1), base + 2);
2010 assert_eq!(*submatrix.element(1, 2), base + 3);
2011 });
2012
2013 let batchsize = 3;
2016 m.window_iter(NonZeroUsize::new(batchsize).unwrap())
2017 .enumerate()
2018 .for_each(|(i, submatrix)| {
2019 if i == 0 {
2020 assert_eq!(submatrix.nrows(), batchsize);
2021 assert_eq!(submatrix.ncols(), m.ncols());
2022
2023 assert_eq!(*submatrix.element(0, 0), 0);
2025 assert_eq!(*submatrix.element(0, 1), 1);
2026 assert_eq!(*submatrix.element(0, 2), 2);
2027
2028 assert_eq!(*submatrix.element(1, 0), 1);
2029 assert_eq!(*submatrix.element(1, 1), 2);
2030 assert_eq!(*submatrix.element(1, 2), 3);
2031
2032 assert_eq!(*submatrix.element(2, 0), 2);
2033 assert_eq!(*submatrix.element(2, 1), 3);
2034 assert_eq!(*submatrix.element(2, 2), 4);
2035 } else {
2036 assert_eq!(submatrix.nrows(), 1);
2037 assert_eq!(submatrix.ncols(), m.ncols());
2038
2039 assert_eq!(*submatrix.element(0, 0), 3);
2041 assert_eq!(*submatrix.element(0, 1), 4);
2042 assert_eq!(*submatrix.element(0, 2), 5);
2043 }
2044 });
2045 }
2046
2047 #[test]
2048 fn matrix_happy_path() {
2049 let data = make_test_matrix();
2050 let m = Owned::try_from_data(data.into(), 4, 3).unwrap();
2051 test_basic_indexing(&m);
2052
2053 let ptr = m.as_ptr();
2056 let view = m.as_view();
2057 assert!(is_copyable(view));
2058 assert_eq!(view.as_ptr(), ptr);
2059 assert_eq!(view.nrows(), m.nrows());
2060 assert_eq!(view.ncols(), m.ncols());
2061 test_basic_indexing(&view);
2062 }
2063
2064 #[test]
2065 fn matrix_try_from_construction_error() {
2066 let data = make_test_matrix();
2067 let ptr = data.as_ptr();
2068 let len = data.len();
2069
2070 let m = Owned::try_from_data(data.into(), 5, 4);
2071 assert!(m.is_err());
2072 let err = m.unwrap_err();
2073 assert_eq!(
2074 err.to_string(),
2075 "tried to construct a 5x4 matrix over a span of length 12"
2076 );
2077
2078 let data = err.into_inner();
2080 assert_eq!(data.as_ptr(), ptr);
2081 assert_eq!(data.len(), len);
2082
2083 let m = Ref::try_from_data(&data, 5, 4);
2084 assert!(m.is_err());
2085 assert_eq!(
2086 m.unwrap_err().to_string(),
2087 "tried to construct a 5x4 matrix over a span of length 12"
2088 );
2089 }
2090
2091 #[test]
2092 fn mutable_matrix_direct_construction() {
2093 let mut data = make_test_matrix();
2094
2095 {
2096 let mut m = Mut::try_from_data(data.as_mut_slice(), 4, 3).unwrap();
2097 *m.element_mut(1, 2) = 30;
2098 }
2099 assert_eq!(data[5], 30);
2100
2101 let err = Mut::try_from_data(data.as_mut_slice(), 5, 4).unwrap_err();
2102 assert_eq!(
2103 err.to_string(),
2104 "tried to construct a 5x4 matrix over a span of length 12"
2105 );
2106 let recovered = err.into_inner();
2107 recovered[0] = 10;
2108 assert_eq!(data[0], 10);
2109 }
2110
2111 #[test]
2112 fn matrix_mut_view() {
2113 let mut m = Owned::<usize>::from_element(4, 3, 0);
2114 assert_eq!(m.nrows(), 4);
2115 assert_eq!(m.ncols(), 3);
2116 assert!(m.as_slice().iter().all(|&i| i == 0));
2117 let ptr = m.as_ptr();
2118 let mut_ptr = m.as_mut_ptr();
2119 assert_eq!(ptr, mut_ptr);
2120
2121 let mut view = m.as_view_mut();
2122 assert_eq!(view.nrows(), 4);
2123 assert_eq!(view.ncols(), 3);
2124 assert_eq!(view.as_ptr(), ptr);
2125 assert_eq!(view.as_mut_ptr(), mut_ptr);
2126
2127 for i in 0..view.nrows() {
2129 for j in 0..view.ncols() {
2130 *view.element_mut(i, j) = i + j;
2131 }
2132 }
2133
2134 test_basic_indexing(&m);
2136
2137 let mut m_clone = m.clone();
2139 assert_eq!(m.as_view_mut(), m_clone.as_view_mut());
2140
2141 let inner = m.into_inner();
2142 assert_eq!(inner.as_ptr(), ptr);
2143 assert_eq!(inner.len(), 4 * 3);
2144 }
2145
2146 #[test]
2147 fn matrix_view_zero_sizes() {
2148 let data: Vec<usize> = vec![];
2149 let m = Ref::try_from_data(data.as_slice(), 0, 10).unwrap();
2151 assert_eq!(m.nrows(), 0);
2152 assert_eq!(m.ncols(), 10);
2153
2154 let m = Ref::try_from_data(data.as_slice(), 3, 0).unwrap();
2156 assert_eq!(m.nrows(), 3);
2157 assert_eq!(m.ncols(), 0);
2158 let empty: &[usize] = &[];
2159 assert_eq!(m.row(0), empty);
2160 assert_eq!(m.row(1), empty);
2161 assert_eq!(m.row(2), empty);
2162
2163 let m = Ref::try_from_data(data.as_slice(), 0, 0).unwrap();
2165 assert_eq!(m.nrows(), 0);
2166 assert_eq!(m.ncols(), 0);
2167 }
2168
2169 #[test]
2170 fn matrix_construction_by_row() {
2171 let mut m = Owned::<usize>::from_element(4, 3, 0);
2172 assert!(m.as_slice().iter().all(|i| *i == 0));
2173
2174 let ncols = m.ncols();
2175 for i in 0..m.nrows() {
2176 let row = m.row_mut(i);
2177 assert_eq!(row.len(), ncols);
2178 row[0] = i;
2179 row[1] = i + 1;
2180 row[2] = i + 2;
2181 }
2182 test_basic_indexing(&m);
2183 }
2184
2185 #[test]
2187 #[should_panic(expected = "tried to access row 3 of a matrix with 3 rows")]
2188 fn test_get_row_panics() {
2189 let m = Owned::<usize>::from_element(3, 7, 0);
2190 m.row(3);
2191 }
2192
2193 #[test]
2194 #[should_panic(expected = "tried to access row 3 of a matrix with 3 rows")]
2195 fn test_get_row_mut_panics() {
2196 let mut m = Owned::<usize>::from_element(3, 7, 0);
2197 m.row_mut(3);
2198 }
2199
2200 #[test]
2201 #[should_panic(expected = "row 3 is out of bounds (max: 3)")]
2202 fn test_element_panics_row() {
2203 let m = Owned::<usize>::from_element(3, 7, 0);
2204 assert!(m.get_element(3, 2).is_none());
2205 let _ = m.element(3, 2);
2206 }
2207
2208 #[test]
2209 #[should_panic(expected = "col 7 is out of bounds (max: 7)")]
2210 fn test_element_panics_col() {
2211 let m = Owned::<usize>::from_element(3, 7, 0);
2212 assert!(m.get_element(2, 7).is_none());
2213 let _ = m.element(2, 7);
2214 }
2215
2216 #[test]
2217 #[should_panic(expected = "row 3 is out of bounds (max: 3)")]
2218 fn test_element_mut_panics_row() {
2219 let mut m = Owned::<usize>::from_element(3, 7, 0);
2220 assert!(m.get_element_mut(3, 2).is_none());
2221 *m.element_mut(3, 2) = 1;
2222 }
2223
2224 #[test]
2225 #[should_panic(expected = "col 7 is out of bounds (max: 7)")]
2226 fn test_element_mut_panics_col() {
2227 let mut m = Owned::<usize>::from_element(3, 7, 0);
2228 assert!(m.get_element_mut(2, 7).is_none());
2229 *m.element_mut(2, 7) = 1;
2230 }
2231
2232 #[test]
2233 #[cfg(feature = "rayon")]
2234 #[should_panic(expected = "par_window_iter batchsize cannot be zero")]
2235 fn test_par_window_iter_panics() {
2236 let m = Owned::<usize>::from_element(4, 4, 0);
2237 let _ = m.par_window_iter(0);
2238 }
2239
2240 #[test]
2241 #[cfg(feature = "rayon")]
2242 #[should_panic(expected = "par_window_iter_mut batchsize cannot be zero")]
2243 fn test_par_window_iter_mut_panics() {
2244 let mut m = Owned::<usize>::from_element(4, 4, 0);
2245 let _ = m.par_window_iter_mut(0);
2246 }
2247
2248 #[test]
2251 fn test_try_from_error_light() {
2252 let data = vec![1, 2, 3];
2254 let err = Ref::try_from_data(data.as_slice(), 2, 3).unwrap_err();
2255
2256 let err_static = err.as_static();
2258 let msg = err_static.to_string();
2259 assert_contains!(
2260 msg,
2261 "tried to construct a 2x3 matrix over a span of length 3",
2262 );
2263 let recovered_data = err.into_inner();
2265 assert_eq!(recovered_data, data.as_slice());
2266
2267 let err = Ref::try_from_data(data.as_slice(), 2, usize::MAX).unwrap_err();
2269 let msg = err.to_string();
2270 assert_contains!(msg, "usize::MAX");
2271
2272 assert_eq!(data.as_slice(), err.into_inner());
2273 }
2274
2275 #[test]
2276 fn test_map_errors() {
2277 #[derive(Debug, Clone, Copy)]
2278 struct Zst;
2279
2280 let b = Box::<[Zst]>::new_uninit_slice((isize::MAX as usize) + 1);
2282
2283 let b = unsafe { b.assume_init() };
2285
2286 let m = Owned::column_vector(b);
2287 let err = m.try_map(|_: &Zst| 0u8).unwrap_err();
2288 let msg = err.to_string();
2289 assert!(msg.contains("isize::MAX"), "{msg}");
2290
2291 let err = std::panic::catch_unwind(|| m.map(|_: &Zst| 0u8))
2293 .unwrap_err()
2294 .downcast::<String>()
2295 .unwrap();
2296 let msg = err.to_string();
2297 assert!(msg.contains("isize::MAX"), "{msg}");
2298 }
2299
2300 #[test]
2301 fn test_get_row_optional() {
2302 let data = make_test_matrix();
2303 let mut m = Owned::try_from_data(data.into(), 4, 3).unwrap();
2304
2305 assert_eq!(m.get_row(0), Some(&[0, 1, 2][..]));
2306 assert_eq!(m.get_row(1), Some(&[1, 2, 3][..]));
2307 assert_eq!(m.get_row(3), Some(&[3, 4, 5][..]));
2308 assert_eq!(m.get_row(4), None);
2309 assert_eq!(m.get_row(100), None);
2310
2311 let row = m.get_row_mut(1).unwrap();
2312 assert_eq!(row, &[1, 2, 3]);
2313 row[0] = 10;
2314 assert_eq!(m.row(1), &[10, 2, 3]);
2315 assert!(m.get_row_mut(4).is_none());
2316 assert!(m.get_row_mut(100).is_none());
2317 }
2318
2319 #[test]
2320 fn test_unsafe_get_unchecked_methods() {
2321 let data = make_test_matrix();
2322 let mut m = Owned::try_from_data(data.into(), 4, 3).unwrap();
2323
2324 unsafe {
2326 assert_eq!(*m.element_unchecked(0, 0), 0);
2327 assert_eq!(*m.element_unchecked(1, 2), 3);
2328 assert_eq!(*m.element_unchecked(3, 1), 4);
2329 }
2330
2331 unsafe {
2333 *m.element_unchecked_mut(0, 0) = 100;
2334 *m.element_unchecked_mut(1, 2) = 200;
2335 }
2336
2337 assert_eq!(*m.element(0, 0), 100);
2338 assert_eq!(*m.element(1, 2), 200);
2339
2340 unsafe {
2342 let row0 = m.row_unchecked(0);
2343 assert_eq!(row0[0], 100);
2344 assert_eq!(row0[1], 1);
2345 assert_eq!(row0[2], 2);
2346 }
2347
2348 unsafe {
2350 let row1 = m.row_unchecked_mut(1);
2351 row1[0] = 300;
2352 }
2353
2354 assert_eq!(*m.element(1, 0), 300);
2355 }
2356
2357 #[test]
2358 fn test_to_owned() {
2359 let data = make_test_matrix();
2360 let view = Ref::try_from_data(data.as_slice(), 4, 3).unwrap();
2361
2362 let owned: Owned<_> = view.to_rowmajor_owned();
2364 assert_eq!(owned.nrows(), view.nrows());
2365 assert_eq!(owned.ncols(), view.ncols());
2366 assert_eq!(owned.as_slice(), view.as_slice());
2367
2368 assert_ne!(owned.as_ptr(), view.as_ptr());
2370
2371 test_basic_indexing(&owned);
2373 }
2374
2375 #[test]
2376 fn test_matrix_from_conversions() {
2377 let data = make_test_matrix();
2378 let m = Owned::try_from_data(data.into(), 4, 3).unwrap();
2379
2380 let view = m.as_view();
2382 let slice: &[usize] = view.into_slice();
2383 assert_eq!(slice.len(), 12);
2384 assert_eq!(slice[0], 0);
2385 assert_eq!(slice[11], 5);
2386
2387 let data2 = make_test_matrix();
2389 let mut m2 = Owned::try_from_data(data2.into(), 4, 3).unwrap();
2390 let mut_view = m2.as_view_mut();
2391 let slice2: &mut [usize] = mut_view.into_mut_slice();
2392 assert_eq!(slice2.len(), 12);
2393 assert_eq!(slice2[0], 0);
2394 assert_eq!(slice2[11], 5);
2395 slice2[11] = 6;
2396 assert_eq!(*m2.element(3, 2), 6);
2397 }
2398
2399 #[test]
2400 fn test_row_vector() {
2401 let data = vec![1, 2, 3];
2402 let m = Ref::row_vector(data.as_slice());
2403 assert_eq!(m.nrows(), 1);
2404 assert_eq!(m.ncols(), 3);
2405 assert_eq!(m.as_slice(), &[1, 2, 3]);
2406 assert_eq!(m.row(0), &[1, 2, 3]);
2407
2408 let empty: &[i32] = &[];
2410 let m = Ref::row_vector(empty);
2411 assert_eq!(m.nrows(), 1);
2412 assert_eq!(m.ncols(), 0);
2413
2414 let m = Owned::row_vector(vec![10u64, 20].into_boxed_slice());
2416 assert_eq!(m.nrows(), 1);
2417 assert_eq!(m.ncols(), 2);
2418 assert_eq!(*m.element(0, 0), 10);
2419 assert_eq!(*m.element(0, 1), 20);
2420 }
2421
2422 #[test]
2423 fn test_column_vector() {
2424 let data = vec![1, 2, 3];
2425 let m = Ref::column_vector(data.as_slice());
2426 assert_eq!(m.nrows(), 3);
2427 assert_eq!(m.ncols(), 1);
2428 assert_eq!(m.as_slice(), &[1, 2, 3]);
2429 assert_eq!(*m.element(0, 0), 1);
2430 assert_eq!(*m.element(1, 0), 2);
2431 assert_eq!(*m.element(2, 0), 3);
2432 assert_eq!(m.row(0), &[1]);
2433 assert_eq!(m.row(1), &[2]);
2434 assert_eq!(m.row(2), &[3]);
2435
2436 let empty: &[i32] = &[];
2438 let m = Ref::column_vector(empty);
2439 assert_eq!(m.nrows(), 0);
2440 assert_eq!(m.ncols(), 1);
2441
2442 let m = Owned::column_vector(vec![10u64, 20].into_boxed_slice());
2444 assert_eq!(m.nrows(), 2);
2445 assert_eq!(m.ncols(), 1);
2446 assert_eq!(*m.element(0, 0), 10);
2447 assert_eq!(*m.element(1, 0), 20);
2448 }
2449
2450 #[test]
2451 fn test_map() {
2452 let m = Owned::try_from_data(vec![1u32, 2, 3, 4].into(), 2, 2).unwrap();
2453 let doubled = m.map(|&x| x * 2);
2454 assert_eq!(doubled.as_slice(), &[2, 4, 6, 8]);
2455 assert_eq!(doubled.nrows(), 2);
2456 assert_eq!(doubled.ncols(), 2);
2457
2458 let as_f64 = m.map(|&x| x as f64);
2460 assert_eq!(as_f64.as_slice(), &[1.0, 2.0, 3.0, 4.0]);
2461 }
2462
2463 #[test]
2464 fn test_get_element() {
2465 let mut m = Owned::try_from_data(vec![1, 2, 3, 4, 5, 6].into(), 2, 3).unwrap();
2466 assert_eq!(m.get_element(0, 0), Some(&1));
2467 assert_eq!(m.get_element(1, 2), Some(&6));
2468 assert_eq!(m.get_element(2, 0), None);
2469 assert_eq!(m.get_element(0, 3), None);
2470
2471 *m.get_element_mut(1, 2).unwrap() = 7;
2472 assert_eq!(m.get_element(1, 2), Some(&7));
2473 assert_eq!(m.get_element_mut(2, 0), None);
2474 assert_eq!(m.get_element_mut(0, 3), None);
2475 }
2476
2477 fn check_subviews<T>(m: &mut Owned<T>, rows: std::ops::Range<usize>) -> Option<Ref<'_, T>> {
2480 let expected = m
2481 .subview_mut(rows.clone())
2482 .map(|v| (v.as_ptr(), v.layout()));
2483 let subview = m.subview(rows);
2484 assert_eq!(subview.map(|v| (v.as_ptr(), v.layout())), expected);
2485 subview
2486 }
2487
2488 #[test]
2489 fn test_subviews() {
2490 let data = make_test_matrix();
2491 let mut m = Owned::try_from_data(data.into(), 4, 3).unwrap();
2492
2493 {
2495 let subview = check_subviews(&mut m, 0..4).unwrap();
2496 assert_eq!(subview.nrows(), 4);
2497 assert_eq!(subview.ncols(), 3);
2498
2499 assert_eq!(subview.row(0), &[0, 1, 2]);
2500 assert_eq!(subview.row(1), &[1, 2, 3]);
2501 assert_eq!(subview.row(2), &[2, 3, 4]);
2502 assert_eq!(subview.row(3), &[3, 4, 5]);
2503 assert!(subview.get_row(4).is_none());
2504 }
2505
2506 {
2508 let subview = check_subviews(&mut m, 1..4).unwrap();
2509 assert_eq!(subview.nrows(), 3);
2510 assert_eq!(subview.ncols(), 3);
2511
2512 assert_eq!(subview.row(0), &[1, 2, 3]);
2513 assert_eq!(subview.row(1), &[2, 3, 4]);
2514 assert_eq!(subview.row(2), &[3, 4, 5]);
2515 assert!(subview.get_row(3).is_none());
2516 }
2517
2518 {
2520 let subview = check_subviews(&mut m, 2..2).unwrap();
2521 assert_eq!(subview.nrows(), 0);
2522 assert_eq!(subview.ncols(), 3);
2523 }
2524
2525 {
2527 let subview = check_subviews(&mut m, 0..0).unwrap();
2528 assert_eq!(subview.nrows(), 0);
2529 assert_eq!(subview.ncols(), 3);
2530
2531 let subview = check_subviews(&mut m, 4..4).unwrap();
2532 assert_eq!(subview.nrows(), 0);
2533 assert_eq!(subview.ncols(), 3);
2534 }
2535
2536 assert!(check_subviews(&mut m, 5..5).is_none());
2538
2539 assert!(check_subviews(&mut m, 2..10).is_none());
2541
2542 #[expect(
2544 clippy::reversed_empty_ranges,
2545 reason = "we want to make sure it doesn't work"
2546 )]
2547 let empty = 3..2;
2548 assert!(check_subviews(&mut m, empty).is_none());
2549
2550 assert!(check_subviews(&mut m, usize::MAX - 1..usize::MAX).is_none());
2552
2553 {
2555 let mut outer = m.subview_mut(1..4).unwrap();
2556 outer.row_mut(0).copy_from_slice(&[10, 11, 12]);
2557
2558 let mut inner = outer.subview_mut(1..2).unwrap();
2559 assert_eq!(inner.row(0), &[2, 3, 4]);
2560 inner.as_mut_slice().fill(7);
2561 }
2562 assert_eq!(m.as_slice(), &[0, 1, 2, 10, 11, 12, 7, 7, 7, 3, 4, 5]);
2563 }
2564
2565 #[expect(
2566 clippy::reversed_empty_ranges,
2567 reason = "we want to make sure it doesn't work"
2568 )]
2569 #[test]
2570 fn test_subview_zero_cols() {
2571 let mut m = Owned::from_element(10, 0, 0u32);
2572
2573 assert!(check_subviews(&mut m, 100..200).is_none());
2575
2576 assert!(check_subviews(&mut m, 10..11).is_none());
2578
2579 assert!(check_subviews(&mut m, 5..4).is_none());
2581
2582 let v = check_subviews(&mut m, 5..10).unwrap();
2584 assert_eq!(v.nrows(), 5);
2585 assert_eq!(v.ncols(), 0);
2586
2587 let v = check_subviews(&mut m, 10..10).unwrap();
2589 assert_eq!(v.nrows(), 0);
2590 assert_eq!(v.ncols(), 0);
2591
2592 let v = check_subviews(&mut m, 0..10).unwrap();
2594 assert_eq!(v.nrows(), 10);
2595 assert_eq!(v.ncols(), 0);
2596 }
2597
2598 #[test]
2599 #[cfg(all(not(miri), feature = "rayon"))]
2600 fn parallel_immutable_iterators_match_scalar_indexing() {
2601 for (nrows, ncols) in [(0, 0), (0, 4), (3, 0), (1, 1), (1, 4), (4, 1), (5, 3)] {
2602 let m = striped_matrix(nrows, ncols);
2603 let view = m.as_view();
2604
2605 assert_parallel_rows_match_scalar(view);
2606 for batchsize in [1, 2, 3, usize::MAX] {
2607 assert_parallel_windows_match_scalar(view, batchsize);
2608 }
2609 }
2610 }
2611
2612 #[test]
2613 #[cfg(all(not(miri), feature = "rayon"))]
2614 fn parallel_mutable_iterators_match_scalar_indexing() {
2615 use rayon::prelude::*;
2616
2617 for (nrows, ncols) in [(0, 0), (0, 4), (3, 0), (1, 1), (1, 4), (4, 1), (5, 3)] {
2618 let context = lazy_format!("nrows = {nrows}, ncols = {ncols}");
2619
2620 let original = striped_matrix(nrows, ncols);
2621 let mut rows = original.clone();
2622
2623 let row_views: Vec<_> = rows.par_rows_mut().collect();
2624 assert_eq!(row_views.len(), nrows, "{context}");
2625 for (row_index, row) in row_views.into_iter().enumerate() {
2626 assert_eq!(row.len(), ncols, "row = {row_index} -- {context}");
2627 for value in row {
2628 *value = value.wrapping_add(row_index);
2629 }
2630 }
2631
2632 for row in 0..nrows {
2633 for col in 0..ncols {
2634 assert_eq!(
2635 *rows.element(row, col),
2636 original.element(row, col).wrapping_add(row),
2637 "row = {}, col = {} -- {}",
2638 row,
2639 col,
2640 context,
2641 );
2642 }
2643 }
2644
2645 for batchsize in [1, 2, 3, usize::MAX] {
2646 let context = lazy_format!("{context}, batchsize = {batchsize}");
2647
2648 let mut windows = original.clone();
2649 let window_views: Vec<_> = windows.par_window_iter_mut(batchsize).collect();
2650 assert_eq!(window_views.len(), nrows.div_ceil(batchsize), "{context}");
2651 for (window_index, mut window) in window_views.into_iter().enumerate() {
2652 let first_row = window_index * batchsize;
2653 assert_eq!(
2654 window.nrows(),
2655 batchsize.min(nrows - first_row),
2656 "window = {window_index} -- {context}"
2657 );
2658 assert_eq!(
2659 window.ncols(),
2660 ncols,
2661 "window = {window_index} -- {context}"
2662 );
2663 for value in window.as_mut_slice() {
2664 *value = value.wrapping_add(window_index);
2665 }
2666 }
2667
2668 for row in 0..nrows {
2669 for col in 0..ncols {
2670 assert_eq!(
2671 *windows.element(row, col),
2672 original.element(row, col).wrapping_add(row / batchsize),
2673 "row = {}, col = {} -- {}",
2674 row,
2675 col,
2676 context,
2677 );
2678 }
2679 }
2680 }
2681 }
2682 }
2683
2684 #[test]
2685 fn matrix_iterators_match_scalar_indexing() {
2686 for (nrows, ncols) in [(0, 0), (0, 4), (3, 0), (1, 1), (1, 4), (4, 1), (5, 3)] {
2687 let original = striped_matrix(nrows, ncols);
2688 let view = original.as_view();
2689
2690 let rows = view.rows().collect();
2691 assert_rows_match_scalar(view, rows);
2692 for batchsize in [1, 2, 3, usize::MAX] {
2693 let windows = view
2694 .window_iter(NonZeroUsize::new(batchsize).unwrap())
2695 .collect();
2696 assert_windows_match_scalar(view, batchsize, windows);
2697 }
2698
2699 let context = lazy_format!("nrows = {nrows}, ncols = {ncols}");
2700 let mut mutable = original.clone();
2701 let rows: Vec<_> = mutable.rows_mut().collect();
2702 assert_eq!(rows.len(), nrows, "{context}");
2703
2704 for (row_index, row) in rows.into_iter().enumerate() {
2705 assert_eq!(row.len(), ncols, "row = {row_index} -- {context}");
2706 for (col_index, value) in row.iter_mut().enumerate() {
2707 assert_eq!(
2708 *value,
2709 *original.element(row_index, col_index),
2710 "row = {row_index}, col = {col_index} -- {context}"
2711 );
2712 *value = value.wrapping_add(1);
2713 }
2714 }
2715
2716 for row in 0..nrows {
2717 for col in 0..ncols {
2718 assert_eq!(
2719 *mutable.element(row, col),
2720 original.element(row, col).wrapping_add(1),
2721 "row = {row}, col = {col} -- {context}"
2722 );
2723 }
2724 }
2725 }
2726 }
2727
2728 #[test]
2729 fn matrix_iterators_track_exact_remaining_lengths() {
2730 for (nrows, ncols) in [(0, 0), (0, 4), (3, 0), (5, 3)] {
2731 let mut m = striped_matrix(nrows, ncols);
2732
2733 assert_exact_fused(m.rows(), nrows);
2734 assert_exact_fused(m.rows_mut(), nrows);
2735
2736 for batchsize in [1, 2, usize::MAX] {
2737 assert_exact_fused(
2738 m.window_iter(NonZeroUsize::new(batchsize).unwrap()),
2739 nrows.div_ceil(batchsize),
2740 );
2741 }
2742 }
2743 }
2744
2745 #[test]
2746 fn matrix_transformations_preserve_empty_shapes() {
2747 for (nrows, ncols) in [(0, 0), (0, 4), (3, 0)] {
2748 let m = striped_matrix(nrows, ncols);
2749
2750 let owned = m.to_rowmajor_owned();
2751 assert_eq!(owned.nrows(), nrows);
2752 assert_eq!(owned.ncols(), ncols);
2753
2754 let mapped = m.map(|_| -> u8 { unreachable!("empty matrix has no elements") });
2755 assert_eq!(mapped.nrows(), nrows);
2756 assert_eq!(mapped.ncols(), ncols);
2757 }
2758 }
2759
2760 #[test]
2761 fn owned_from_fn_initializes_in_memory_order() {
2762 let mut value = 0;
2763 let m = Owned::from_fn(2, 3, |_| {
2764 let result = value;
2765 value += 1;
2766 result
2767 });
2768
2769 assert_eq!(*m.element(0, 0), 0);
2770 assert_eq!(*m.element(0, 1), 1);
2771 assert_eq!(*m.element(0, 2), 2);
2772 assert_eq!(*m.element(1, 0), 3);
2773 assert_eq!(*m.element(1, 1), 4);
2774 assert_eq!(*m.element(1, 2), 5);
2775 }
2776
2777 #[test]
2778 fn test_transpose() {
2779 {
2780 let v = Owned::from_element(0, 0, 0);
2781 let t = v.transpose();
2782 assert_eq!(t.nrows(), 0);
2783 assert_eq!(t.ncols(), 0);
2784 }
2785
2786 {
2787 let v = Owned::from_element(0, 10, 0);
2788 let t = v.transpose();
2789 assert_eq!(t.nrows(), 10);
2790 assert_eq!(t.ncols(), 0);
2791 }
2792
2793 {
2794 let v = Owned::from_element(10, 0, 0);
2795 let t = v.transpose();
2796 assert_eq!(t.nrows(), 0);
2797 assert_eq!(t.ncols(), 10);
2798 }
2799
2800 {
2801 let v = Owned::<usize>::try_from_data(Box::new([1, 2, 3, 4, 5, 6]), 2, 3).unwrap();
2802 let t = v.transpose();
2803
2804 assert_eq!(t.row(0), &[1, 4]);
2805 assert_eq!(t.row(1), &[2, 5]);
2806 assert_eq!(t.row(2), &[3, 6]);
2807 }
2808 }
2809
2810 #[test]
2811 fn test_debug_error_formatting() {
2812 let data = vec![1, 2, 3];
2814 let err = Owned::try_from_data(data.into(), 2, 3).unwrap_err();
2815 let debug_str = format!("{:?}", err);
2816 assert_contains!(debug_str, "TryFromError");
2817
2818 #[derive(Clone)]
2820 struct NonDebug(#[expect(dead_code)] i32);
2821
2822 let non_debug_data: Box<[NonDebug]> = vec![NonDebug(1), NonDebug(2)].into();
2823 let non_debug_err = match Owned::try_from_data(non_debug_data, 1, 3) {
2824 Ok(_) => panic!("should not have succeeded!"),
2825 Err(err) => err,
2826 };
2827 let debug_str = format!("{:?}", non_debug_err);
2828 assert_contains!(debug_str, "TryFromError");
2829 }
2830}