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}