Skip to main content

ferroui_base/utilities/
array_builder.rs

1//! `ArrayBuilder<T>`: a growable buffer that can be cleared and reused without
2//! giving its storage back (the pooled scratch buffer of the text formatter).
3
4/// A simple growable buffer.
5///
6/// Upstream hands out `ArraySlice`s aliasing the builder's array; here the
7/// builder owns a `Vec<T>` and ranges are borrowed as plain slices.
8#[derive(Debug, Default)]
9pub struct ArrayBuilder<T> {
10    data: Vec<T>,
11}
12
13impl<T> ArrayBuilder<T> {
14    pub const fn new() -> Self {
15        Self { data: Vec::new() }
16    }
17
18    /// The number of items.
19    #[inline]
20    pub fn length(&self) -> usize {
21        self.data.len()
22    }
23
24    /// The allocated capacity.
25    #[inline]
26    pub fn capacity(&self) -> usize {
27        self.data.capacity()
28    }
29
30    /// Appends one item.
31    #[inline]
32    pub fn add_item(&mut self, value: T) {
33        self.data.push(value);
34    }
35
36    /// Removes every item, keeping the storage.
37    #[inline]
38    pub fn clear(&mut self) {
39        self.data.clear();
40    }
41
42    /// Drops the storage (C# `arrayBuilder = default`).
43    pub fn reset(&mut self) {
44        self.data = Vec::new();
45    }
46
47    /// The items.
48    #[inline]
49    pub fn as_span(&self) -> &[T] {
50        &self.data
51    }
52
53    /// The items, mutably.
54    #[inline]
55    pub fn as_span_mut(&mut self) -> &mut [T] {
56        &mut self.data
57    }
58
59    /// `length` items starting at `start`.
60    #[inline]
61    pub fn as_slice(&self, start: usize, length: usize) -> &[T] {
62        &self.data[start..start + length]
63    }
64
65    /// The first `length` items (the original's `AsSlice(length)`; its
66    /// `AsSlice()` is [`as_span`](Self::as_span)).
67    #[inline]
68    pub fn as_slice_to(&self, length: usize) -> &[T] {
69        &self.data[..length]
70    }
71
72    /// `length` items starting at `start`, mutably.
73    #[inline]
74    pub fn as_slice_mut(&mut self, start: usize, length: usize) -> &mut [T] {
75        &mut self.data[start..start + length]
76    }
77}
78
79impl<T: Clone + Default> ArrayBuilder<T> {
80    /// Sets the number of items; new items are default values.
81    pub fn set_length(&mut self, value: usize) {
82        self.data.resize(value, T::default());
83    }
84
85    /// Appends `length` default items and returns them.
86    pub fn add(&mut self, length: usize) -> &mut [T] {
87        let position = self.data.len();
88        self.data.resize(position + length, T::default());
89        &mut self.data[position..]
90    }
91
92    /// Appends a copy of `value` and returns the appended range.
93    pub fn add_slice(&mut self, value: &[T]) -> &mut [T] {
94        let position = self.data.len();
95        self.data.extend_from_slice(value);
96        &mut self.data[position..]
97    }
98}
99
100impl<T> std::ops::Index<usize> for ArrayBuilder<T> {
101    type Output = T;
102
103    #[inline]
104    fn index(&self, index: usize) -> &T {
105        &self.data[index]
106    }
107}
108
109impl<T> std::ops::IndexMut<usize> for ArrayBuilder<T> {
110    #[inline]
111    fn index_mut(&mut self, index: usize) -> &mut T {
112        &mut self.data[index]
113    }
114}
115
116#[cfg(test)]
117mod tests {
118    use super::*;
119
120    #[test]
121    fn add_and_reuse() {
122        let mut builder = ArrayBuilder::<i32>::new();
123        builder.add_item(1);
124        builder.add(2).fill(7);
125        builder.add_slice(&[9]);
126        assert_eq!(builder.as_span(), &[1, 7, 7, 9]);
127        let capacity = builder.capacity();
128        builder.clear();
129        assert_eq!(builder.length(), 0);
130        assert_eq!(builder.capacity(), capacity);
131        builder.set_length(2);
132        builder[1] = 5;
133        assert_eq!(builder.as_slice(1, 1), &[5]);
134    }
135}