toad_array/lib.rs
1//! This microcrate contains the `Array` trait used by the
2//! [`toad`](https://github.com/toad-lib/toad) CoAP runtime / ecosystem.
3//!
4//! The `Array` trait defines common operations used with heap-allocated
5//! collections like [`Vec`](https://doc.rust-lang.org/std/vec/struct.Vec.html) but
6//! is also implemented for [`tinyvec::ArrayVec`](https://docs.rs/tinyvec/latest) allowing
7//! for applications to be usable on platforms with or without heap allocation.
8
9// docs
10#![doc(html_root_url = "https://docs.rs/toad-array/0.1.0")]
11#![cfg_attr(any(docsrs, feature = "docs"), feature(doc_cfg))]
12// -
13// style
14#![allow(clippy::unused_unit)]
15// -
16// deny
17#![deny(missing_docs)]
18#![deny(missing_debug_implementations)]
19#![deny(missing_copy_implementations)]
20#![cfg_attr(not(test), deny(unsafe_code))]
21// -
22// warnings
23#![cfg_attr(not(test), warn(unreachable_pub))]
24// -
25// features
26#![cfg_attr(not(feature = "std"), no_std)]
27
28#[cfg(feature = "alloc")]
29extern crate alloc as std_alloc;
30
31use core::ops::{Deref, DerefMut};
32
33#[cfg(feature = "alloc")]
34use std_alloc::vec::Vec;
35use toad_len::Len;
36
37/// Operations on ordered indexed collections
38pub trait Indexed<T>
39 where Self: Len + Deref<Target = [T]>
40{
41 /// Insert a new element at `ix`, shifting all other elements to the right.
42 ///
43 /// ```
44 /// use toad_array::Indexed;
45 ///
46 /// fn do_stuff<I: Indexed<u32> + AsRef<Vec<u32>>>(mut i: I) {
47 /// i.insert(0, 2);
48 /// assert_eq!(i.as_ref(), &vec![2]);
49 ///
50 /// i.insert(0, 1);
51 /// assert_eq!(i.as_ref(), &vec![1, 2]);
52 ///
53 /// i.insert(2, 3);
54 /// assert_eq!(i.as_ref(), &vec![1, 2, 3]);
55 /// }
56 ///
57 /// do_stuff(vec![]);
58 /// ```
59 fn insert(&mut self, ix: usize, t: T);
60
61 /// Remove element at `ix`, shifting all other elements to the left.
62 ///
63 /// ```
64 /// use toad_array::Indexed;
65 ///
66 /// fn do_stuff<I: Indexed<u32> + AsRef<Vec<u32>>>(mut i: I) {
67 /// i.remove(1);
68 /// assert_eq!(i.as_ref(), &vec![1]);
69 ///
70 /// i.remove(0);
71 /// assert_eq!(i.as_ref(), &vec![]);
72 ///
73 /// i.remove(0);
74 /// assert_eq!(i.as_ref(), &vec![]);
75 /// }
76 ///
77 /// do_stuff(vec![1, 2]);
78 /// ```
79 fn remove(&mut self, ix: usize) -> Option<T>;
80
81 /// Insert an element at the front of the collection
82 ///
83 /// ```
84 /// use toad_array::Indexed;
85 ///
86 /// fn do_stuff<I: Indexed<u32> + AsRef<Vec<u32>>>(mut i: I) {
87 /// i.push(3);
88 /// assert_eq!(i.as_ref(), &vec![3]);
89 ///
90 /// i.push(2);
91 /// assert_eq!(i.as_ref(), &vec![2, 3]);
92 ///
93 /// i.push(1);
94 /// assert_eq!(i.as_ref(), &vec![1, 2, 3]);
95 /// }
96 ///
97 /// do_stuff(vec![]);
98 /// ```
99 fn push(&mut self, t: T) {
100 self.insert(0, t)
101 }
102
103 /// Insert an element at the end of the collection
104 ///
105 /// ```
106 /// use toad_array::Indexed;
107 ///
108 /// fn do_stuff<I: Indexed<u32> + AsRef<Vec<u32>>>(mut i: I) {
109 /// i.append(3);
110 /// assert_eq!(i.as_ref(), &vec![3]);
111 ///
112 /// i.append(2);
113 /// assert_eq!(i.as_ref(), &vec![3, 2]);
114 ///
115 /// i.append(1);
116 /// assert_eq!(i.as_ref(), &vec![3, 2, 1]);
117 /// }
118 ///
119 /// do_stuff(vec![]);
120 /// ```
121 fn append(&mut self, t: T) {
122 self.insert(self.len(), t)
123 }
124
125 /// Drop `ct` elements from the front of the collection
126 ///
127 /// ```
128 /// use toad_array::Indexed;
129 ///
130 /// let mut v: Vec<u32> = vec![1, 2, 3, 4];
131 ///
132 /// v.drop_front(2);
133 /// assert_eq!(v, vec![3, 4]);
134 ///
135 /// v.drop_front(3);
136 /// assert_eq!(v, vec![]);
137 ///
138 /// v.drop_front(1);
139 /// assert_eq!(v, vec![]);
140 /// ```
141 fn drop_front(&mut self, ct: usize) {
142 if !self.is_empty() && ct > 0 {
143 self.remove(0);
144 self.drop_front(ct - 1);
145 }
146 }
147
148 /// Drop `ct` elements from the back of the collection
149 ///
150 /// ```
151 /// use toad_array::Indexed;
152 ///
153 /// let mut v: Vec<u32> = vec![1, 2, 3, 4];
154 ///
155 /// v.drop_back(2);
156 /// assert_eq!(v, vec![1, 2]);
157 ///
158 /// v.drop_back(2);
159 /// assert_eq!(v, vec![]);
160 ///
161 /// v.drop_back(1);
162 /// assert_eq!(v, vec![]);
163 /// ```
164 fn drop_back(&mut self, ct: usize) {
165 if !self.is_empty() && ct > 0 {
166 self.remove(self.len() - 1);
167 self.drop_back(ct - 1);
168 }
169 }
170
171 /// Drop elements from the front of the collection until
172 /// the collection is emptied or the predicate returns
173 /// false.
174 ///
175 /// ```
176 /// use toad_array::Indexed;
177 ///
178 /// let mut v: Vec<u32> = vec![2, 4, 6, 5];
179 ///
180 /// v.drop_while(|n| n % 2 == 0);
181 /// assert_eq!(v, vec![5]);
182 /// ```
183 fn drop_while<F>(&mut self, f: F)
184 where F: for<'a> Fn(&'a T) -> bool
185 {
186 match self.get(0) {
187 | Some(t) if !f(&t) => return,
188 | None => return,
189 | _ => (),
190 };
191
192 self.remove(0);
193 self.drop_while(f);
194 }
195}
196
197/// Create a data structure and reserve some amount of space for it to grow into
198///
199/// # Examples
200/// - `Vec` is `Reserve`, and invokes `Vec::with_capacity`
201/// - `tinyvec::ArrayVec` is `Reserve` and invokes `Default::default()` because creating an `ArrayVec` automatically allocates the required space on the stack.
202pub trait Reserve
203 where Self: Default
204{
205 /// Create an instance of the collection with a given capacity.
206 ///
207 /// Used to reserve some contiguous space, e.g. [`Vec::with_capacity`]
208 ///
209 /// The default implementation invokes `Default::default`
210 fn reserve(_: usize) -> Self {
211 Default::default()
212 }
213}
214
215/// Truncate this collection to a new length.
216///
217/// If self was shorter than `len`, nothing happens.
218///
219/// If self was longer, drops elements up to `len`
220pub trait Trunc
221 where Self: Sized
222{
223 #[allow(missing_docs)]
224 fn trunc(&mut self, len: usize) -> ();
225
226 /// Erase all elements in the collection
227 fn clear(&mut self) {
228 self.trunc(0);
229 }
230}
231
232#[cfg(feature = "alloc")]
233impl<T> Trunc for Vec<T> {
234 fn trunc(&mut self, len: usize) -> () {
235 self.truncate(len)
236 }
237}
238
239impl<T, const N: usize> Trunc for tinyvec::ArrayVec<[T; N]> where T: Default
240{
241 fn trunc(&mut self, len: usize) -> () {
242 self.truncate(len)
243 }
244}
245
246/// Fill this collection to the end with copies of `t`,
247/// copying array initialization `[0u8; 1000]` to the [`Array`] trait.
248///
249/// If the collection has no end (e.g. [`Vec`]),
250/// this trait's methods will return `None`.
251pub trait Filled<T>: Sized {
252 #[allow(missing_docs)]
253 fn filled(t: T) -> Option<Self>
254 where T: Copy
255 {
256 Self::filled_using(|| t)
257 }
258
259 #[allow(missing_docs)]
260 fn filled_default() -> Option<Self>
261 where T: Default
262 {
263 Self::filled_using(|| Default::default())
264 }
265
266 #[allow(missing_docs)]
267 fn filled_using<F>(f: F) -> Option<Self>
268 where F: Fn() -> T;
269}
270
271#[cfg(feature = "alloc")]
272impl<T> Reserve for Vec<T> {
273 fn reserve(n: usize) -> Self {
274 Self::with_capacity(n)
275 }
276}
277
278#[cfg(feature = "alloc")]
279impl<T> Filled<T> for Vec<T> {
280 fn filled_using<F>(_: F) -> Option<Self>
281 where F: Fn() -> T
282 {
283 None
284 }
285}
286
287impl<A: tinyvec::Array> Reserve for tinyvec::ArrayVec<A> {}
288
289impl<T, const N: usize> Filled<T> for tinyvec::ArrayVec<[T; N]> where T: Default
290{
291 fn filled_using<F>(f: F) -> Option<Self>
292 where F: Fn() -> T
293 {
294 Some(core::iter::repeat(()).take(N).map(|_| f()).collect())
295 }
296
297 fn filled(t: T) -> Option<Self>
298 where T: Copy
299 {
300 Some(Self::from([t; N]))
301 }
302}
303
304/// A generalization of [`std::vec::Vec`]
305///
306/// # Provided implementations
307/// - [`Vec`]
308/// - [`tinyvec::ArrayVec`]
309///
310/// ## Why [`tinyvec::ArrayVec`]?
311/// The performance of `heapless` and `arrayvec`'s Extend implementations
312/// are notably worse than `tinyvec`. (see `toad-msg/benches/collections.rs`)
313/// `tinyvec` also has the added bonus of being 100% unsafe-code-free.
314///
315/// # Definition of an [`Array`]
316/// The Array trait is automatically implemented for ordered indexed collections
317/// with a non-fixed number of elements which are contiguous in memory.
318///
319/// This translates to the trait requirements:
320/// - Must have an empty ([`Default`]) value
321/// - Must allow populating every element with a value ([`Filled`])
322/// - Must allow dropping every element after a given index ([`Trunc`])
323/// - Must allow mutably appending one or more elements ([`Extend`])
324/// - Must be creatable from an iterator ([`FromIterator`])
325/// - Must allow iterating over owned elements ([`IntoIterator`])
326/// - Must be dereferenceable to readonly and mutable slices ([`Deref`], [`DerefMut`])
327/// - Must allow getting the runtime length ([`Len`])
328/// - May have a hard limit on number of elements ([`Len`])
329/// - May allow creating an instance with maximum length and a given filler value ([`Filled`])
330/// - May allow pre-allocating space for a specific number of elements ([`Reserve`])
331pub trait Array:
332 Default
333 + Len
334 + Reserve
335 + Filled<<Self as Array>::Item>
336 + Trunc
337 + Indexed<<Self as Array>::Item>
338 + Extend<<Self as Array>::Item>
339 + FromIterator<<Self as Array>::Item>
340 + IntoIterator<Item = <Self as Array>::Item>
341 + Deref<Target = [<Self as Array>::Item]>
342 + DerefMut
343{
344 /// The type of item contained in the collection
345 type Item;
346}
347
348/// Collections that support extending themselves mutably from copyable slices
349pub trait AppendCopy<T>
350 where T: Copy
351{
352 /// Extend self mutably, copying from a slice.
353 ///
354 /// Worst-case implementations copy 1 element at a time (time O(n))
355 ///
356 /// Best-case implementations copy as much of the origin slice
357 /// at once as possible (system word size), e.g. [`Vec::append`].
358 /// (still linear time, but on 64-bit systems this is 64 times faster than a 1-by-1 copy.)
359 fn append_copy(&mut self, i: &[T]);
360}
361
362#[cfg(feature = "alloc")]
363impl<T> AppendCopy<T> for Vec<T> where T: Copy
364{
365 fn append_copy(&mut self, i: &[T]) {
366 self.extend(i);
367 }
368}
369
370impl<T, A> AppendCopy<T> for tinyvec::ArrayVec<A>
371 where T: Copy,
372 A: tinyvec::Array<Item = T>
373{
374 fn append_copy(&mut self, i: &[T]) {
375 self.extend_from_slice(i);
376 }
377}
378
379#[cfg(feature = "alloc")]
380impl<T> Array for Vec<T> {
381 type Item = T;
382}
383
384#[cfg(feature = "alloc")]
385impl<T> Indexed<T> for Vec<T> {
386 fn insert(&mut self, index: usize, value: T) {
387 self.insert(index, value);
388 }
389
390 fn remove(&mut self, index: usize) -> Option<T> {
391 if index < self.len() {
392 Some(Vec::remove(self, index))
393 } else {
394 None
395 }
396 }
397}
398
399impl<A, T> Array for tinyvec::ArrayVec<A>
400 where Self: Filled<T> + Trunc,
401 A: tinyvec::Array<Item = T>
402{
403 type Item = T;
404}
405
406impl<A> Indexed<A::Item> for tinyvec::ArrayVec<A>
407 where Self: Filled<A::Item> + Trunc,
408 A: tinyvec::Array
409{
410 fn insert(&mut self, ix: usize, t: A::Item) {
411 tinyvec::ArrayVec::insert(self, ix, t)
412 }
413
414 fn remove(&mut self, ix: usize) -> Option<A::Item> {
415 if ix < self.len() {
416 Some(tinyvec::ArrayVec::remove(self, ix))
417 } else {
418 None
419 }
420 }
421}