Skip to main content

generic_array/ext_impls/
impl_alloc.rs

1use alloc::{boxed::Box, vec::Vec};
2
3use crate::{ArrayLength, GenericArray, IntrusiveArrayBuilder, LengthError};
4
5use core::{alloc::Layout, mem::MaybeUninit, ptr};
6
7struct IntrusiveBoxedArrayBuilder<T, N: ArrayLength> {
8    layout: Layout,
9    ptr: *mut GenericArray<MaybeUninit<T>, N>,
10    position: usize,
11}
12
13impl<T, N: ArrayLength> IntrusiveBoxedArrayBuilder<T, N> {
14    #[inline(always)]
15    unsafe fn iter_position(
16        &'_ mut self,
17    ) -> (core::slice::IterMut<'_, MaybeUninit<T>>, &'_ mut usize) {
18        ((&mut *self.ptr).iter_mut(), &mut self.position)
19    }
20
21    #[inline(always)]
22    unsafe fn finish(self) -> Box<GenericArray<T, N>> {
23        debug_assert!(self.position == N::USIZE);
24        let ptr = self.ptr;
25        core::mem::forget(self);
26        Box::from_raw(ptr.cast())
27    }
28}
29
30impl<T, N: ArrayLength> Drop for IntrusiveBoxedArrayBuilder<T, N> {
31    fn drop(&mut self) {
32        unsafe {
33            if self.layout.size() == 0 {
34                // ZST: self.ptr is dangling, so avoid forming any reference to it.
35                // drop_in_place on a dangling-but-aligned raw slice ptr is valid for ZSTs.
36                ptr::drop_in_place(ptr::slice_from_raw_parts_mut(
37                    ptr::NonNull::<T>::dangling().as_ptr(),
38                    self.position,
39                ));
40            } else {
41                ptr::drop_in_place((&mut *self.ptr).get_unchecked_mut(..self.position)
42                    as *mut [MaybeUninit<T>] as *mut [T]);
43
44                alloc::alloc::dealloc(self.ptr.cast(), self.layout);
45            }
46        }
47    }
48}
49
50impl<T, N: ArrayLength> TryFrom<Vec<T>> for GenericArray<T, N> {
51    type Error = crate::LengthError;
52
53    fn try_from(v: Vec<T>) -> Result<Self, Self::Error> {
54        if v.len() != N::USIZE {
55            return Err(crate::LengthError);
56        }
57
58        unsafe {
59            let mut destination = core::mem::MaybeUninit::<GenericArray<T, N>>::uninit();
60            let mut builder = IntrusiveArrayBuilder::new_alt(&mut destination);
61
62            builder.extend(v.into_iter());
63
64            Ok(builder.finish_and_assume_init())
65        }
66    }
67}
68
69impl<T, N: ArrayLength> GenericArray<T, N> {
70    /// Converts a `Box<GenericArray<T, N>>` into `Box<[T]>` without reallocating.
71    ///
72    /// This operation is O(1), constant-time regardless of the array length N.
73    #[inline]
74    pub fn into_boxed_slice(self: Box<GenericArray<T, N>>) -> Box<[T]> {
75        unsafe {
76            // SAFETY: Box ensures the array is properly aligned
77            Box::from_raw(core::ptr::slice_from_raw_parts_mut(
78                Box::into_raw(self) as *mut T,
79                N::USIZE,
80            ))
81        }
82    }
83
84    /// Converts a `Box<GenericArray<T, N>>` into `Vec<T>` without reallocating.
85    ///
86    /// This operation is O(1), constant-time regardless of the array length N.
87    #[inline]
88    pub fn into_vec(self: Box<GenericArray<T, N>>) -> Vec<T> {
89        Vec::from(self.into_boxed_slice())
90    }
91
92    /// Attempts to convert a `Box<[T]>` into `Box<GenericArray<T, N>>` without reallocating.
93    ///
94    /// This operation is O(1), constant-time regardless of the array length N.
95    #[inline]
96    pub fn try_from_boxed_slice(slice: Box<[T]>) -> Result<Box<GenericArray<T, N>>, LengthError> {
97        if slice.len() != N::USIZE {
98            return Err(LengthError);
99        }
100
101        Ok(unsafe { Box::from_raw(Box::into_raw(slice) as *mut _) })
102    }
103
104    /// Attempts to convert a `Vec<T>` into `Box<GenericArray<T, N>>` without reallocating.
105    ///
106    /// This operation is O(1) **if the `Vec` has the same length and capacity as `N`**,
107    /// otherwise it will be forced to call `Vec::shrink_to_fit` which is O(N),
108    /// where N is the number of elements.
109    #[inline]
110    pub fn try_from_vec(vec: Vec<T>) -> Result<Box<GenericArray<T, N>>, LengthError> {
111        Self::try_from_boxed_slice(vec.into_boxed_slice())
112    }
113
114    /// Alternative to `Box::<GenericArray<T, N>>::default()` that won't overflow the stack for very large arrays.
115    ///
116    /// The standard `Box::default()` calls `default` on the inner type, creating it on the stack,
117    /// and then moves it onto the heap. Optimized release builds often remove this step, but debug builds
118    /// may have issues.
119    #[inline]
120    pub fn default_boxed() -> Box<GenericArray<T, N>>
121    where
122        T: Default,
123    {
124        Box::<GenericArray<T, N>>::generate(|_| T::default())
125    }
126
127    /// Like [`GenericArray::try_from_iter`] but returns a `Box<GenericArray<T, N>>` instead.
128    pub fn try_boxed_from_iter<I>(iter: I) -> Result<Box<GenericArray<T, N>>, LengthError>
129    where
130        I: IntoIterator<Item = T>,
131    {
132        let mut iter = iter.into_iter();
133
134        // pre-checks
135        match iter.size_hint() {
136            // if the lower bound is greater than N, array will overflow
137            (n, _) if n > N::USIZE => return Err(LengthError),
138            // if the upper bound is smaller than N, array cannot be filled
139            (_, Some(n)) if n < N::USIZE => return Err(LengthError),
140            _ => {}
141        }
142
143        let mut v = Vec::with_capacity(N::USIZE);
144        v.extend((&mut iter).take(N::USIZE));
145
146        if v.len() != N::USIZE || iter.next().is_some() {
147            return Err(LengthError);
148        }
149
150        Ok(GenericArray::try_from_vec(v).unwrap())
151    }
152}
153
154impl<T, N: ArrayLength> TryFrom<Box<[T]>> for GenericArray<T, N> {
155    type Error = crate::LengthError;
156
157    #[inline]
158    fn try_from(value: Box<[T]>) -> Result<Self, Self::Error> {
159        Vec::from(value).try_into()
160    }
161}
162
163impl<T, N: ArrayLength> From<GenericArray<T, N>> for Box<[T]> {
164    #[inline]
165    fn from(value: GenericArray<T, N>) -> Self {
166        Box::new(value).into_boxed_slice()
167    }
168}
169
170impl<T, N: ArrayLength> From<GenericArray<T, N>> for Vec<T> {
171    #[inline]
172    fn from(value: GenericArray<T, N>) -> Self {
173        Box::<[T]>::from(value).into()
174    }
175}
176
177impl<T, N: ArrayLength> IntoIterator for Box<GenericArray<T, N>> {
178    type IntoIter = alloc::vec::IntoIter<T>;
179    type Item = T;
180
181    fn into_iter(self) -> Self::IntoIter {
182        GenericArray::into_vec(self).into_iter()
183    }
184}
185
186impl<T, N: ArrayLength> FromIterator<T> for Box<GenericArray<T, N>> {
187    /// Create a `Box<GenericArray>` from an iterator.
188    ///
189    /// Will panic if the number of elements is not exactly the array length.
190    ///
191    /// See [`GenericArray::try_boxed_from_iter]` for a fallible alternative.
192    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
193        match GenericArray::try_boxed_from_iter(iter) {
194            Ok(res) => res,
195            Err(_) => crate::from_iter_length_fail(N::USIZE),
196        }
197    }
198}
199
200use crate::functional::{FunctionalSequence, MappedGenericSequence};
201use crate::GenericSequence;
202
203unsafe impl<T, N: ArrayLength> GenericSequence<T> for Box<GenericArray<T, N>> {
204    type Length = N;
205    type Sequence = Box<GenericArray<T, N>>;
206
207    fn generate<F>(mut f: F) -> Self::Sequence
208    where
209        F: FnMut(usize) -> T,
210    {
211        unsafe {
212            let layout = Layout::new::<GenericArray<MaybeUninit<T>, N>>();
213
214            let raw_ptr: *mut GenericArray<MaybeUninit<T>, N> = if layout.size() == 0 {
215                ptr::NonNull::dangling().as_ptr()
216            } else {
217                let p = alloc::alloc::alloc(layout);
218
219                if p.is_null() {
220                    alloc::alloc::handle_alloc_error(layout);
221                }
222
223                p.cast()
224            };
225
226            let mut builder = IntrusiveBoxedArrayBuilder {
227                layout,
228                ptr: raw_ptr,
229                position: 0,
230            };
231
232            {
233                let (builder_iter, position) = builder.iter_position();
234
235                builder_iter.enumerate().for_each(|(i, dst)| {
236                    dst.write(f(i));
237                    *position += 1;
238                });
239            }
240
241            builder.finish()
242        }
243    }
244}
245
246impl<T, U, N: ArrayLength> MappedGenericSequence<T, U> for Box<GenericArray<T, N>> {
247    type Mapped = Box<GenericArray<U, N>>;
248}
249
250impl<T, N: ArrayLength> FunctionalSequence<T> for Box<GenericArray<T, N>> where
251    Self: GenericSequence<T, Item = T, Length = N>
252{
253}
254
255use crate::sequence::{FallibleGenericSequence, FromFallibleIterator};
256
257impl<T, N: ArrayLength> FromFallibleIterator<T> for Box<GenericArray<T, N>> {
258    fn from_fallible_iter<I, E>(iter: I) -> Result<Self, E>
259    where
260        I: IntoIterator<Item = Result<T, E>>,
261    {
262        let mut iter = iter.into_iter();
263        let mut v = Vec::with_capacity(N::USIZE);
264        for item in (&mut iter).take(N::USIZE) {
265            v.push(item?);
266        }
267        if v.len() != N::USIZE || iter.next().is_some() {
268            crate::from_iter_length_fail(N::USIZE)
269        } else {
270            Ok(GenericArray::try_from_vec(v).unwrap())
271        }
272    }
273}
274
275unsafe impl<T, N: ArrayLength> FallibleGenericSequence<T> for Box<GenericArray<T, N>> {
276    type Error = crate::AllocError;
277
278    fn try_generate<F, E>(mut f: F) -> Result<Result<Self::Sequence, E>, crate::AllocError>
279    where
280        F: FnMut(usize) -> Result<T, E>,
281    {
282        unsafe {
283            let layout = Layout::new::<GenericArray<MaybeUninit<T>, N>>();
284
285            let raw_ptr: *mut GenericArray<MaybeUninit<T>, N> = if layout.size() == 0 {
286                ptr::NonNull::dangling().as_ptr()
287            } else {
288                let p = alloc::alloc::alloc(layout);
289
290                if p.is_null() {
291                    return Err(crate::AllocError);
292                }
293
294                p.cast()
295            };
296
297            let mut builder = IntrusiveBoxedArrayBuilder {
298                layout,
299                ptr: raw_ptr,
300                position: 0,
301            };
302
303            let (builder_iter, position) = builder.iter_position();
304
305            if let Err(e) = builder_iter
306                .enumerate()
307                .try_for_each(|(i, dst)| match f(i) {
308                    Ok(value) => {
309                        dst.write(value);
310                        *position += 1;
311                        Ok(())
312                    }
313                    Err(e) => Err(e),
314                })
315            {
316                drop(builder);
317                return Ok(Err(e));
318            }
319
320            Ok(Ok(builder.finish()))
321        }
322    }
323}