vec_to_array/
lib.rs

1//! Moves a heap allocated `Vec<T>` to an stack allocated array of type `T` and size `N`.
2
3
4/// Tries to move a `Vec<T>` into an array of type `T` and size `N`.
5///
6/// # Arguments
7///
8/// - `$vec`: The vector to be moved.
9/// - `$t`: The type of the elements in the vector and array.
10/// - `$size`: The expected size of the array.
11///
12/// # Returns
13///
14/// - `Ok([T; N])` if the vector can be moved successfully.
15/// - `Err(VecToArrayError::SizeMismatch)` if the size of the vector doesn't match the specified size.
16///
17/// # Examples
18///
19/// ```
20/// use vec_to_array::try_vec_to_array;
21/// let v = vec![1, 2, 3];
22/// let arr: [i32; 3] = try_vec_to_array!(v, i32, 3).unwrap();
23/// assert_eq!(arr, [1, 2, 3]);
24/// ```
25#[macro_export]
26macro_rules! try_vec_to_array {
27    ($vec:ident, $t:ty, $size:expr) => {
28        {
29            if $vec.len() == $size {
30                let mut arr: [std::mem::MaybeUninit<$t>; $size] = unsafe {
31                    std::mem::MaybeUninit::uninit().assume_init()
32                };
33                for (i, item) in $vec.into_iter().enumerate() {
34                    arr[i] =  std::mem::MaybeUninit::new(item);
35                }
36                Ok(unsafe { std::mem::transmute::<_, [$t; $size]>(arr) })
37            } else {
38                Err($crate::VecToArrayError::SizeMismatch { expected: $size, found: $vec.len() })
39            }
40        }
41    }
42}
43
44/// Moves a `Vec<T>` into an array of type `T` and size `N`.
45///
46/// This macro will panic if the size of the vector is different from the specified size.
47///
48/// # Arguments
49///
50/// - `$vec`: The vector to be moved.
51/// - `$t`: The type of the elements in the vector and array.
52/// - `$size`: The expected size of the array.
53///
54/// # Panics
55///
56/// Panics if the size of the vector doesn't match the specified size.
57///
58/// # Examples
59///
60/// ```
61/// use vec_to_array::vec_to_array;
62/// let v = vec![1, 2, 3];
63/// let arr: [i32; 3] = vec_to_array!(v, i32, 3);
64/// assert_eq!(arr, [1, 2, 3]);
65/// ```
66#[macro_export]
67macro_rules! vec_to_array {
68    ($vec:ident, $t:ty, $size:expr) => {
69        {
70            if $vec.len() != $size {
71                panic!("{}", $crate::VecToArrayError::SizeMismatch {
72                    expected: $size,
73                    found: $vec.len()
74                });
75            }
76            let mut arr: [std::mem::MaybeUninit<$t>; $size] = unsafe {
77                std::mem::MaybeUninit::uninit().assume_init()
78            };
79            for (i, item) in $vec.into_iter().enumerate() {
80                arr[i] =  std::mem::MaybeUninit::new(item);
81            }
82            unsafe { std::mem::transmute::<_, [$t; $size]>(arr) }
83        }
84    }
85}
86
87#[derive(Debug)]
88pub enum VecToArrayError {
89    SizeMismatch { expected: usize, found: usize },
90}
91
92impl std::fmt::Display for VecToArrayError {
93    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
94        match self {
95            VecToArrayError::SizeMismatch { expected, found } => write!(f, "Expected vector of size {}, but found size {}", expected, found),
96            // Handle other error variants here if added.
97        }
98    }
99}
100
101impl std::error::Error for VecToArrayError {}
102
103
104#[cfg(test)]
105mod tests {
106    use crate::VecToArrayError;
107
108    #[test]
109    fn basic_test() {
110        let vec: Vec<i64> = vec![1, 2, 3];
111        let array: [i64; 3] = vec_to_array!(vec, i64, 3);
112        assert_eq!(array, [1, 2, 3]);
113        let vec: Vec<i32> = vec![1, 2, 3];
114        let array: Result<[i32; 3], VecToArrayError> = try_vec_to_array!(vec, i32, 3);
115        assert_eq!(array.unwrap(), [1, 2, 3]);
116
117        let v: Vec<i32> = vec![0; 768];
118        let _arr: [i32; 768] = vec_to_array!(v, i32, 768);
119
120        let v: Vec<i32> = Vec::with_capacity(768);
121        let arr = try_vec_to_array!(v, i32, 768);
122        match arr {
123            Err(VecToArrayError::SizeMismatch { expected: 768, found: 0 }) => (),
124            _ => panic!()
125        }
126        let v: Vec<i32> = vec![0; 768];
127        let arr: Result<[i32; 768], VecToArrayError> = try_vec_to_array!(v, i32, 768);
128        assert!(arr.is_ok());
129    }
130
131    #[test]
132    fn more_complex_test() {
133        let mut x: Vec<Vec<String>> = Vec::new();
134        x.push(vec![String::from("12"), String::from("3")]);
135        let exp = x.clone();
136        let y: [Vec<String>; 1] = vec_to_array!(x, Vec<String>, 1);
137        let act = y.to_vec();
138        assert_eq!(act, exp);
139    }
140
141    #[test]
142    fn test_will_not_panic() {
143        let v: Vec<i32> = vec![0; 768];
144        let _arr: Result<[i32; 769], VecToArrayError> = try_vec_to_array!(v, i32, 769);
145        let v: Vec<i32> = vec![0; 768];
146        let _arr: Result<[i32; 767], VecToArrayError> = try_vec_to_array!(v, i32, 767);
147    }
148
149    #[test]
150    #[should_panic]
151    fn test_panics1() {
152        let v: Vec<i32> = vec![0; 768];
153        let _arr: [i32; 767] = vec_to_array!(v, i32, 767);
154    }
155
156    #[test]
157    #[should_panic]
158    fn test_panics2() {
159        let v: Vec<i32> = vec![0; 768];
160        let _arr: [i32; 769] = vec_to_array!(v, i32, 769);
161    }
162
163    #[test]
164    #[should_panic]
165    fn test_panics3() {
166        let v: Vec<i32> = Vec::with_capacity(768);
167        let _arr: [i32; 768] = vec_to_array!(v, i32, 768);
168    }
169
170    // #[test]
171    // fn test_borrow_checker_works() {
172    //     let v: Vec<String> = vec![String::new(); 768];
173    //     let _arr: [String; 768] = vec_to_array!(v, String, 768);
174    //     let _arr2: [String; 768] = vec_to_array!(v, String, 768);
175    // }
176}