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}