1
- use core:: mem:: MaybeUninit ;
1
+ use core:: mem:: { self , MaybeUninit } ;
2
2
use core:: ptr;
3
3
4
- /// Helper struct to build up an array element by element .
4
+ /// An array of at most `N` elements .
5
5
struct ArrayBuilder < T , const N : usize > {
6
- arr : [ MaybeUninit < T > ; N ] , // Invariant: arr[..len] is initialized .
6
+ arr : [ MaybeUninit < T > ; N ] , // Invariant: arr[..len] is valid .
7
7
len : usize , // Invariant: len <= N.
8
8
}
9
9
10
10
impl < T , const N : usize > ArrayBuilder < T , N > {
11
+ /// Initializes a new, empty `ArrayBuilder`.
11
12
pub fn new ( ) -> Self {
13
+ // SAFETY: the validity invariant trivially hold for a zero-length array.
12
14
Self {
13
15
arr : [ ( ) ; N ] . map ( |_| MaybeUninit :: uninit ( ) ) ,
14
16
len : 0 ,
15
17
}
16
18
}
17
19
20
+ /// Pushes `value` onto the end of the array.
21
+ ///
22
+ /// # Panics
23
+ ///
24
+ /// This panics if `self.len() >= N`.
18
25
pub fn push ( & mut self , value : T ) {
19
- // We maintain the invariant here that arr[..len] is initialized .
26
+ // SAFETY: we maintain the invariant here that arr[..len] is valid .
20
27
// Indexing with self.len also ensures self.len < N, and thus <= N after
21
28
// the increment.
22
29
self . arr [ self . len ] = MaybeUninit :: new ( value) ;
23
30
self . len += 1 ;
24
31
}
25
32
33
+ /// Consumes the elements in the `ArrayBuilder` and returns them as an array `[T; N]`.
34
+ ///
35
+ /// If `self.len() < N`, this returns `None`.
26
36
pub fn take ( & mut self ) -> Option < [ T ; N ] > {
27
37
if self . len == N {
28
- // Take the array, resetting the length back to zero.
29
- let arr = core:: mem:: replace ( & mut self . arr , [ ( ) ; N ] . map ( |_| MaybeUninit :: uninit ( ) ) ) ;
38
+ // Take the array, resetting our length back to zero.
30
39
self . len = 0 ;
40
+ let arr = mem:: replace ( & mut self . arr , [ ( ) ; N ] . map ( |_| MaybeUninit :: uninit ( ) ) ) ;
31
41
32
- // SAFETY: we had len == N, so all elements in arr are initialized .
42
+ // SAFETY: we had len == N, so all elements in arr are valid .
33
43
Some ( unsafe { arr. map ( |v| v. assume_init ( ) ) } )
34
44
} else {
35
45
None
@@ -40,10 +50,10 @@ impl<T, const N: usize> ArrayBuilder<T, N> {
40
50
impl < T , const N : usize > Drop for ArrayBuilder < T , N > {
41
51
fn drop ( & mut self ) {
42
52
unsafe {
43
- // SAFETY: arr[..len] is initialized , so must be dropped.
44
- // First we create a pointer to this initialized slice, then drop
45
- // that slice in-place. The cast from *mut MaybeUninit<T> to *mut T
46
- // is always sound by the layout guarantees of MaybeUninit.
53
+ // SAFETY: arr[..len] is valid , so must be dropped. First we create
54
+ // a pointer to this valid slice, then drop that slice in-place.
55
+ // The cast from *mut MaybeUninit<T> to *mut T is always sound by
56
+ // the layout guarantees of MaybeUninit.
47
57
let ptr_to_first: * mut MaybeUninit < T > = self . arr . as_mut_ptr ( ) ;
48
58
let ptr_to_slice = ptr:: slice_from_raw_parts_mut ( ptr_to_first. cast :: < T > ( ) , self . len ) ;
49
59
ptr:: drop_in_place ( ptr_to_slice) ;
0 commit comments