generic_array/
internal.rs

1#![allow(dead_code)] // ArrayBuilder is soft-deprecated internally
2
3use crate::*;
4
5pub trait Sealed {}
6
7impl<T> Sealed for [T; 0] {}
8
9/// **UNSAFE**: Creates an array one element at a time using a mutable iterator of pointers.
10///
11/// You MUST increment the position while iterating to mark off created elements,
12/// which will be dropped if `into_inner` is not called.
13///
14/// This is soft-deprecated in favor of [`IntrusiveArrayBuilder`] due to Rust's
15/// lack of return-value optimization causing issues moving the array out of the struct.
16/// Still works fine for smaller arrays, though.
17pub struct ArrayBuilder<T, N: ArrayLength> {
18    array: GenericArray<MaybeUninit<T>, N>,
19    position: usize,
20}
21
22impl<T, N: ArrayLength> ArrayBuilder<T, N> {
23    /// Begin building an array
24    #[inline(always)]
25    pub const fn new() -> ArrayBuilder<T, N> {
26        ArrayBuilder {
27            array: GenericArray::uninit(),
28            position: 0,
29        }
30    }
31
32    /// Consume an iterator, `.zip`-ing it to fill some or all of the array. This does not check if the
33    /// iterator had extra elements or too few elements.
34    ///
35    /// This makes no attempt to continue where a previous `extend` leaves off. Therefore, it should
36    /// only be used once per `ArrayBuilder`.
37    #[inline(always)]
38    pub unsafe fn extend(&mut self, source: impl Iterator<Item = T>) {
39        let (destination, position) = (self.array.iter_mut(), &mut self.position);
40
41        destination.zip(source).for_each(|(dst, src)| {
42            dst.write(src);
43            *position += 1;
44        });
45    }
46
47    /// Returns true if the write position equals the array size
48    #[inline(always)]
49    pub const fn is_full(&self) -> bool {
50        self.position == N::USIZE
51    }
52
53    /// Creates a mutable iterator for writing to the array elements.
54    ///
55    /// You MUST increment the position value (given as a mutable reference) as you iterate
56    /// to mark how many elements have been created.
57    ///
58    /// ```
59    /// #[cfg(feature = "internals")]
60    /// # {
61    /// # use generic_array::{GenericArray, internals::ArrayBuilder, typenum::U5};
62    /// # struct SomeType;
63    /// fn make_some_struct() -> SomeType { SomeType }
64    /// unsafe {
65    ///     let mut builder = ArrayBuilder::<SomeType, U5>::new();
66    ///     let (dst_iter, position) = builder.iter_position();
67    ///     for dst in dst_iter {
68    ///         dst.write(make_some_struct());
69    ///         // MUST be done AFTER ownership of the value has been given to `dst.write`
70    ///         *position += 1;
71    ///     }
72    ///     let your_array = builder.assume_init();
73    /// }
74    /// # }
75    /// ```
76    #[inline(always)]
77    pub unsafe fn iter_position(&mut self) -> (slice::IterMut<MaybeUninit<T>>, &mut usize) {
78        (self.array.iter_mut(), &mut self.position)
79    }
80
81    /// When done writing (assuming all elements have been written to),
82    /// get the inner array.
83    #[inline(always)]
84    pub const unsafe fn assume_init(self) -> GenericArray<T, N> {
85        debug_assert!(self.is_full());
86
87        let array = ptr::read(&self.array);
88        mem::forget(self);
89        GenericArray::assume_init(array)
90    }
91}
92
93impl<T, N: ArrayLength> Drop for ArrayBuilder<T, N> {
94    fn drop(&mut self) {
95        unsafe {
96            ptr::drop_in_place(
97                // Same cast as MaybeUninit::slice_assume_init_mut
98                self.array.get_unchecked_mut(..self.position) as *mut [MaybeUninit<T>]
99                    as *mut [T],
100            );
101        }
102    }
103}
104
105/// Similar to [`ArrayBuilder`] but uses a reference to a pre-allocated array, be
106/// it on the stack or heap.
107pub struct IntrusiveArrayBuilder<'a, T, N: ArrayLength> {
108    array: &'a mut GenericArray<MaybeUninit<T>, N>,
109    position: usize,
110}
111
112impl<'a, T, N: ArrayLength> IntrusiveArrayBuilder<'a, T, N> {
113    /// Begin building an array
114    #[inline(always)]
115    pub const fn new(
116        array: &'a mut GenericArray<MaybeUninit<T>, N>,
117    ) -> IntrusiveArrayBuilder<'a, T, N> {
118        IntrusiveArrayBuilder { array, position: 0 }
119    }
120
121    /// Consume an iterator, `.zip`-ing it to fill some or all of the array. This does not check if the
122    /// iterator had extra elements or too few elements.
123    ///
124    /// This makes no attempt to continue where a previous `extend` leaves off. Therefore, it should
125    /// only be used once per `ArrayBuilder`.
126    #[inline(always)]
127    pub unsafe fn extend(&mut self, source: impl Iterator<Item = T>) {
128        let (destination, position) = (self.array.iter_mut(), &mut self.position);
129
130        destination.zip(source).for_each(|(dst, src)| {
131            dst.write(src);
132            *position += 1;
133        });
134    }
135
136    /// Returns true if the write position equals the array size
137    #[inline(always)]
138    pub const fn is_full(&self) -> bool {
139        self.position == N::USIZE
140    }
141
142    /// Creates a mutable iterator for writing to the array elements.
143    ///
144    /// You MUST increment the position value (given as a mutable reference) as you iterate
145    /// to mark how many elements have been created.
146    ///
147    /// ```
148    /// #[cfg(feature = "internals")]
149    /// # {
150    /// # use generic_array::{GenericArray, internals::IntrusiveArrayBuilder, typenum::U5};
151    /// # struct SomeType;
152    /// fn make_some_struct() -> SomeType { SomeType }
153    /// unsafe {
154    ///     let mut array = GenericArray::uninit();
155    ///     let mut builder = IntrusiveArrayBuilder::<SomeType, U5>::new(&mut array);
156    ///     let (dst_iter, position) = builder.iter_position();
157    ///     for dst in dst_iter {
158    ///         dst.write(make_some_struct());
159    ///         // MUST be done AFTER ownership of the value has been given to `dst.write`
160    ///         *position += 1;
161    ///     }
162    ///     let your_array = { builder.finish(); IntrusiveArrayBuilder::array_assume_init(array) };
163    /// }
164    /// # }
165    /// ```
166    #[inline(always)]
167    pub unsafe fn iter_position(&mut self) -> (slice::IterMut<MaybeUninit<T>>, &mut usize) {
168        (self.array.iter_mut(), &mut self.position)
169    }
170
171    /// When done writing (assuming all elements have been written to),
172    /// get the inner array.
173    #[inline(always)]
174    pub const unsafe fn finish(self) {
175        debug_assert!(self.is_full());
176        mem::forget(self)
177    }
178
179    /// Similar to [`GenericArray::assume_init`] but not `const` and optimizes better.
180    #[inline(always)]
181    pub unsafe fn array_assume_init(array: GenericArray<MaybeUninit<T>, N>) -> GenericArray<T, N> {
182        ptr::read(&array as *const _ as *const MaybeUninit<GenericArray<T, N>>).assume_init()
183    }
184}
185
186impl<T, N: ArrayLength> Drop for IntrusiveArrayBuilder<'_, T, N> {
187    fn drop(&mut self) {
188        unsafe {
189            ptr::drop_in_place(
190                // Same cast as MaybeUninit::slice_assume_init_mut
191                self.array.get_unchecked_mut(..self.position) as *mut [MaybeUninit<T>]
192                    as *mut [T],
193            );
194        }
195    }
196}
197
198/// **UNSAFE**: Consumes an array one element at a time.
199///
200/// You MUST increment the position while iterating and any leftover elements
201/// will be dropped if position does not go to N
202pub struct ArrayConsumer<T, N: ArrayLength> {
203    array: ManuallyDrop<GenericArray<T, N>>,
204    position: usize,
205}
206
207impl<T, N: ArrayLength> ArrayConsumer<T, N> {
208    /// Give ownership of the array to the consumer
209    #[inline(always)]
210    pub const fn new(array: GenericArray<T, N>) -> ArrayConsumer<T, N> {
211        ArrayConsumer {
212            array: ManuallyDrop::new(array),
213            position: 0,
214        }
215    }
216
217    /// Creates an iterator and mutable reference to the internal position
218    /// to keep track of consumed elements.
219    ///
220    /// You MUST increment the position as you iterate to mark off consumed elements.
221    #[inline(always)]
222    pub unsafe fn iter_position(&mut self) -> (slice::Iter<T>, &mut usize) {
223        (self.array.iter(), &mut self.position)
224    }
225}
226
227impl<T, N: ArrayLength> Drop for ArrayConsumer<T, N> {
228    fn drop(&mut self) {
229        unsafe {
230            ptr::drop_in_place(self.array.get_unchecked_mut(self.position..));
231        }
232    }
233}