toad_common/
array.rs

1use core::ops::{Deref, DerefMut};
2
3#[cfg(feature = "alloc")]
4use std_alloc::vec::Vec;
5
6/// Get the runtime size of some data structure
7///
8/// # Deprecated
9/// Note: in a future version of `toad_common` this will be deprecated in favor of clearly delineating
10/// "size in bytes" (e.g. `RuntimeSize`) from "collection of potentially bounded length" (e.g. `Len`)
11///
12/// ## Collections
13/// For collections this just yields the number of elements ([`Vec::len`], [`tinyvec::ArrayVec::len`]),
14/// and when the collection is over [`u8`]s,
15/// then `get_size` represents the number of bytes in the collection.
16///
17/// ## Structs and enums
18/// When implemented for items that are not collections,
19/// this is expected to yield the runtime size in bytes
20/// (not the static Rust [`core::mem::size_of`] size)
21pub trait GetSize {
22  /// Get the max size that this data structure can acommodate.
23  const CAPACITY: Option<usize>;
24
25  /// Get the runtime size (in bytes) of a struct
26  ///
27  /// For collections this is always equivalent to calling an inherent `len` method.
28  ///
29  /// ```
30  /// use toad_common::GetSize;
31  ///
32  /// assert_eq!(vec![1u8, 2].get_size(), 2)
33  /// ```
34  fn get_size(&self) -> usize;
35
36  /// Check if the runtime size is zero
37  ///
38  /// ```
39  /// use toad_common::GetSize;
40  ///
41  /// assert!(Vec::<u8>::new().size_is_zero())
42  /// ```
43  fn size_is_zero(&self) -> bool {
44    self.get_size() == 0
45  }
46
47  /// Is there no room left in this collection?
48  ///
49  /// ```
50  /// use toad_common::GetSize;
51  ///
52  /// let array = tinyvec::ArrayVec::<[u8; 2]>::from([1, 2]);
53  ///
54  /// assert!(array.is_full())
55  /// ```
56  fn is_full(&self) -> bool;
57}
58
59#[cfg(feature = "alloc")]
60impl<T> GetSize for Vec<T> {
61  const CAPACITY: Option<usize> = None;
62
63  fn get_size(&self) -> usize {
64    self.len()
65  }
66
67  fn is_full(&self) -> bool {
68    false
69  }
70}
71
72impl<A: tinyvec::Array> GetSize for tinyvec::ArrayVec<A> {
73  const CAPACITY: Option<usize> = Some(A::CAPACITY);
74
75  fn get_size(&self) -> usize {
76    self.len()
77  }
78
79  fn is_full(&self) -> bool {
80    self.len() >= self.capacity()
81  }
82}
83
84/// Create a data structure and reserve some amount of space for it to grow into
85///
86/// # Examples
87/// - `Vec` is `Reserve`, and invokes `Vec::with_capacity`
88/// - `tinyvec::ArrayVec` is `Reserve` and invokes `Default::default()` because creating an `ArrayVec` automatically allocates the required space on the stack.
89pub trait Reserve: Default {
90  /// Create an instance of the collection with a given capacity.
91  ///
92  /// Used to reserve some contiguous space, e.g. [`Vec::with_capacity`]
93  ///
94  /// The default implementation invokes `Default::default`
95  fn reserve(_: usize) -> Self {
96    Default::default()
97  }
98}
99
100/// Truncate this collection to a new length.
101///
102/// If self was shorter than `len`, nothing happens.
103///
104/// If self was longer, drops elements up to `len`
105pub trait Trunc
106  where Self: Sized
107{
108  #[allow(missing_docs)]
109  fn trunc(&mut self, len: usize) -> ();
110
111  /// Erase all elements in the collection
112  fn clear(&mut self) {
113    self.trunc(0);
114  }
115}
116
117#[cfg(feature = "alloc")]
118impl<T> Trunc for Vec<T> {
119  fn trunc(&mut self, len: usize) -> () {
120    self.truncate(len)
121  }
122}
123
124impl<T, const N: usize> Trunc for tinyvec::ArrayVec<[T; N]> where T: Default
125{
126  fn trunc(&mut self, len: usize) -> () {
127    self.truncate(len)
128  }
129}
130
131/// Fill this collection to the end with copies of `t`,
132/// copying array initialization `[0u8; 1000]` to the [`Array`] trait.
133///
134/// If the collection has no end (e.g. [`Vec`]),
135/// this trait's methods will return `None`.
136pub trait Filled<T>: Sized {
137  #[allow(missing_docs)]
138  fn filled(t: T) -> Option<Self>
139    where T: Copy
140  {
141    Self::filled_using(|| t)
142  }
143
144  #[allow(missing_docs)]
145  fn filled_default() -> Option<Self>
146    where T: Default
147  {
148    Self::filled_using(|| Default::default())
149  }
150
151  #[allow(missing_docs)]
152  fn filled_using<F>(f: F) -> Option<Self>
153    where F: Fn() -> T;
154}
155
156#[cfg(feature = "alloc")]
157impl<T> Reserve for Vec<T> {
158  fn reserve(n: usize) -> Self {
159    Self::with_capacity(n)
160  }
161}
162
163#[cfg(feature = "alloc")]
164impl<T> Filled<T> for Vec<T> {
165  fn filled_using<F>(_: F) -> Option<Self>
166    where F: Fn() -> T
167  {
168    None
169  }
170}
171
172impl<A: tinyvec::Array> Reserve for tinyvec::ArrayVec<A> {}
173
174impl<T, const N: usize> Filled<T> for tinyvec::ArrayVec<[T; N]> where T: Default
175{
176  fn filled_using<F>(f: F) -> Option<Self>
177    where F: Fn() -> T
178  {
179    Some(core::iter::repeat(()).take(N).map(|_| f()).collect())
180  }
181
182  fn filled(t: T) -> Option<Self>
183    where T: Copy
184  {
185    Some(Self::from([t; N]))
186  }
187}
188
189/// An ordered indexable collection of some type `Item`
190///
191/// # Provided implementations
192/// - [`Vec`]
193/// - [`tinyvec::ArrayVec`]
194///
195/// Notably, not `heapless::ArrayVec` or `arrayvec::ArrayVec`. An important usecase within `toad`
196/// is [`Extend`]ing the collection, and the performance of `heapless` and `arrayvec`'s Extend implementations
197/// are notably worse than `tinyvec`.
198///
199/// `tinyvec` also has the added bonus of being 100% unsafe-code-free, meaning if you choose `tinyvec` you eliminate the
200/// possibility of memory defects and UB.
201///
202/// # Requirements
203/// - [`Default`] for creating the collection
204/// - [`Extend`] for mutating and adding onto the collection (1 or more elements)
205/// - [`Reserve`] for reserving space ahead of time
206/// - [`GetSize`] for bound checks, empty checks, and accessing the length
207/// - [`FromIterator`] for [`collect`](core::iter::Iterator#method.collect)ing into the collection
208/// - [`IntoIterator`] for iterating and destroying the collection
209/// - [`Deref<Target = [T]>`](Deref) and [`DerefMut`] for:
210///    - indexing ([`Index`](core::ops::Index), [`IndexMut`](core::ops::IndexMut))
211///    - iterating ([`&[T].iter()`](primitive@slice#method.iter) and [`&mut [T].iter_mut()`](primitive@slice#method.iter_mut))
212pub trait Array:
213  Default
214  + GetSize
215  + Reserve
216  + Filled<<Self as Array>::Item>
217  + Trunc
218  + Deref<Target = [<Self as Array>::Item]>
219  + DerefMut
220  + Extend<<Self as Array>::Item>
221  + FromIterator<<Self as Array>::Item>
222  + IntoIterator<Item = <Self as Array>::Item>
223{
224  /// The type of item contained in the collection
225  type Item;
226
227  /// Insert a value at a particular index of a collection.
228  fn insert_at(&mut self, index: usize, value: <Self as Array>::Item);
229
230  /// Try to remove an entry from the collection.
231  ///
232  /// Returns `Some(Self::Item)` if `index` was in-bounds, `None` if `index` is out of bounds.
233  fn remove(&mut self, index: usize) -> Option<<Self as Array>::Item>;
234
235  /// Add a value to the end of a collection.
236  fn push(&mut self, value: <Self as Array>::Item);
237}
238
239/// Collections that support extending themselves mutably from copyable slices
240pub trait AppendCopy<T: Copy> {
241  /// Extend self mutably, copying from a slice.
242  ///
243  /// Worst-case implementations copy 1 element at a time (time O(n))
244  ///
245  /// Best-case implementations copy as much of the origin slice
246  /// at once as possible (system word size), e.g. [`Vec::append`].
247  /// (still linear time, but on 64-bit systems this is 64 times faster than a 1-by-1 copy.)
248  fn append_copy(&mut self, i: &[T]);
249}
250
251#[cfg(feature = "alloc")]
252impl<T: Copy> AppendCopy<T> for Vec<T> {
253  fn append_copy(&mut self, i: &[T]) {
254    self.extend(i);
255  }
256}
257
258impl<T: Copy, A: tinyvec::Array<Item = T>> AppendCopy<T> for tinyvec::ArrayVec<A> {
259  fn append_copy(&mut self, i: &[T]) {
260    self.extend_from_slice(i);
261  }
262}
263
264#[cfg(feature = "alloc")]
265impl<T> Array for Vec<T> {
266  type Item = T;
267
268  fn insert_at(&mut self, index: usize, value: T) {
269    self.insert(index, value);
270  }
271
272  fn remove(&mut self, index: usize) -> Option<T> {
273    if index < self.len() {
274      Some(Vec::remove(self, index))
275    } else {
276      None
277    }
278  }
279
280  fn push(&mut self, value: T) {
281    self.push(value)
282  }
283}
284
285impl<A: tinyvec::Array<Item = T>, T> Array for tinyvec::ArrayVec<A> where Self: Filled<T> + Trunc
286{
287  type Item = T;
288
289  fn insert_at(&mut self, index: usize, value: A::Item) {
290    self.insert(index, value);
291  }
292
293  fn remove(&mut self, index: usize) -> Option<T> {
294    if index < self.len() {
295      Some(tinyvec::ArrayVec::remove(self, index))
296    } else {
297      None
298    }
299  }
300
301  fn push(&mut self, value: A::Item) {
302    self.push(value)
303  }
304}