brownstone/
builder.rs

1/*!
2A low level builder type for creating fixed size arrays. See [`ArrayBuilder`]
3for details.
4*/
5
6use core::fmt::{self, Debug, Formatter};
7
8use arrayvec::ArrayVec;
9
10/**
11Error type returned from [`ArrayBuilder::try_push`], indicating that the
12builder was already full. Includes the value that couldn't be pushed to the
13array.
14*/
15#[derive(Debug, Clone, Copy)]
16pub struct Overflow<T>(pub T);
17
18/**
19Result type returned from [`ArrayBuilder::push`], indicating whether the
20array is full after the push. `ArrayBuilder::push` panics on overflow, so this
21only indicates if there is room to push additional elements.
22*/
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub enum PushResult {
25    NotFull,
26    Full,
27}
28
29/**
30Low-level builder type for `[T; N]` arrays. Uses a
31[`push`][ArrayBuilder::push] + [`finish`][ArrayBuilder::finish] interface to
32build an array 1 element at a time.
33
34The interface provided by this type is fairly low level; most of its methods
35are fallible in some way (returning a [`Result`] or panicking on errors).
36Consider instead the misuse-resistant
37[`move_builder::ArrayBuilder`][crate::move_builder::ArrayBuilder], which uses
38ownership semantics to provide only infallible operations, or the
39[`build!`][crate::build] macro at the top level of the crate.
40*/
41#[derive(Clone)]
42pub struct ArrayBuilder<T, const N: usize> {
43    vec: ArrayVec<T, N>,
44}
45
46impl<T, const N: usize> ArrayBuilder<T, N> {
47    /**
48    Create a new, empty `ArrayBuilder`.
49    */
50    #[inline]
51    #[must_use]
52    pub const fn new() -> Self {
53        Self {
54            vec: ArrayVec::new_const(),
55        }
56    }
57
58    /**
59    Returns true if every element in the array is initialized. If the
60    builder is full, the next call to `finish` will return the built array.
61    */
62    #[inline]
63    #[must_use]
64    pub fn is_full(&self) -> bool {
65        self.vec.is_full()
66    }
67
68    /**
69    Returns true if no elements in the array are initialized.
70    */
71    #[inline]
72    #[must_use]
73    pub fn is_empty(&self) -> bool {
74        self.vec.is_empty()
75    }
76
77    /**
78    Returns the number of initialized elements in the array.
79    */
80    #[inline]
81    #[must_use]
82    pub fn len(&self) -> usize {
83        self.vec.len()
84    }
85
86    /**
87    Get a PushResult after a push. Indicates if the array is full or not.
88    */
89    #[inline]
90    #[must_use]
91    fn push_result(&self) -> PushResult {
92        match self.len() >= N {
93            true => PushResult::Full,
94            false => PushResult::NotFull,
95        }
96    }
97
98    /// Add an initialized element to the array, without performing a bounds
99    /// check.
100    ///
101    /// # Safety
102    ///
103    /// This must only be called when the builder is not full.
104    #[inline]
105    pub unsafe fn push_unchecked(&mut self, value: T) -> PushResult {
106        debug_assert!(self.vec.len() < N);
107
108        // Safety: the caller has ensured that the array isn't full yet.
109        self.vec.push_unchecked(value);
110        self.push_result()
111    }
112
113    /**
114    Try to add an initialized element to the array. Returns an error if the
115    array is already full, or a [`PushResult`] indicating if the array is now full
116    and can be retrieved via [`finish`][Self::finish].
117    */
118    #[inline]
119    pub fn try_push(&mut self, value: T) -> Result<PushResult, Overflow<T>> {
120        // We could avoid the unsafe and use try_push, but we'd prefer to
121        // contain the logic as much as possible
122        match self.vec.is_full() {
123            false => Ok(unsafe { self.push_unchecked(value) }),
124            true => Err(Overflow(value)),
125        }
126    }
127
128    /**
129    Add an initialized element to the array. Returns a [`PushResult`]
130    indicating if the array is now full and can be retrieved via
131    [`finish`][Self::finish].
132
133    # Panics
134
135    Panics if the array is already full.
136    */
137    #[inline]
138    pub fn push(&mut self, value: T) -> PushResult {
139        match self.try_push(value) {
140            Ok(result) => result,
141            Err(..) => panic!("ArrayBuilder::push overflow"),
142        }
143    }
144
145    /// Return the fully initialized array without checking that it's fully
146    /// initialized.
147    ///
148    /// # Safety
149    ///
150    /// This must only be called when the builder is full.
151    #[inline]
152    pub unsafe fn finish_unchecked(self) -> [T; N] {
153        debug_assert!(self.is_full());
154        self.vec.into_inner_unchecked()
155    }
156
157    /**
158    Try to return the fully initialized array. Returns the builder if the
159    array isn't fully initialized yet.
160    */
161    #[inline]
162    pub fn try_finish(self) -> Result<[T; N], Self> {
163        match self.is_full() {
164            true => Ok(unsafe { self.finish_unchecked() }),
165            false => Err(self),
166        }
167    }
168
169    /**
170    Return the fully initialized array.
171
172    # Panics
173
174    Panics if the array isn't fully initialized yet.
175    */
176    #[inline]
177    pub fn finish(self) -> [T; N] {
178        match self.try_finish() {
179            Ok(array) => array,
180            Err(..) => panic!("ArrayBuilder::finish incomplete"),
181        }
182    }
183
184    /**
185    Get the slice of the array that has already been initialized.
186    */
187    #[inline]
188    #[must_use]
189    pub fn finished_slice(&self) -> &[T] {
190        self.vec.as_slice()
191    }
192
193    /**
194    Get the mutable slice of the array that has already been initialized.
195    */
196    #[inline]
197    #[must_use]
198    pub fn finished_slice_mut(&mut self) -> &mut [T] {
199        self.vec.as_mut_slice()
200    }
201}
202
203impl<T, const N: usize> Default for ArrayBuilder<T, N> {
204    fn default() -> Self {
205        Self::new()
206    }
207}
208
209impl<T: Debug, const N: usize> Debug for ArrayBuilder<T, N> {
210    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
211        f.debug_struct("ArrayBuilder")
212            .field("array", &self.finished_slice())
213            .field("progress", &format_args!("{} / {}", self.len(), N))
214            .finish()
215    }
216}
217
218impl<T, const N: usize> Extend<T> for ArrayBuilder<T, N> {
219    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
220        iter.into_iter().for_each(|item| {
221            self.push(item);
222        })
223    }
224
225    // TODO: extend_one, when it's stable
226}