nonempty_collections/array.rs
1//! Extends non-zero length arrays with conversion methods to non-empty
2//! collections.
3//!
4//! Since fixed-size arrays are by definition already not empty, they aren't
5//! given a special wrapper type like [`crate::NEVec`]. Instead, we enable them
6//! to be easily iterated over in a compatible way:
7//!
8//! ```
9//! use nonempty_collections::*;
10//!
11//! let a: [u32; 4] = [1, 2, 3, 4];
12//! let v: NEVec<_> = a.into_nonempty_iter().map(|n| n + 1).collect();
13//! assert_eq!(nev![2, 3, 4, 5], v);
14//! ```
15//!
16//! See [`NonEmptyArrayExt`] for more conversions.
17//!
18//! # Caveats
19//!
20//! These extensions are only provided for arrays up to size 32.
21
22use core::fmt;
23use std::num::NonZeroUsize;
24
25use crate::impl_nonempty_iter_for_arrays;
26use crate::IntoNonEmptyIterator;
27use crate::NonEmptyIterator;
28
29/// Provides extension methods for non-empty arrays.
30///
31/// # Examples
32///
33/// Create a non-empty slice of an array:
34///
35/// ```
36/// # use nonempty_collections::*;
37/// assert_eq!(
38/// NESlice::try_from_slice(&[1, 2]),
39/// Some([1, 2].as_nonempty_slice())
40/// );
41/// ```
42///
43/// Get the length of an array as a [`NonZeroUsize`]:
44///
45/// ```
46/// # use nonempty_collections::NonEmptyArrayExt;
47/// # use std::num::NonZeroUsize;
48/// assert_eq!(NonZeroUsize::MIN, [1].nonzero_len());
49/// ```
50///
51/// Convert array into a non-empty vec:
52///
53/// ```
54/// # use nonempty_collections::*;
55/// assert_eq!(nev![4], [4].into_nonempty_vec());
56/// ```
57pub trait NonEmptyArrayExt<T> {
58 /// Create a `NESlice` that borrows the contents of `self`.
59 fn as_nonempty_slice(&self) -> crate::NESlice<'_, T>;
60
61 /// Returns the length of this array as a [`NonZeroUsize`].
62 fn nonzero_len(&self) -> NonZeroUsize;
63
64 /// Moves `self` into a new [`crate::NEVec`].
65 fn into_nonempty_vec(self) -> crate::NEVec<T>;
66}
67
68/// Non-empty iterator for arrays with length > 0.
69///
70/// # Examples
71///
72/// Use non-zero length arrays anywhere an [`IntoNonEmptyIterator`] is expected.
73///
74/// ```
75/// use std::num::NonZeroUsize;
76///
77/// use nonempty_collections::*;
78///
79/// fn is_one<T>(iter: impl IntoNonEmptyIterator<Item = T>) {
80/// assert_eq!(NonZeroUsize::MIN, iter.into_nonempty_iter().count());
81/// }
82///
83/// is_one([0]);
84/// ```
85///
86/// Only compiles for non-empty arrays:
87///
88/// ```compile_fail
89/// use nonempty_collections::*;
90///
91/// fn is_one(iter: impl IntoNonEmptyIterator<Item = usize>) {}
92///
93/// is_one([]); // Doesn't compile because it is empty.
94/// ```
95#[derive(Clone)]
96pub struct ArrayNonEmptyIterator<T, const C: usize> {
97 iter: core::array::IntoIter<T, C>,
98}
99
100impl<T, const C: usize> IntoIterator for ArrayNonEmptyIterator<T, C> {
101 type Item = T;
102
103 type IntoIter = core::array::IntoIter<T, C>;
104
105 fn into_iter(self) -> Self::IntoIter {
106 self.iter
107 }
108}
109
110impl<T, const C: usize> NonEmptyIterator for ArrayNonEmptyIterator<T, C> {}
111
112impl<T: fmt::Debug, const C: usize> fmt::Debug for ArrayNonEmptyIterator<T, C> {
113 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
114 self.iter.fmt(f)
115 }
116}
117
118// NOTE 2024-04-05 This must never be implemented for 0.
119//
120// Also, happy birthday Dad.
121impl_nonempty_iter_for_arrays!(
122 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26,
123 27, 28, 29, 30, 31, 32
124);
125
126#[doc(hidden)]
127#[macro_export]
128macro_rules! impl_nonempty_iter_for_arrays {
129 ($($i:literal),+ $(,)?) => {
130 $(
131 impl<T> IntoNonEmptyIterator for [T; $i] {
132 type IntoNEIter = ArrayNonEmptyIterator<T, $i>;
133
134 fn into_nonempty_iter(self) -> Self::IntoNEIter {
135 ArrayNonEmptyIterator {
136 iter: self.into_iter(),
137 }
138 }
139 }
140
141 impl<'a, T> IntoNonEmptyIterator for &'a [T; $i] {
142 type IntoNEIter = $crate::slice::Iter<'a,T>;
143
144 fn into_nonempty_iter(self) -> Self::IntoNEIter {
145 self.as_nonempty_slice().into_nonempty_iter()
146 }
147 }
148
149 impl<T> NonEmptyArrayExt<T> for [T; $i] {
150 fn as_nonempty_slice(&self) -> $crate::NESlice<'_, T> {
151 // This should never panic because a slice with length > 0
152 // is non-empty by definition.
153 $crate::NESlice::try_from_slice(self).unwrap()
154 }
155
156 fn nonzero_len(&self) -> NonZeroUsize {
157 // This should be fine because $i is always > 0.
158 unsafe { NonZeroUsize::new_unchecked($i) }
159 }
160
161 fn into_nonempty_vec(self) -> $crate::NEVec<T> {
162 self.into_nonempty_iter().collect()
163 }
164 }
165 )+
166 };
167}
168
169#[cfg(test)]
170mod test {
171 use crate::IntoNonEmptyIterator;
172 use crate::NonEmptyIterator;
173
174 #[test]
175 fn test_iter() {
176 let iter = [1, 2, 3, 4].into_nonempty_iter();
177 let (first, rest) = iter.next();
178 assert_eq!(1, first);
179 assert_eq!(vec![2, 3, 4], rest.into_iter().collect::<Vec<_>>());
180
181 let iter = [1].into_nonempty_iter();
182 let (first, rest) = iter.next();
183 assert_eq!(1, first);
184 assert_eq!(0, rest.into_iter().count());
185
186 assert_eq!(33, [1, -2, 33, 4].into_nonempty_iter().max());
187 }
188
189 #[test]
190 fn test_iter_ref() {
191 let iter = (&[1, 2, 3, 4]).into_nonempty_iter();
192 let (first, rest) = iter.next();
193 assert_eq!(&1, first);
194 assert_eq!(vec![&2, &3, &4], rest.into_iter().collect::<Vec<_>>());
195
196 let iter = (&[1]).into_nonempty_iter();
197 let (first, rest) = iter.next();
198 assert_eq!(&1, first);
199 assert_eq!(0, rest.into_iter().count());
200
201 assert_eq!(&33, (&[1, -2, 33, 4]).into_nonempty_iter().max());
202 }
203}