generic_array/
impl_alloc.rs

1use alloc::{boxed::Box, vec::Vec};
2
3use crate::{ArrayLength, GenericArray, IntrusiveArrayBuilder, LengthError};
4
5impl<T, N: ArrayLength> TryFrom<Vec<T>> for GenericArray<T, N> {
6    type Error = crate::LengthError;
7
8    fn try_from(v: Vec<T>) -> Result<Self, Self::Error> {
9        if v.len() != N::USIZE {
10            return Err(crate::LengthError);
11        }
12
13        unsafe {
14            let mut destination = GenericArray::uninit();
15            let mut builder = IntrusiveArrayBuilder::new(&mut destination);
16
17            builder.extend(v.into_iter());
18
19            Ok({
20                builder.finish();
21                IntrusiveArrayBuilder::array_assume_init(destination)
22            })
23        }
24    }
25}
26
27impl<T, N: ArrayLength> GenericArray<T, N> {
28    /// Converts a `Box<GenericArray<T, N>>` into `Box<[T]>` without reallocating.
29    ///
30    /// This operation is O(1), constant-time regardless of the array length N.
31    #[inline]
32    pub fn into_boxed_slice(self: Box<GenericArray<T, N>>) -> Box<[T]> {
33        unsafe {
34            // SAFETY: Box ensures the array is properly aligned
35            Box::from_raw(core::ptr::slice_from_raw_parts_mut(
36                Box::into_raw(self) as *mut T,
37                N::USIZE,
38            ))
39        }
40    }
41
42    /// Converts a `Box<GenericArray<T, N>>` into `Vec<T>` without reallocating.
43    ///
44    /// This operation is O(1), constant-time regardless of the array length N.
45    #[inline]
46    pub fn into_vec(self: Box<GenericArray<T, N>>) -> Vec<T> {
47        Vec::from(self.into_boxed_slice())
48    }
49
50    /// Attempts to convert a `Box<[T]>` into `Box<GenericArray<T, N>>` without reallocating.
51    ///
52    /// This operation is O(1), constant-time regardless of the array length N.
53    #[inline]
54    pub fn try_from_boxed_slice(slice: Box<[T]>) -> Result<Box<GenericArray<T, N>>, LengthError> {
55        if slice.len() != N::USIZE {
56            return Err(LengthError);
57        }
58
59        Ok(unsafe { Box::from_raw(Box::into_raw(slice) as *mut _) })
60    }
61
62    /// Attempts to convert a `Vec<T>` into `Box<GenericArray<T, N>>` without reallocating.
63    ///
64    /// This operation is O(1) **if the `Vec` has the same length and capacity as `N`**,
65    /// otherwise it will be forced to call `Vec::shrink_to_fit` which is O(N),
66    /// where N is the number of elements.
67    #[inline]
68    pub fn try_from_vec(vec: Vec<T>) -> Result<Box<GenericArray<T, N>>, LengthError> {
69        Self::try_from_boxed_slice(vec.into_boxed_slice())
70    }
71
72    /// Alternative to `Box::<GenericArray<T, N>>::default()` that won't overflow the stack for very large arrays.
73    ///
74    /// The standard `Box::default()` calls `default` on the inner type, creating it on the stack,
75    /// and then moves it onto the heap. Optimized release builds often remove this step, but debug builds
76    /// may have issues.
77    #[inline]
78    pub fn default_boxed() -> Box<GenericArray<T, N>>
79    where
80        T: Default,
81    {
82        Box::<GenericArray<T, N>>::generate(|_| T::default())
83    }
84
85    /// Like [`GenericArray::try_from_iter`] but returns a `Box<GenericArray<T, N>>` instead.
86    pub fn try_boxed_from_iter<I>(iter: I) -> Result<Box<GenericArray<T, N>>, LengthError>
87    where
88        I: IntoIterator<Item = T>,
89    {
90        let mut iter = iter.into_iter();
91
92        // pre-checks
93        match iter.size_hint() {
94            // if the lower bound is greater than N, array will overflow
95            (n, _) if n > N::USIZE => return Err(LengthError),
96            // if the upper bound is smaller than N, array cannot be filled
97            (_, Some(n)) if n < N::USIZE => return Err(LengthError),
98            _ => {}
99        }
100
101        let mut v = Vec::with_capacity(N::USIZE);
102        v.extend((&mut iter).take(N::USIZE));
103
104        if v.len() != N::USIZE || iter.next().is_some() {
105            return Err(LengthError);
106        }
107
108        Ok(GenericArray::try_from_vec(v).unwrap())
109    }
110}
111
112impl<T, N: ArrayLength> TryFrom<Box<[T]>> for GenericArray<T, N> {
113    type Error = crate::LengthError;
114
115    #[inline]
116    fn try_from(value: Box<[T]>) -> Result<Self, Self::Error> {
117        Vec::from(value).try_into()
118    }
119}
120
121impl<T, N: ArrayLength> From<GenericArray<T, N>> for Box<[T]> {
122    #[inline]
123    fn from(value: GenericArray<T, N>) -> Self {
124        Box::new(value).into_boxed_slice()
125    }
126}
127
128impl<T, N: ArrayLength> From<GenericArray<T, N>> for Vec<T> {
129    #[inline]
130    fn from(value: GenericArray<T, N>) -> Self {
131        Box::<[T]>::from(value).into()
132    }
133}
134
135impl<T, N: ArrayLength> IntoIterator for Box<GenericArray<T, N>> {
136    type IntoIter = alloc::vec::IntoIter<T>;
137    type Item = T;
138
139    fn into_iter(self) -> Self::IntoIter {
140        GenericArray::into_vec(self).into_iter()
141    }
142}
143
144impl<T, N: ArrayLength> FromIterator<T> for Box<GenericArray<T, N>> {
145    /// Create a `Box<GenericArray>` from an iterator.
146    ///
147    /// Will panic if the number of elements is not exactly the array length.
148    ///
149    /// See [`GenericArray::try_boxed_from_iter]` for a fallible alternative.
150    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
151        match GenericArray::try_boxed_from_iter(iter) {
152            Ok(res) => res,
153            Err(_) => crate::from_iter_length_fail(N::USIZE),
154        }
155    }
156}
157
158use crate::functional::{FunctionalSequence, MappedGenericSequence};
159use crate::GenericSequence;
160
161unsafe impl<T, N: ArrayLength> GenericSequence<T> for Box<GenericArray<T, N>> {
162    type Length = N;
163    type Sequence = Box<GenericArray<T, N>>;
164
165    fn generate<F>(mut f: F) -> Self::Sequence
166    where
167        F: FnMut(usize) -> T,
168    {
169        unsafe {
170            use core::{
171                alloc::Layout,
172                mem::{size_of, MaybeUninit},
173                ptr,
174            };
175
176            // Box::new_uninit() is nightly-only
177            let ptr: *mut GenericArray<MaybeUninit<T>, N> = if size_of::<T>() == 0 {
178                ptr::NonNull::dangling().as_ptr()
179            } else {
180                alloc::alloc::alloc(Layout::new::<GenericArray<MaybeUninit<T>, N>>()).cast()
181            };
182
183            let mut builder = IntrusiveArrayBuilder::new(&mut *ptr);
184
185            {
186                let (builder_iter, position) = builder.iter_position();
187
188                builder_iter.enumerate().for_each(|(i, dst)| {
189                    dst.write(f(i));
190                    *position += 1;
191                });
192            }
193
194            builder.finish();
195
196            Box::from_raw(ptr.cast()) // IntrusiveArrayBuilder::array_assume_init
197        }
198    }
199}
200
201impl<T, U, N: ArrayLength> MappedGenericSequence<T, U> for Box<GenericArray<T, N>> {
202    type Mapped = Box<GenericArray<U, N>>;
203}
204
205impl<T, N: ArrayLength> FunctionalSequence<T> for Box<GenericArray<T, N>> where
206    Self: GenericSequence<T, Item = T, Length = N>
207{
208}