partial_array/
lib.rs

1//! Potentially partial-filled arrays.
2//!
3//! This crate provides a central new data type, similar to an [array]: the
4//! [`PartialArray<N>`]. It is equivalent to an array, but the number of entries
5//! might be anywhere from `0` to `N`. While this has similarities to a `Vec<T>`
6//! keep in mind, that a [`PartialArray`] does not grow its memory: it always
7//! takes up the memory for the fully array (with some additional counter) and
8//! it cannot ever hold more than `N` elements. This means that its memory is
9//! fully static and on the stack, making it usable from `#![no_std]` crates.
10//!
11//! ## Usages
12//! This new data type is most likely to be used for collecting iterators into
13//! arrays, when then length is not known, but has an upper bound, e.g.:
14//! ```
15//! # use partial_array::PartialArray;
16//! /// Take the first 10 elements of an iterator, that match the condition.
17//! ///
18//! /// This can return less than 10 elements if the iterator has fewer than 10
19//! /// items or there are less than 10 matching elements.
20//! fn first_10_matching<T, I, F>(iter: I, check: F) -> PartialArray<T, 10>
21//!     where I: IntoIterator<Item = T>,
22//!           F: FnMut(&T) -> bool,
23//! {
24//!     iter.into_iter().filter(check).take(10).collect()
25//! }
26//! ```
27//! Aside from this main usage, the [`PartialArray`] can be used like a normal
28//! array, i.e. it can be used as a [slice], you can convert [`from`] arrays and
29//! [`try_from`] slices. You can also iterate over the [`PartialArray`]s by
30//! value.
31//! ```
32//! # use partial_array::PartialArray;
33//! let array = PartialArray::from([42_u16; 4]);
34//! assert_eq!(array.len(), 4);
35//! assert_eq!(array[0], 42);
36//! assert_eq!(array[3], 42);
37//! assert_eq!(array[2..].len(), 2);
38//! array.into_iter().map(|x| x + 4).for_each(|x| println!("{}", x));
39//! ```
40//! As [`PartialArray`] implements [`IntoIterator`], you can use it in a `for`
41//! loop directly:
42//! ```
43//! # use partial_array::partial_array;
44//! let array = partial_array![42_u16; 4];
45//! for item in array {
46//!     println!("{}", item);
47//! }
48//! ```
49//! This crate also provides a [macro] to make creating partial arrays easier:
50//! ```
51//! # use partial_array::partial_array;
52//! let array = partial_array![42, -13, 2];
53//! ```
54//!
55//! ## Behavior on out-of-bounds accesses
56//! This crate simply panics on an out-of-bound access, both if you using more
57//! than `N` items or if you use a non-initialized entry:
58//! ```should_panic
59//! # use partial_array::PartialArray;
60//! // partial array is only filled half, the last entry is uninitialized and
61//! // therefore out of bounds:
62//! let mut array: PartialArray<i32, 4> = (0..2).collect();
63//! array[2] = 42; // panic!
64//! ```
65//! ```should_panic
66//! # use partial_array::PartialArray;
67//! // partial array has less space than the iterator has items:
68//! let _array: PartialArray<i32, 4> = (0..42).collect(); // panic!
69//! ```
70//!
71//! [array]: prim@array
72//! [slice]: prim@slice
73//! [`from`]: core::convert::From::from
74//! [`try_from`]: core::convert::TryFrom::try_from
75//! [macro]: crate::partial_array
76#![cfg_attr(not(test), no_std)] // allow `std` for tests
77
78pub mod iter;
79
80#[cfg(test)]
81mod tests;
82
83use core::cmp::Ordering;
84use core::fmt::{self, Debug, Formatter};
85use core::hash::{Hash, Hasher};
86use core::iter::{FromIterator, IntoIterator};
87use core::mem::{self, MaybeUninit};
88use core::ops::{Deref, DerefMut};
89
90/// A potentially partially filled array.
91///
92/// This is an array, with a length of at most `N`, but any value below that is
93/// possible. It is mainly used as a [`iter.collect()`][collect]
94/// target via the [`FromIterator`] trait.
95/// ```
96/// # use partial_array::PartialArray;
97/// fn first_five_authors<'a>(names: &mut [&'a str]) -> PartialArray<&'a str, 5> {
98///     names.sort();
99///     names.iter().copied().take(5).collect() // can be less than 5 items
100/// }
101///
102/// // e.g. works with 5 or more items, less than 5 or even none at all
103/// assert_eq!(
104///     first_five_authors(&mut ["a", "c", "b", "d", "f", "e"]),
105///     ["a", "b", "c", "d", "e"],
106/// );
107/// assert_eq!(
108///     first_five_authors(&mut ["Bela Writa", "A Nauthor"]),
109///     ["A Nauthor", "Bela Writa"],
110/// );
111/// assert_eq!(first_five_authors(&mut []), []);
112/// ```
113///
114/// It [deref]s to a slice, so you can execute the usual slice operations on it.
115///
116/// See the [crate-level-documentation](crate) for more information on the
117/// intended usage.
118///
119/// [deref]: core::ops::Deref::deref
120/// [collect]: Iterator::collect
121pub struct PartialArray<T, const N: usize> {
122    /// The number of filled entries inside the array.
123    ///
124    /// Each item in `0..filled` must be initialized. Others may or may not.
125    /// This must never be greater than `N`.
126    filled: usize,
127    /// The actual storage for the items.
128    ///
129    /// This is an array of [`MaybeUninit`] items to prevent initialization of
130    /// non-filled elements. There is the invariant: `filled` elements must be
131    /// initialized and allowed to read independently.
132    array: [MaybeUninit<T>; N],
133}
134impl<T, const N: usize> Deref for PartialArray<T, N> {
135    /// A [`PartialArray<T, _>`] dereferences to a [slice of `T`][slice].
136    type Target = [T];
137
138    /// Dereference to the slice of filled elements (potentially less than `N`).
139    fn deref(&self) -> &Self::Target {
140        let slice = &self.array[..self.filled];
141        // SAFETY: the invariant is, that `0..self.filled` is initialized, so it
142        // is no UB reading those. The transmute itself is safe, since
143        // `MaybeUninit` is `#[rpr(transparent)]`.
144        unsafe { mem::transmute(slice) }
145    }
146}
147impl<T, const N: usize> DerefMut for PartialArray<T, N> {
148    /// Dereference to the slice of filled elements (potentially less than `N`).
149    fn deref_mut(&mut self) -> &mut Self::Target {
150        let slice = &mut self.array[..self.filled];
151        // SAFETY: the invariant is, that `0..self.filled` is initialized, so it
152        // is no UB reading those. The transmute itself is safe, since
153        // `MaybeUninit` is `#[rpr(transparent)]`.
154        unsafe { mem::transmute(slice) }
155    }
156}
157impl<T: Debug, const N: usize> Debug for PartialArray<T, N> {
158    /// Debug-format the slice of filled elements (potentially less than `N`).
159    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
160        <[T] as Debug>::fmt(self, f)
161    }
162}
163impl<T: PartialEq, const N: usize, const M: usize> PartialEq<PartialArray<T, M>>
164    for PartialArray<T, N>
165{
166    /// Compare the filled elements of [`PartialArray`]s.
167    ///
168    /// Two [`PartialArray`]s can be compared even if their lengths do not
169    /// match. Only the number of filled elements and their values are compared.
170    ///
171    /// # Example
172    /// ```
173    /// # use partial_array::PartialArray;
174    /// let a: PartialArray<u8, 5> = (0..4).collect();
175    /// let b: PartialArray<u8, 500> = (0..4).collect();
176    ///
177    /// assert_eq!(a, b);
178    /// ```
179    fn eq(&self, other: &PartialArray<T, M>) -> bool {
180        self.len() == other.len() && self.deref() == other.deref()
181    }
182}
183impl<T: PartialEq, const N: usize, const M: usize> PartialEq<[T; M]> for PartialArray<T, N> {
184    /// Compare a [`PartialArray`] with a normal array.
185    ///
186    /// This compares the filled elements (potentially less than `N`).
187    ///
188    /// # Example
189    /// ```
190    /// # use partial_array::PartialArray;
191    /// let a: PartialArray<u8, 5> = (10..15).collect();
192    /// let b = [10, 11, 12, 13, 14];
193    ///
194    /// assert_eq!(a, b);
195    ///
196    /// // the other way round is also possible.
197    /// assert_eq!(b, a);
198    /// ```
199    fn eq(&self, other: &[T; M]) -> bool {
200        self.len() == other.len() && self.deref() == other.deref()
201    }
202}
203impl<T: PartialEq, const N: usize, const M: usize> PartialEq<PartialArray<T, M>> for [T; N] {
204    /// Compare a normal array with a [`PartialArray`].
205    ///
206    /// This compares the filled elements (potentially less than `N`).
207    ///
208    /// # Example
209    /// ```
210    /// # use partial_array::PartialArray;
211    /// let a = [10, 11, 12, 13, 14];
212    /// let b: PartialArray<u8, 5> = (10..15).collect();
213    ///
214    /// assert_eq!(a, b);
215    ///
216    /// // the other way round is also possible.
217    /// assert_eq!(b, a);
218    /// ```
219    fn eq(&self, other: &PartialArray<T, M>) -> bool {
220        self.len() == other.len() && self.deref() == other.deref()
221    }
222}
223impl<T: PartialEq, const N: usize> PartialEq<&[T]> for PartialArray<T, N> {
224    /// Compare the slice of filled elements (potentially less than `N`).
225    ///
226    /// # Example
227    /// ```
228    /// # use partial_array::PartialArray;
229    /// let a: PartialArray<u8, 5> = (10..15).collect();
230    /// let b = &[10, 11, 12, 13, 14][..];
231    ///
232    /// assert_eq!(a, b);
233    /// ```
234    fn eq(&self, other: &&[T]) -> bool {
235        self.len() == other.len() && self.deref() == other.deref()
236    }
237}
238impl<T: PartialEq, const N: usize> PartialEq<PartialArray<T, N>> for &[T] {
239    /// Compare a slice with a [`PartialArray`].
240    ///
241    /// This compares the filled elements (potentially less than `N`).
242    ///
243    /// # Example
244    /// ```
245    /// # use partial_array::PartialArray;
246    /// let a: &[u8] = &[10, 11, 12, 13, 14];
247    /// let b: PartialArray<u8, 5> = (10..15).collect();
248    ///
249    /// assert_eq!(a, b);
250    ///
251    /// // the other way round is also possible.
252    /// assert_eq!(b, a);
253    /// ```
254    fn eq(&self, other: &PartialArray<T, N>) -> bool {
255        self.len() == other.len() && self.deref() == other.deref()
256    }
257}
258impl<T: Eq, const N: usize> Eq for PartialArray<T, N> {}
259impl<T, const N: usize> Default for PartialArray<T, N> {
260    /// Initialize an empty [`PartialArray`].
261    fn default() -> Self {
262        Self {
263            array: [Self::UNINIT; N],
264            filled: 0,
265        }
266    }
267}
268impl<T: Hash, const N: usize> Hash for PartialArray<T, N> {
269    /// Calculate the [`Hash`] of a [`PartialArray`].
270    ///
271    /// This has takes only the initialized elements into account (which is in
272    /// line with the `PartialEq` implementation).
273    fn hash<H: Hasher>(&self, state: &mut H) {
274        self.deref().hash(state);
275    }
276}
277impl<T: PartialOrd, const N: usize> PartialOrd for PartialArray<T, N> {
278    /// Compare two [`PartialArray`]s element-by-element.
279    ///
280    /// # Example
281    /// ```
282    /// # use partial_array::partial_array;
283    /// assert!(partial_array![17.0, 24.0, 2.0] < partial_array![17.0, 24.0, 9.0]);
284    /// ```
285    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
286        self.deref().partial_cmp(other.deref())
287    }
288}
289impl<T: Ord, const N: usize> Ord for PartialArray<T, N> {
290    /// Compare two [`PartialArray`]s element-by-element.
291    ///
292    /// # Example
293    /// ```
294    /// # use partial_array::partial_array;
295    /// assert!(partial_array![17, 24, 25] < partial_array![17, 24, 100]);
296    /// ```
297    fn cmp(&self, other: &Self) -> Ordering {
298        self.deref().cmp(other.deref())
299    }
300}
301impl<T: Clone, const N: usize> Clone for PartialArray<T, N> {
302    /// Clone a [`PartialArray`].
303    ///
304    /// The whole array storage is cloned, i.e. the old and new length are the
305    /// same. Uninitialized elements remain uninitialized. The number of entries
306    /// in the array stays the same.
307    ///
308    /// # Example
309    /// ```
310    /// # use partial_array::PartialArray;
311    /// let a: PartialArray::<i32, 10> = (32..37).map(|x| x * 2).collect();
312    /// let b = a.clone();
313    ///
314    /// assert_eq!(a.len(), b.len());
315    /// assert_eq!(a, b);
316    /// ```
317    fn clone(&self) -> Self {
318        self.iter().cloned().collect()
319    }
320}
321impl<T, const N: usize> Drop for PartialArray<T, N> {
322    fn drop(&mut self) {
323        (0..self.filled)
324            .map(|i| mem::replace(&mut self.array[i], Self::UNINIT))
325            .map(|entry| {
326                // SAFETY: we only iterate over the filled entries, so we can be
327                // sure, that this is initialized.
328                unsafe { entry.assume_init() }
329            })
330            .for_each(drop);
331    }
332}
333impl<T, const N: usize> PartialArray<T, N> {
334    /// Required for `MaybeUninit::uninit()` in array initializers
335    const UNINIT: MaybeUninit<T> = MaybeUninit::uninit();
336}
337impl<T, const N: usize> FromIterator<T> for PartialArray<T, N> {
338    /// Build up a [`PartialArray`] from an iterator with potentially less than
339    /// `N` elements.
340    ///
341    /// # Example
342    /// ```
343    /// # use partial_array::PartialArray;
344    /// // a set of channels set to different values
345    /// let mut channels = [12, 13, 8, 12, 255, 8, 8, 8];
346    ///
347    /// // we want to only have the distinct channel values
348    /// channels.sort_unstable();
349    /// let distinct_channels: PartialArray<_, 8> = channels
350    ///     .windows(2)
351    ///     .chain(Some(&[channels[7], 0][..]))
352    ///     .filter(|window| window[0] != window[1])
353    ///     .map(|window| window[0])
354    ///     .collect();
355    ///
356    /// assert_eq!(distinct_channels.len(), 4);
357    /// assert_eq!(distinct_channels, [8, 12, 13, 255]);
358    /// ```
359    ///
360    /// # Panics
361    /// Panics, if the length of the iterator os greater than the maximum length
362    /// of the array (`N`).
363    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
364        let mut result = Self::default();
365        result.extend(iter);
366        result
367    }
368}
369impl<T, const N: usize> Extend<T> for PartialArray<T, N> {
370    fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
371        let remaining = (self.filled..N).len();
372        let mut iter = iter.into_iter();
373
374        iter.by_ref().take(remaining).for_each(|element| {
375            self.array[self.filled] = MaybeUninit::new(element);
376            self.filled += 1;
377        });
378
379        // check, that there are no more elements left
380        let remaining = iter.count();
381        assert_eq!(remaining, 0, "Iterator has {} elements to much", remaining);
382    }
383}
384impl<T, const N: usize> IntoIterator for PartialArray<T, N> {
385    type Item = T;
386    type IntoIter = iter::IntoIter<T, N>;
387
388    fn into_iter(self) -> Self::IntoIter {
389        iter::IntoIter::new(self)
390    }
391}
392// TODO: generalize to From<[T; M]> for PartialArray<T, N> where M <= N
393impl<T, const N: usize> From<[T; N]> for PartialArray<T, N> {
394    fn from(array: [T; N]) -> Self {
395        // TODO: is there a more performant way? Maybe with unsafe
396        core::array::IntoIter::new(array).collect()
397    }
398}
399
400/// Create a partial array from a given set of values (similar to `vec![]`).
401///
402/// # Example
403/// ```
404/// use partial_array::{partial_array, PartialArray};
405///
406/// assert_eq!(partial_array![0, 1, 2], PartialArray::from([0, 1, 2]));
407/// assert_eq!(partial_array![17, 12, 2, ], PartialArray::from([17, 12, 2]));
408/// assert_eq!(partial_array![42; 5], PartialArray::from([42; 5]));
409/// ```
410#[macro_export]
411macro_rules! partial_array {
412    ($($element:expr),*$(,)?) => {
413        $crate::PartialArray::from([$($element),*])
414    };
415    ($element:expr; $n: literal) => {
416        $crate::PartialArray::from([$element; $n])
417    };
418}