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