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