rstsr_common/
pack_array.rs

1//! Cast `Vec<T>` to/from `Vec<[T; N]>` (or its reference) without copying.
2
3use crate::prelude_dev::*;
4use std::mem::ManuallyDrop;
5
6pub trait PackableArrayAPI<T, const N: usize> {
7    type Array;
8    type ArrayVec;
9}
10
11pub trait PackArrayAPI<T> {
12    fn pack_array_f<const N: usize>(self) -> Result<Self::ArrayVec>
13    where
14        Self: PackableArrayAPI<T, N>;
15    fn pack_array<const N: usize>(self) -> Self::ArrayVec
16    where
17        Self: PackableArrayAPI<T, N> + Sized,
18    {
19        self.pack_array_f().unwrap()
20    }
21}
22
23pub trait UnpackArrayAPI {
24    type Output;
25    fn unpack_array(self) -> Self::Output;
26}
27
28/* #region impl of Vec<T> */
29
30impl<T, const N: usize> PackableArrayAPI<T, N> for Vec<T> {
31    type Array = [T; N];
32    type ArrayVec = Vec<[T; N]>;
33}
34
35impl<T> PackArrayAPI<T> for Vec<T> {
36    fn pack_array_f<const N: usize>(self) -> Result<<Self as PackableArrayAPI<T, N>>::ArrayVec> {
37        let len = self.len();
38        rstsr_assert!(
39            len % N == 0,
40            InvalidValue,
41            "Length of Vec<T> {len} must be a multiple to cast into Vec<[T; {N}]>"
42        )?;
43        let vec = ManuallyDrop::new(self);
44        let arr = unsafe { Vec::from_raw_parts(vec.as_ptr() as *mut [T; N], len / N, len / N) };
45        Ok(arr)
46    }
47}
48
49impl<T, const N: usize> UnpackArrayAPI for Vec<[T; N]> {
50    type Output = Vec<T>;
51
52    fn unpack_array(self) -> Self::Output {
53        let len = self.len();
54        let arr = ManuallyDrop::new(self);
55        unsafe { Vec::from_raw_parts(arr.as_ptr() as *mut T, len * N, len * N) }
56    }
57}
58
59/* #endregion */
60
61/* #region impl of &[T] */
62
63impl<'l, T, const N: usize> PackableArrayAPI<T, N> for &'l [T] {
64    type Array = [T; N];
65    type ArrayVec = &'l [[T; N]];
66}
67
68impl<T> PackArrayAPI<T> for &[T] {
69    fn pack_array_f<const N: usize>(self) -> Result<<Self as PackableArrayAPI<T, N>>::ArrayVec> {
70        let len = self.len();
71        rstsr_assert!(
72            len % N == 0,
73            InvalidValue,
74            "Length of &[T] {len} must be a multiple to cast into Vec<[T; {N}]>"
75        )?;
76        let arr = unsafe { core::slice::from_raw_parts(self.as_ptr() as *const [T; N], len / N) };
77        Ok(arr)
78    }
79}
80
81impl<'l, T, const N: usize> UnpackArrayAPI for &'l [[T; N]] {
82    type Output = &'l [T];
83
84    fn unpack_array(self) -> Self::Output {
85        let len = self.len();
86        unsafe { core::slice::from_raw_parts(self.as_ptr() as *const T, len * N) }
87    }
88}
89
90/* #endregion */
91
92/* #region impl of &mut [T] */
93
94impl<'l, T, const N: usize> PackableArrayAPI<T, N> for &'l mut [T] {
95    type Array = [T; N];
96    type ArrayVec = &'l mut [[T; N]];
97}
98
99impl<T> PackArrayAPI<T> for &mut [T] {
100    fn pack_array_f<const N: usize>(self) -> Result<<Self as PackableArrayAPI<T, N>>::ArrayVec> {
101        let len = self.len();
102        rstsr_assert!(
103            len % N == 0,
104            InvalidValue,
105            "Length of &[T] {len} must be a multiple to cast into Vec<[T; {N}]>"
106        )?;
107        let arr = unsafe { core::slice::from_raw_parts_mut(self.as_mut_ptr() as *mut [T; N], len / N) };
108        Ok(arr)
109    }
110}
111
112impl<'l, T, const N: usize> UnpackArrayAPI for &'l mut [[T; N]] {
113    type Output = &'l mut [T];
114
115    fn unpack_array(self) -> Self::Output {
116        let len = self.len();
117        unsafe { core::slice::from_raw_parts_mut(self.as_ptr() as *mut T, len * N) }
118    }
119}
120
121/* #endregion */
122
123#[cfg(test)]
124mod test {
125    use super::*;
126
127    #[test]
128    fn playground() {
129        let v1 = vec![1, 2, 3, 4, 5, 6];
130        let ptr_v1 = v1.as_ptr();
131
132        let a1: Vec<[i32; 2]> = v1.pack_array();
133        let ptr_a1 = a1.as_ptr();
134        assert_eq!(a1, vec![[1, 2], [3, 4], [5, 6]]);
135        assert_eq!(ptr_v1, ptr_a1 as *const i32);
136
137        let v2: Vec<i32> = a1.unpack_array();
138        let ptr_v2 = v2.as_ptr();
139        assert_eq!(v2, vec![1, 2, 3, 4, 5, 6]);
140        assert_eq!(ptr_v1, ptr_v2);
141    }
142}