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}