1#![doc = include_str!("../README.md")]
2#![no_std] use core::fmt::Debug;
5
6use generic_array::{ArrayLength, GenericArray, IntoArrayLength, functional::FunctionalSequence};
7use nalgebra::{
8 DefaultAllocator, IsContiguous, Matrix, OMatrix, Owned, RawStorage, RawStorageMut, Scalar,
9 Storage, allocator::Allocator,
10};
11
12mod conv;
13pub use conv::Conv;
14
15#[repr(transparent)]
19pub struct GenericArrayStorage<T, R: Conv, C: Conv>(
20 pub GenericArray<GenericArray<T, R::TNum>, C::TNum>,
21);
22
23impl<T: Debug, R: Conv, C: Conv> Debug for GenericArrayStorage<T, R, C> {
24 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
25 <GenericArray<GenericArray<T, R::TNum>, C::TNum> as Debug>::fmt(&self.0, f)
26 }
27}
28
29impl<T, R: Conv, C: Conv> Clone for GenericArrayStorage<T, R, C>
30where
31 T: Clone,
32 GenericArray<GenericArray<T, R::TNum>, C::TNum>: Clone,
33{
34 fn clone(&self) -> Self {
35 Self(self.0.clone())
36 }
37}
38
39impl<T, R: Conv, C: Conv> Copy for GenericArrayStorage<T, R, C>
40where
41 T: Copy,
42 <R::TNum as ArrayLength>::ArrayType<T>: Copy,
43 <C::TNum as ArrayLength>::ArrayType<GenericArray<T, R::TNum>>: Copy,
44{
45}
46
47impl<T, R: Conv, C: Conv> AsRef<[T]> for GenericArrayStorage<T, R, C> {
48 fn as_ref(&self) -> &[T] {
49 GenericArray::slice_from_chunks(&self.0)
50 }
51}
52
53impl<T, R: Conv, C: Conv> AsMut<[T]> for GenericArrayStorage<T, R, C> {
54 fn as_mut(&mut self) -> &mut [T] {
55 GenericArray::slice_from_chunks_mut(&mut self.0)
56 }
57}
58
59#[allow(unsafe_code, reason = "nalgebra storage traits are unsafe")]
60unsafe impl<T, R: Conv, C: Conv> RawStorage<T, R::Nalg, C::Nalg> for GenericArrayStorage<T, R, C> {
61 type RStride = nalgebra::U1;
62
63 type CStride = R::Nalg;
64
65 fn ptr(&self) -> *const T {
66 if self.0.is_empty() {
67 core::ptr::NonNull::<T>::dangling().as_ptr()
68 } else {
69 self.0.as_ptr().cast()
70 }
71 }
72
73 fn shape(&self) -> (R::Nalg, C::Nalg) {
74 (R::new_nalg(), C::new_nalg())
75 }
76
77 fn strides(&self) -> (Self::RStride, Self::CStride) {
78 (nalgebra::U1, R::new_nalg())
79 }
80
81 fn is_contiguous(&self) -> bool {
82 true
83 }
84
85 unsafe fn as_slice_unchecked(&self) -> &[T] {
86 self.as_ref()
87 }
88}
89
90#[allow(unsafe_code, reason = "nalgebra storage traits are unsafe")]
91unsafe impl<T, R: Conv, C: Conv> RawStorageMut<T, R::Nalg, C::Nalg>
92 for GenericArrayStorage<T, R, C>
93{
94 fn ptr_mut(&mut self) -> *mut T {
95 if self.0.is_empty() {
96 core::ptr::NonNull::<T>::dangling().as_ptr()
97 } else {
98 self.0.as_mut_ptr().cast()
99 }
100 }
101
102 unsafe fn as_mut_slice_unchecked(&mut self) -> &mut [T] {
103 self.as_mut()
105 }
106}
107
108#[allow(unsafe_code, reason = "nalgebra storage traits are unsafe")]
109unsafe impl<T: Scalar, R: Conv, C: Conv> Storage<T, R::Nalg, C::Nalg>
110 for GenericArrayStorage<T, R, C>
111where
112 nalgebra::DefaultAllocator: nalgebra::allocator::Allocator<R::Nalg, C::Nalg>,
113{
114 fn into_owned(self) -> Owned<T, R::Nalg, C::Nalg>
115 where
116 nalgebra::DefaultAllocator: nalgebra::allocator::Allocator<R::Nalg, C::Nalg>,
117 {
118 nalgebra::DefaultAllocator::allocate_from_iterator(
119 R::new_nalg(),
120 C::new_nalg(),
121 self.0.into_iter().flatten(),
122 )
123 }
124
125 fn clone_owned(&self) -> Owned<T, R::Nalg, C::Nalg>
126 where
127 nalgebra::DefaultAllocator: nalgebra::allocator::Allocator<R::Nalg, C::Nalg>,
128 {
129 self.clone().into_owned()
130 }
131
132 fn forget_elements(self) {
133 core::mem::forget(self);
134 }
135}
136
137#[allow(unsafe_code, reason = "nalgebra storage traits are unsafe")]
138unsafe impl<R: Conv, C: Conv, T: nalgebra::Scalar> IsContiguous for GenericArrayStorage<T, R, C> {}
139
140pub type GenericMatrix<T, R, C> =
142 nalgebra::Matrix<T, <R as Conv>::Nalg, <C as Conv>::Nalg, GenericArrayStorage<T, R, C>>;
143
144type TNum<const N: usize> = typenum::Const<N>;
145
146impl<T, const AR: usize, const AC: usize, R, C> From<[[T; AR]; AC]> for GenericArrayStorage<T, R, C>
147where
148 TNum<AR>: IntoArrayLength,
149 TNum<AC>: IntoArrayLength,
150 R: Conv<TNum = <TNum<AR> as IntoArrayLength>::ArrayLength>,
151 C: Conv<TNum = <TNum<AC> as IntoArrayLength>::ArrayLength>,
152{
153 fn from(value: [[T; AR]; AC]) -> Self {
154 let tnum_array: GenericArray<
155 GenericArray<T, <TNum<AR> as IntoArrayLength>::ArrayLength>,
156 <TNum<AC> as IntoArrayLength>::ArrayLength,
157 > = GenericArray::from_array(value.map(GenericArray::from_array));
158 Self(tnum_array)
159 }
160}
161
162impl<T, const AR: usize, const AC: usize, R, C> From<GenericArrayStorage<T, R, C>> for [[T; AR]; AC]
163where
164 TNum<AR>: IntoArrayLength,
165 TNum<AC>: IntoArrayLength,
166 R: Conv<TNum = <TNum<AR> as IntoArrayLength>::ArrayLength>,
167 C: Conv<TNum = <TNum<AC> as IntoArrayLength>::ArrayLength>,
168{
169 fn from(GenericArrayStorage(data): GenericArrayStorage<T, R, C>) -> Self {
170 data.map(GenericArray::into_array).into_array()
171 }
172}
173
174pub trait GenericMatrixFromExt<R: Conv, C: Conv> {
176 type T;
180
181 fn into_generic_matrix(self) -> GenericMatrix<Self::T, R, C>;
183}
184
185impl<T, const AR: usize, const AC: usize, R, C> GenericMatrixFromExt<R, C> for [[T; AR]; AC]
186where
187 TNum<AR>: IntoArrayLength,
188 TNum<AC>: IntoArrayLength,
189 R: Conv<TNum = <TNum<AR> as IntoArrayLength>::ArrayLength>,
190 C: Conv<TNum = <TNum<AC> as IntoArrayLength>::ArrayLength>,
191{
192 type T = T;
193
194 fn into_generic_matrix(self) -> GenericMatrix<Self::T, R, C> {
195 GenericMatrix::from_data(self.into())
196 }
197}
198
199impl<T, R, C> GenericMatrixFromExt<R, C> for OMatrix<T, R::Nalg, C::Nalg>
200where
201 T: Scalar,
202 R: Conv,
203 C: Conv,
204 DefaultAllocator: Allocator<R::Nalg, C::Nalg>,
205{
206 type T = T;
207
208 fn into_generic_matrix(self) -> GenericMatrix<Self::T, R, C> {
209 let (rows, rest) = GenericArray::<_, R::TNum>::chunks_from_slice(self.as_slice());
210 debug_assert!(rest.is_empty(), "Should be no leftover");
211 let arr = GenericArray::<_, C::TNum>::from_slice(rows);
212 let storage = GenericArrayStorage(arr.clone());
213 GenericMatrix::from_data(storage)
214 }
215}
216
217pub trait GenericMatrixExt {
219 type T: Scalar;
223
224 type R: Conv;
226
227 type C: Conv;
229
230 fn into_regular_matrix(
232 self,
233 ) -> OMatrix<Self::T, <Self::R as Conv>::Nalg, <Self::C as Conv>::Nalg>
234 where
235 nalgebra::DefaultAllocator:
236 nalgebra::allocator::Allocator<<Self::R as Conv>::Nalg, <Self::C as Conv>::Nalg>;
237
238 fn conv<
240 NewR: Conv<TNum = <Self::R as Conv>::TNum>,
241 NewC: Conv<TNum = <Self::C as Conv>::TNum>,
242 >(
243 self,
244 ) -> GenericMatrix<Self::T, NewR, NewC>;
245}
246
247impl<T: Scalar, R: Conv, C: Conv> GenericMatrixExt for GenericMatrix<T, R, C> {
248 type T = T;
249
250 type R = R;
251
252 type C = C;
253
254 fn into_regular_matrix(
255 self,
256 ) -> OMatrix<Self::T, <Self::R as Conv>::Nalg, <Self::C as Conv>::Nalg>
257 where
258 DefaultAllocator: Allocator<<Self::R as Conv>::Nalg, <Self::C as Conv>::Nalg>,
259 {
260 Matrix::from_data(DefaultAllocator::allocate_from_iterator(
261 <Self::R as Conv>::new_nalg(),
262 <Self::C as Conv>::new_nalg(),
263 self.data.0.into_iter().flatten(),
264 ))
265 }
266
267 fn conv<
268 NewR: Conv<TNum = <Self::R as Conv>::TNum>,
269 NewC: Conv<TNum = <Self::C as Conv>::TNum>,
270 >(
271 self,
272 ) -> GenericMatrix<Self::T, NewR, NewC> {
273 GenericMatrix::from_data(GenericArrayStorage(self.data.0))
274 }
275}
276
277#[cfg(test)]
278mod tests;