array_util/lib.rs
1//! `no_std` array helpers available without nightly.
2//!
3//! ## Description
4//!
5//! Many useful array and slice methods are currently gated by nightly
6//! features, though their general functionality and interface is essentially
7//! stable. As such this crate provides stable alternatives to the following
8//! features, often the same underlying implementation as the current nightly
9//! version:
10//!
11//! - [`array_try_from_fn`]
12//! - [`array_try_map`]
13//! - [`array_chunks`]
14//! - [`slice_as_chunks`]
15//! - [`slice_flatten`]
16//!
17//! ## Usage
18//!
19//! Users can either import an `Ext` trait (`SliceExt`, `ArrayExt`, or
20//! `SliceOfArrayExt`) traits to bring in the desired methods, or use the bare
21//! functions. Note that trait methods have the `_ext` suffix to avoid
22//! collision with the core library methods.
23//!
24//! ```
25//! use array_util::ArrayExt;
26//!
27//! let a = ["1", "2", "3"];
28//! let b = a.try_map_ext(|v| v.parse::<u32>()).unwrap().map(|v| v + 1);
29//! assert_eq!(b, [2, 3, 4]);
30//!
31//! let a = ["1", "2a", "3"];
32//! let b = a.try_map_ext(|v| v.parse::<u32>());
33//! assert!(b.is_err());
34//! ```
35//!
36//! ```
37//! let a = ["1", "2", "3"];
38//! let b = array_util::try_map(a, |v| v.parse::<u32>()).unwrap().map(|v| v + 1);
39//! assert_eq!(b, [2, 3, 4]);
40//!
41//! let a = ["1", "2a", "3"];
42//! let b = array_util::try_map(a, |v| v.parse::<u32>());
43//! assert!(b.is_err());
44//! ```
45//!
46//! ## Limitations
47//!
48//! These functions aren't stabilized because they rely on undecided behaviors.
49//! For example, "should compile-time errors be generated for `0` length
50//! arrays?" or "What should the associated types and traits of `Try` be?". As
51//! these questions remain unresolved, reliance on the particular answers
52//! this crate has chosen in it's implementation may make porting to the
53//! eventual stabilized version more painful. If you're just calling functions,
54//! you'll probably be fine, but try to avoid using the `Ext` traits as bounds.
55//!
56//! [`array_try_from_fn`]: https://github.com/rust-lang/rust/issues/89379
57//! [`array_try_map`]: https://github.com/rust-lang/rust/issues/79711
58//! [`array_chunks`]: https://github.com/rust-lang/rust/issues/74985
59//! [`slice_as_chunks`]: https://github.com/rust-lang/rust/issues/74985
60//! [`slice_flatten`]: https://github.com/rust-lang/rust/issues/95629
61#![no_std]
62#![warn(missing_docs)]
63
64use core::{array, iter::FusedIterator, mem::size_of, ops::ControlFlow, slice};
65
66use arrayvec::ArrayVec;
67
68#[doc(hidden)]
69mod try_helper;
70
71use try_helper::*;
72
73/// A fallible function `f` applied to each element on array `self` in order to
74/// return an array the same size as `self` or the first error encountered.
75///
76/// The return type of this function depends on the return type of the closure.
77/// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N], E>`.
78/// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
79///
80/// # Examples
81///
82/// ```
83/// let a = ["1", "2", "3"];
84/// let b = array_util::try_map(a, |v| v.parse::<u32>()).unwrap().map(|v| v + 1);
85/// assert_eq!(b, [2, 3, 4]);
86///
87/// let a = ["1", "2a", "3"];
88/// let b = array_util::try_map(a, |v| v.parse::<u32>());
89/// assert!(b.is_err());
90///
91/// use std::num::NonZeroU32;
92/// let z = [1, 2, 0, 3, 4];
93/// assert_eq!(array_util::try_map(z, NonZeroU32::new), None);
94/// let a = [1, 2, 3];
95/// let b = array_util::try_map(a, NonZeroU32::new);
96/// let c = b.map(|x| x.map(NonZeroU32::get));
97/// assert_eq!(c, Some(a));
98/// ```
99pub fn try_map<T, const N: usize, F, R>(
100 vals: [T; N],
101 mut f: F,
102) -> <<R as Try>::Residual as Residual<[<R as Try>::Output; N]>>::TryType
103where
104 F: FnMut(T) -> R,
105 R: Try,
106 <R as Try>::Residual: Residual<[<R as Try>::Output; N]>,
107{
108 let mut output = ArrayVec::new();
109 for val in vals {
110 match f(val).branch() {
111 ControlFlow::Break(b) => return FromResidual::from_residual(b),
112
113 // SAFETY: `val` is len N and `output` has capacity N
114 ControlFlow::Continue(c) => unsafe { output.push_unchecked(c) },
115 }
116 }
117 // SAFETY: `output` can only be len N if we got here
118 unsafe { Try::from_output(output.into_inner_unchecked()) }
119}
120
121/// Creates an array `[T; N]` where each fallible array element `T` is returned by the `cb` call.
122/// Unlike [`from_fn`], where the element creation can't fail, this version will return an error
123/// if any element creation was unsuccessful.
124///
125/// The return type of this function depends on the return type of the closure.
126/// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N], E>`.
127/// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
128///
129/// # Arguments
130///
131/// * `cb`: Callback where the passed argument is the current array index.
132///
133/// # Example
134///
135/// ```rust
136/// # use core::convert::TryInto;
137/// let array: Result<[u8; 5], _> = array_util::try_from_fn(|i| i.try_into());
138/// assert_eq!(array, Ok([0, 1, 2, 3, 4]));
139///
140/// let array: Result<[i8; 200], _> = array_util::try_from_fn(|i| i.try_into());
141/// assert!(array.is_err());
142///
143/// let array: Option<[_; 4]> = array_util::try_from_fn(|i| i.checked_add(100));
144/// assert_eq!(array, Some([100, 101, 102, 103]));
145///
146/// let array: Option<[_; 4]> = array_util::try_from_fn(|i| i.checked_sub(100));
147/// assert_eq!(array, None);
148/// ```
149///
150/// [`from_fn`]: core::array::from_fn
151#[inline]
152pub fn try_from_fn<R, const N: usize, F>(
153 cb: F,
154) -> <<R as Try>::Residual as Residual<[R::Output; N]>>::TryType
155where
156 F: FnMut(usize) -> R,
157 R: Try,
158 R::Residual: Residual<[R::Output; N]>,
159{
160 try_map(array::from_fn(|i| i), cb)
161}
162
163/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a
164/// time), starting at the beginning of the slice.
165///
166/// When the slice len is not evenly divided by the chunk size, the last
167/// up to `N-1` elements will be omitted but can be retrieved from
168/// the [`remainder`] function from the iterator.
169///
170/// This struct is created by the [`array_chunks`] method on [slices].
171///
172/// # Example
173///
174/// ```
175/// let slice = ['l', 'o', 'r', 'e', 'm'];
176/// let iter = array_util::array_chunks::<_, 2>(&slice);
177/// ```
178///
179/// [`remainder`]: ArrayChunks::remainder
180/// [slices]: prim@slice
181#[derive(Debug)]
182#[must_use = "iterators are lazy and do nothing unless consumed"]
183pub struct ArrayChunks<'a, T: 'a, const N: usize> {
184 iter: slice::Iter<'a, [T; N]>,
185 rem: &'a [T],
186}
187
188impl<'a, T, const N: usize> ArrayChunks<'a, T, N> {
189 #[inline]
190 pub(crate) fn new(slice: &'a [T]) -> Self {
191 let (array_slice, rem) = as_chunks(slice);
192 Self {
193 iter: array_slice.iter(),
194 rem,
195 }
196 }
197
198 /// Returns the remainder of the original slice that is not going to be
199 /// returned by the iterator. The returned slice has at most `N-1`
200 /// elements.
201 #[must_use]
202 pub fn remainder(&self) -> &'a [T] {
203 self.rem
204 }
205}
206
207impl<T, const N: usize> Clone for ArrayChunks<'_, T, N> {
208 fn clone(&self) -> Self {
209 ArrayChunks {
210 iter: self.iter.clone(),
211 rem: self.rem,
212 }
213 }
214}
215
216impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> {
217 type Item = &'a [T; N];
218
219 #[inline]
220 fn next(&mut self) -> Option<&'a [T; N]> {
221 self.iter.next()
222 }
223
224 #[inline]
225 fn size_hint(&self) -> (usize, Option<usize>) {
226 self.iter.size_hint()
227 }
228
229 #[inline]
230 fn count(self) -> usize {
231 self.iter.count()
232 }
233
234 #[inline]
235 fn nth(&mut self, n: usize) -> Option<Self::Item> {
236 self.iter.nth(n)
237 }
238
239 #[inline]
240 fn last(self) -> Option<Self::Item> {
241 self.iter.last()
242 }
243}
244
245impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> {
246 #[inline]
247 fn next_back(&mut self) -> Option<&'a [T; N]> {
248 self.iter.next_back()
249 }
250
251 #[inline]
252 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
253 self.iter.nth_back(n)
254 }
255}
256
257impl<T, const N: usize> ExactSizeIterator for ArrayChunks<'_, T, N> {}
258
259impl<T, const N: usize> FusedIterator for ArrayChunks<'_, T, N> {}
260
261/// Returns an iterator over `N` elements of the slice at a time, starting at the
262/// beginning of the slice.
263///
264/// The chunks are array references and do not overlap. If `N` does not divide the
265/// length of the slice, then the last up to `N-1` elements will be omitted and can be
266/// retrieved from the `remainder` function of the iterator.
267///
268/// This method is the const generic equivalent of [`chunks_exact`].
269///
270/// # Panics
271///
272/// Panics if `N` is 0. This check will most probably get changed to a compile time
273/// error before this method gets stabilized.
274///
275/// # Examples
276///
277/// ```
278/// let slice = ['l', 'o', 'r', 'e', 'm'];
279/// let mut iter = array_util::array_chunks(&slice);
280/// assert_eq!(iter.next().unwrap(), &['l', 'o']);
281/// assert_eq!(iter.next().unwrap(), &['r', 'e']);
282/// assert!(iter.next().is_none());
283/// assert_eq!(iter.remainder(), &['m']);
284/// ```
285///
286/// [`chunks_exact`]: prim@slice#method.chunks_exact
287#[inline]
288pub fn array_chunks<T, const N: usize>(vals: &[T]) -> ArrayChunks<'_, T, N> {
289 assert!(N != 0, "chunk size must be non-zero");
290 ArrayChunks::new(vals)
291}
292
293/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements
294/// at a time), starting at the beginning of the slice.
295///
296/// When the slice len is not evenly divided by the chunk size, the last
297/// up to `N-1` elements will be omitted but can be retrieved from
298/// the [`into_remainder`] function from the iterator.
299///
300/// This struct is created by the [`array_chunks_mut`] method on [slices].
301///
302/// # Example
303///
304/// ```
305/// let mut slice = ['l', 'o', 'r', 'e', 'm'];
306/// let iter = array_util::array_chunks_mut::<_, 2>(&mut slice);
307/// ```
308///
309/// [`into_remainder`]: ArrayChunksMut::into_remainder
310/// [slices]: prim@slice
311#[derive(Debug)]
312#[must_use = "iterators are lazy and do nothing unless consumed"]
313pub struct ArrayChunksMut<'a, T: 'a, const N: usize> {
314 iter: slice::IterMut<'a, [T; N]>,
315 rem: &'a mut [T],
316}
317
318impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> {
319 #[inline]
320 pub(crate) fn new(slice: &'a mut [T]) -> Self {
321 let (array_slice, rem) = as_chunks_mut(slice);
322 Self {
323 iter: array_slice.iter_mut(),
324 rem,
325 }
326 }
327
328 /// Returns the remainder of the original slice that is not going to be
329 /// returned by the iterator. The returned slice has at most `N-1`
330 /// elements.
331 #[must_use]
332 pub fn into_remainder(self) -> &'a mut [T] {
333 self.rem
334 }
335}
336
337impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> {
338 type Item = &'a mut [T; N];
339
340 #[inline]
341 fn next(&mut self) -> Option<&'a mut [T; N]> {
342 self.iter.next()
343 }
344
345 #[inline]
346 fn size_hint(&self) -> (usize, Option<usize>) {
347 self.iter.size_hint()
348 }
349
350 #[inline]
351 fn count(self) -> usize {
352 self.iter.count()
353 }
354
355 #[inline]
356 fn nth(&mut self, n: usize) -> Option<Self::Item> {
357 self.iter.nth(n)
358 }
359
360 #[inline]
361 fn last(self) -> Option<Self::Item> {
362 self.iter.last()
363 }
364}
365
366impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> {
367 #[inline]
368 fn next_back(&mut self) -> Option<&'a mut [T; N]> {
369 self.iter.next_back()
370 }
371
372 #[inline]
373 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
374 self.iter.nth_back(n)
375 }
376}
377
378impl<T, const N: usize> ExactSizeIterator for ArrayChunksMut<'_, T, N> {}
379
380impl<T, const N: usize> FusedIterator for ArrayChunksMut<'_, T, N> {}
381
382/// Returns an iterator over `N` elements of the slice at a time, starting at the
383/// beginning of the slice.
384///
385/// The chunks are mutable array references and do not overlap. If `N` does not divide
386/// the length of the slice, then the last up to `N-1` elements will be omitted and
387/// can be retrieved from the `into_remainder` function of the iterator.
388///
389/// This method is the const generic equivalent of [`chunks_exact_mut`].
390///
391/// # Panics
392///
393/// Panics if `N` is 0. This check will most probably get changed to a compile time
394/// error before this method gets stabilized.
395///
396/// # Examples
397///
398/// ```
399/// let v = &mut [0, 0, 0, 0, 0];
400/// let mut count = 1;
401///
402/// for chunk in array_util::array_chunks_mut(v) {
403/// *chunk = [count; 2];
404/// count += 1;
405/// }
406/// assert_eq!(v, &[1, 1, 2, 2, 0]);
407/// ```
408///
409/// [`chunks_exact_mut`]: prim@slice#method.chunks_exact_mut
410#[inline]
411pub fn array_chunks_mut<T, const N: usize>(vals: &mut [T]) -> ArrayChunksMut<'_, T, N> {
412 assert!(N != 0, "chunk size must be non-zero");
413 ArrayChunksMut::new(vals)
414}
415
416/// Splits the slice into a slice of `N`-element arrays,
417/// starting at the beginning of the slice,
418/// and a remainder slice with length strictly less than `N`.
419///
420/// # Panics
421///
422/// Panics if `N` is 0. This check will most probably get changed to a compile time
423/// error before this method gets stabilized.
424///
425/// # Examples
426///
427/// ```
428/// let slice = ['l', 'o', 'r', 'e', 'm'];
429/// let (chunks, remainder) = array_util::as_chunks(&slice);
430/// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
431/// assert_eq!(remainder, &['m']);
432/// ```
433///
434/// If you expect the slice to be an exact multiple, you can combine
435/// `let`-`else` with an empty slice pattern:
436/// ```
437/// let slice = ['R', 'u', 's', 't'];
438/// let (chunks, []) = array_util::as_chunks::<_, 2>(&slice) else {
439/// panic!("slice didn't have even length")
440/// };
441/// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
442/// ```
443#[inline]
444#[must_use]
445pub const fn as_chunks<T, const N: usize>(vals: &[T]) -> (&[[T; N]], &[T]) {
446 assert!(N != 0, "chunk size must be non-zero");
447 let len = vals.len() / N;
448 let (multiple_of_n, remainder) = vals.split_at(len * N);
449 // SAFETY: We already panicked for zero, and ensured by construction
450 // that the length of the subslice is a multiple of N.
451 let array_slice = unsafe { as_chunks_unchecked(multiple_of_n) };
452 (array_slice, remainder)
453}
454
455/// Splits the slice into a slice of `N`-element arrays,
456/// assuming that there's no remainder.
457///
458/// # Safety
459///
460/// This may only be called when
461/// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`).
462/// - `N != 0`.
463///
464/// # Examples
465///
466/// ```
467/// let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!'];
468/// let chunks: &[[char; 1]] =
469/// // SAFETY: 1-element chunks never have remainder
470/// unsafe { array_util::as_chunks_unchecked(&slice) };
471/// assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]);
472/// let chunks: &[[char; 3]] =
473/// // SAFETY: The slice length (6) is a multiple of 3
474/// unsafe { array_util::as_chunks_unchecked(&slice) };
475/// assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]);
476///
477/// // These would be unsound:
478/// // let chunks: &[[_; 5]] = array_util::as_chunks_unchecked(slice) // The slice length is not a multiple of 5
479/// // let chunks: &[[_; 0]] = array_util::as_chunks_unchecked(slice) // Zero-length chunks are never allowed
480/// ```
481#[inline]
482#[must_use]
483pub const unsafe fn as_chunks_unchecked<T, const N: usize>(vals: &[T]) -> &[[T; N]] {
484 debug_assert!(
485 N != 0 && vals.len() % N == 0,
486 "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks",
487 );
488 let new_len = vals.len() / N;
489 // SAFETY: We cast a slice of `new_len * N` elements into
490 // a slice of `new_len` many `N` elements chunks.
491 unsafe { slice::from_raw_parts(vals.as_ptr().cast(), new_len) }
492}
493
494/// Splits the slice into a slice of `N`-element arrays,
495/// starting at the beginning of the slice,
496/// and a remainder slice with length strictly less than `N`.
497///
498/// # Panics
499///
500/// Panics if `N` is 0. This check will most probably get changed to a compile time
501/// error before this method gets stabilized.
502///
503/// # Examples
504///
505/// ```
506/// let v = &mut [0, 0, 0, 0, 0];
507/// let mut count = 1;
508///
509/// let (chunks, remainder) = array_util::as_chunks_mut(v);
510/// remainder[0] = 9;
511/// for chunk in chunks {
512/// *chunk = [count; 2];
513/// count += 1;
514/// }
515/// assert_eq!(v, &[1, 1, 2, 2, 9]);
516/// ```
517#[inline]
518#[must_use]
519pub fn as_chunks_mut<T, const N: usize>(vals: &mut [T]) -> (&mut [[T; N]], &mut [T]) {
520 assert!(N != 0, "chunk size must be non-zero");
521 let len = vals.len() / N;
522 let (multiple_of_n, remainder) = vals.split_at_mut(len * N);
523 // SAFETY: We already panicked for zero, and ensured by construction
524 // that the length of the subslice is a multiple of N.
525 let array_slice = unsafe { as_chunks_unchecked_mut(multiple_of_n) };
526 (array_slice, remainder)
527}
528
529/// Splits the slice into a slice of `N`-element arrays,
530/// assuming that there's no remainder.
531///
532/// # Safety
533///
534/// This may only be called when
535/// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`).
536/// - `N != 0`.
537///
538/// # Examples
539///
540/// ```
541/// let slice: &mut [char] = &mut ['l', 'o', 'r', 'e', 'm', '!'];
542/// let chunks: &mut [[char; 1]] =
543/// // SAFETY: 1-element chunks never have remainder
544/// unsafe { array_util::as_chunks_unchecked_mut(slice) };
545/// chunks[0] = ['L'];
546/// assert_eq!(chunks, &[['L'], ['o'], ['r'], ['e'], ['m'], ['!']]);
547/// let chunks: &mut [[char; 3]] =
548/// // SAFETY: The slice length (6) is a multiple of 3
549/// unsafe { array_util::as_chunks_unchecked_mut(slice) };
550/// chunks[1] = ['a', 'x', '?'];
551/// assert_eq!(slice, &['L', 'o', 'r', 'a', 'x', '?']);
552///
553/// // These would be unsound:
554/// // let chunks: &[[_; 5]] = array_util::as_chunks_unchecked_mut(slice) // The slice length is not a multiple of 5
555/// // let chunks: &[[_; 0]] = array_util::as_chunks_unchecked_mut(slice) // Zero-length chunks are never allowed
556/// ```
557#[inline]
558#[must_use]
559pub unsafe fn as_chunks_unchecked_mut<T, const N: usize>(vals: &mut [T]) -> &mut [[T; N]] {
560 debug_assert!(
561 N != 0 && vals.len() % N == 0,
562 "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks",
563 );
564 let new_len = vals.len() / N;
565 // SAFETY: We cast a slice of `new_len * N` elements into
566 // a slice of `new_len` many `N` elements chunks.
567 unsafe { slice::from_raw_parts_mut(vals.as_mut_ptr().cast(), new_len) }
568}
569
570/// Splits the slice into a slice of `N`-element arrays,
571/// starting at the end of the slice,
572/// and a remainder slice with length strictly less than `N`.
573///
574/// # Panics
575///
576/// Panics if `N` is 0. This check will most probably get changed to a compile time
577/// error before this method gets stabilized.
578///
579/// # Examples
580///
581/// ```
582/// let slice = ['l', 'o', 'r', 'e', 'm'];
583/// let (remainder, chunks) = array_util::as_rchunks(&slice);
584/// assert_eq!(remainder, &['l']);
585/// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]);
586/// ```
587#[inline]
588#[must_use]
589pub const fn as_rchunks<T, const N: usize>(vals: &[T]) -> (&[T], &[[T; N]]) {
590 assert!(N != 0, "chunk size must be non-zero");
591 let len = vals.len() / N;
592 let (remainder, multiple_of_n) = vals.split_at(vals.len() - len * N);
593 // SAFETY: We already panicked for zero, and ensured by construction
594 // that the length of the subslice is a multiple of N.
595 let array_slice = unsafe { as_chunks_unchecked(multiple_of_n) };
596 (remainder, array_slice)
597}
598
599/// Splits the slice into a slice of `N`-element arrays,
600/// starting at the end of the slice,
601/// and a remainder slice with length strictly less than `N`.
602///
603/// # Panics
604///
605/// Panics if `N` is 0. This check will most probably get changed to a compile time
606/// error before this method gets stabilized.
607///
608/// # Examples
609///
610/// ```
611/// let v = &mut [0, 0, 0, 0, 0];
612/// let mut count = 1;
613///
614/// let (remainder, chunks) = array_util::as_rchunks_mut(v);
615/// remainder[0] = 9;
616/// for chunk in chunks {
617/// *chunk = [count; 2];
618/// count += 1;
619/// }
620/// assert_eq!(v, &[9, 1, 1, 2, 2]);
621/// ```
622#[inline]
623#[must_use]
624pub fn as_rchunks_mut<T, const N: usize>(vals: &mut [T]) -> (&mut [T], &mut [[T; N]]) {
625 assert!(N != 0, "chunk size must be non-zero");
626 let len = vals.len() / N;
627 let (remainder, multiple_of_n) = vals.split_at_mut(vals.len() - len * N);
628 // SAFETY: We already panicked for zero, and ensured by construction
629 // that the length of the subslice is a multiple of N.
630 let array_slice = unsafe { as_chunks_unchecked_mut(multiple_of_n) };
631 (remainder, array_slice)
632}
633
634/// Takes a `&[[T; N]]`, and flattens it to a `&[T]`.
635///
636/// # Panics
637///
638/// This panics if the length of the resulting slice would overflow a `usize`.
639///
640/// This is only possible when flattening a slice of arrays of zero-sized
641/// types, and thus tends to be irrelevant in practice. If
642/// `size_of::<T>() > 0`, this will never panic.
643///
644/// # Examples
645///
646/// ```
647/// assert_eq!(array_util::flatten(&[[1, 2, 3], [4, 5, 6]]), &[1, 2, 3, 4, 5, 6]);
648///
649/// assert_eq!(
650/// array_util::flatten(&[[1, 2, 3], [4, 5, 6]]),
651/// array_util::flatten(&[[1, 2], [3, 4], [5, 6]]),
652/// );
653///
654/// let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []];
655/// assert!(array_util::flatten(&slice_of_empty_arrays).is_empty());
656///
657/// let empty_slice_of_arrays: &[[u32; 10]] = &[];
658/// assert!(array_util::flatten(&empty_slice_of_arrays).is_empty());
659/// ```
660pub const fn flatten<T, const N: usize>(vals: &[[T; N]]) -> &[T] {
661 let len = if size_of::<T>() == 0 {
662 match vals.len().checked_mul(N) {
663 Some(v) => v,
664 None => panic!("slice len overflow"),
665 }
666 } else {
667 vals.len() * N
668 };
669 // SAFETY: `[T]` is layout-identical to `[T; N]`
670 unsafe { slice::from_raw_parts(vals.as_ptr().cast(), len) }
671}
672
673/// Takes a `&mut [[T; N]]`, and flattens it to a `&mut [T]`.
674///
675/// # Panics
676///
677/// This panics if the length of the resulting slice would overflow a `usize`.
678///
679/// This is only possible when flattening a slice of arrays of zero-sized
680/// types, and thus tends to be irrelevant in practice. If
681/// `size_of::<T>() > 0`, this will never panic.
682///
683/// # Examples
684///
685/// ```
686/// fn add_5_to_all(slice: &mut [i32]) {
687/// for i in slice {
688/// *i += 5;
689/// }
690/// }
691///
692/// let mut array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
693/// add_5_to_all(array_util::flatten_mut(&mut array));
694/// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]);
695/// ```
696pub fn flatten_mut<T, const N: usize>(vals: &mut [[T; N]]) -> &mut [T] {
697 let len = if size_of::<T>() == 0 {
698 vals.len().checked_mul(N).expect("slice len overflow")
699 } else {
700 vals.len() * N
701 };
702 // SAFETY: `[T]` is layout-identical to `[T; N]`
703 unsafe { slice::from_raw_parts_mut(vals.as_mut_ptr().cast(), len) }
704}
705
706/// A helper extension trait for arrays
707pub trait ArrayExt {
708 #[doc(hidden)]
709 type T;
710 #[doc(hidden)]
711 type TN<U>: ArrayExt<T = U, TN<Self::T> = Self>;
712
713 /// A fallible function `f` applied to each element on array `self` in order to
714 /// return an array the same size as `self` or the first error encountered.
715 ///
716 /// The return type of this function depends on the return type of the closure.
717 /// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N], E>`.
718 /// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
719 ///
720 /// # Examples
721 ///
722 /// ```
723 /// use array_util::ArrayExt;
724 ///
725 /// let a = ["1", "2", "3"];
726 /// let b = a.try_map_ext(|v| v.parse::<u32>()).unwrap().map(|v| v + 1);
727 /// assert_eq!(b, [2, 3, 4]);
728 ///
729 /// let a = ["1", "2a", "3"];
730 /// let b = a.try_map_ext(|v| v.parse::<u32>());
731 /// assert!(b.is_err());
732 ///
733 /// use std::num::NonZeroU32;
734 /// let z = [1, 2, 0, 3, 4];
735 /// assert_eq!(z.try_map_ext(NonZeroU32::new), None);
736 /// let a = [1, 2, 3];
737 /// let b = a.try_map_ext(NonZeroU32::new);
738 /// let c = b.map(|x| x.map(NonZeroU32::get));
739 /// assert_eq!(c, Some(a));
740 /// ```
741 fn try_map_ext<F, R>(
742 self,
743 f: F,
744 ) -> <<R as Try>::Residual as Residual<Self::TN<<R as Try>::Output>>>::TryType
745 where
746 F: FnMut(Self::T) -> R,
747 R: Try,
748 <R as Try>::Residual: Residual<Self::TN<<R as Try>::Output>>;
749}
750
751impl<T, const N: usize> ArrayExt for [T; N] {
752 type T = T;
753 type TN<U> = [U; N];
754
755 /// A fallible function `f` applied to each element on array `self` in order to
756 /// return an array the same size as `self` or the first error encountered.
757 ///
758 /// The return type of this function depends on the return type of the closure.
759 /// If you return `Result<T, E>` from the closure, you'll get a `Result<[T; N], E>`.
760 /// If you return `Option<T>` from the closure, you'll get an `Option<[T; N]>`.
761 ///
762 /// # Examples
763 ///
764 /// ```
765 /// use array_util::ArrayExt;
766 ///
767 /// let a = ["1", "2", "3"];
768 /// let b = a.try_map_ext(|v| v.parse::<u32>()).unwrap().map(|v| v + 1);
769 /// assert_eq!(b, [2, 3, 4]);
770 ///
771 /// let a = ["1", "2a", "3"];
772 /// let b = a.try_map_ext(|v| v.parse::<u32>());
773 /// assert!(b.is_err());
774 ///
775 /// use std::num::NonZeroU32;
776 /// let z = [1, 2, 0, 3, 4];
777 /// assert_eq!(z.try_map_ext(NonZeroU32::new), None);
778 /// let a = [1, 2, 3];
779 /// let b = a.try_map_ext(NonZeroU32::new);
780 /// let c = b.map(|x| x.map(NonZeroU32::get));
781 /// assert_eq!(c, Some(a));
782 /// ```
783 #[inline]
784 fn try_map_ext<F, R>(
785 self,
786 f: F,
787 ) -> <<R as Try>::Residual as Residual<[<R as Try>::Output; N]>>::TryType
788 where
789 F: FnMut(T) -> R,
790 R: Try,
791 <R as Try>::Residual: Residual<[<R as Try>::Output; N]>,
792 {
793 try_map(self, f)
794 }
795}
796
797/// A helper extension trait for slices
798pub trait SliceExt {
799 #[doc(hidden)]
800 type T;
801
802 /// Returns an iterator over `N` elements of the slice at a time, starting at the
803 /// beginning of the slice.
804 ///
805 /// The chunks are array references and do not overlap. If `N` does not divide the
806 /// length of the slice, then the last up to `N-1` elements will be omitted and can be
807 /// retrieved from the `remainder` function of the iterator.
808 ///
809 /// This method is the const generic equivalent of [`chunks_exact`].
810 ///
811 /// # Panics
812 ///
813 /// Panics if `N` is 0. This check will most probably get changed to a compile time
814 /// error before this method gets stabilized.
815 ///
816 /// # Examples
817 ///
818 /// ```
819 /// use array_util::SliceExt;
820 ///
821 /// let slice = ['l', 'o', 'r', 'e', 'm'];
822 /// let mut iter = slice.array_chunks_ext();
823 /// assert_eq!(iter.next().unwrap(), &['l', 'o']);
824 /// assert_eq!(iter.next().unwrap(), &['r', 'e']);
825 /// assert!(iter.next().is_none());
826 /// assert_eq!(iter.remainder(), &['m']);
827 /// ```
828 ///
829 /// [`chunks_exact`]: prim@slice#method.chunks_exact
830 fn array_chunks_ext<const N: usize>(&self) -> ArrayChunks<'_, Self::T, N>;
831
832 /// Returns an iterator over `N` elements of the slice at a time, starting at the
833 /// beginning of the slice.
834 ///
835 /// The chunks are mutable array references and do not overlap. If `N` does not divide
836 /// the length of the slice, then the last up to `N-1` elements will be omitted and
837 /// can be retrieved from the `into_remainder` function of the iterator.
838 ///
839 /// This method is the const generic equivalent of [`chunks_exact_mut`].
840 ///
841 /// # Panics
842 ///
843 /// Panics if `N` is 0. This check will most probably get changed to a compile time
844 /// error before this method gets stabilized.
845 ///
846 /// # Examples
847 ///
848 /// ```
849 /// use array_util::SliceExt;
850 ///
851 /// let v = &mut [0, 0, 0, 0, 0];
852 /// let mut count = 1;
853 ///
854 /// for chunk in v.array_chunks_mut_ext() {
855 /// *chunk = [count; 2];
856 /// count += 1;
857 /// }
858 /// assert_eq!(v, &[1, 1, 2, 2, 0]);
859 /// ```
860 ///
861 /// [`chunks_exact_mut`]: prim@slice#method.chunks_exact_mut
862 fn array_chunks_mut_ext<const N: usize>(&mut self) -> ArrayChunksMut<'_, Self::T, N>;
863
864 /// Splits the slice into a slice of `N`-element arrays,
865 /// starting at the beginning of the slice,
866 /// and a remainder slice with length strictly less than `N`.
867 ///
868 /// # Panics
869 ///
870 /// Panics if `N` is 0. This check will most probably get changed to a compile time
871 /// error before this method gets stabilized.
872 ///
873 /// # Examples
874 ///
875 /// ```
876 /// use array_util::SliceExt;
877 ///
878 /// let slice = ['l', 'o', 'r', 'e', 'm'];
879 /// let (chunks, remainder) = slice.as_chunks_ext();
880 /// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
881 /// assert_eq!(remainder, &['m']);
882 /// ```
883 ///
884 /// If you expect the slice to be an exact multiple, you can combine
885 /// `let`-`else` with an empty slice pattern:
886 /// ```
887 /// use array_util::SliceExt;
888 ///
889 /// let slice = ['R', 'u', 's', 't'];
890 /// let (chunks, []) = slice.as_chunks_ext::<2>() else {
891 /// panic!("slice didn't have even length")
892 /// };
893 /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
894 /// ```
895 #[must_use]
896 fn as_chunks_ext<const N: usize>(&self) -> (&[[Self::T; N]], &[Self::T]);
897
898 /// Splits the slice into a slice of `N`-element arrays,
899 /// assuming that there's no remainder.
900 ///
901 /// # Safety
902 ///
903 /// This may only be called when
904 /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`).
905 /// - `N != 0`.
906 ///
907 /// # Examples
908 ///
909 /// ```
910 /// use array_util::SliceExt;
911 ///
912 /// let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!'];
913 /// let chunks: &[[char; 1]] =
914 /// // SAFETY: 1-element chunks never have remainder
915 /// unsafe { slice.as_chunks_unchecked_ext() };
916 /// assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]);
917 /// let chunks: &[[char; 3]] =
918 /// // SAFETY: The slice length (6) is a multiple of 3
919 /// unsafe { slice.as_chunks_unchecked_ext() };
920 /// assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]);
921 ///
922 /// // These would be unsound:
923 /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked_ext() // The slice length is not a multiple of 5
924 /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_ext() // Zero-length chunks are never allowed
925 /// ```
926 #[must_use]
927 unsafe fn as_chunks_unchecked_ext<const N: usize>(&self) -> &[[Self::T; N]];
928
929 /// Splits the slice into a slice of `N`-element arrays,
930 /// starting at the beginning of the slice,
931 /// and a remainder slice with length strictly less than `N`.
932 ///
933 /// # Panics
934 ///
935 /// Panics if `N` is 0. This check will most probably get changed to a compile time
936 /// error before this method gets stabilized.
937 ///
938 /// # Examples
939 ///
940 /// ```
941 /// use array_util::SliceExt;
942 ///
943 /// let v = &mut [0, 0, 0, 0, 0];
944 /// let mut count = 1;
945 ///
946 /// let (chunks, remainder) = v.as_chunks_mut_ext();
947 /// remainder[0] = 9;
948 /// for chunk in chunks {
949 /// *chunk = [count; 2];
950 /// count += 1;
951 /// }
952 /// assert_eq!(v, &[1, 1, 2, 2, 9]);
953 /// ```
954 #[must_use]
955 fn as_chunks_mut_ext<const N: usize>(&mut self) -> (&mut [[Self::T; N]], &mut [Self::T]);
956
957 /// Splits the slice into a slice of `N`-element arrays,
958 /// assuming that there's no remainder.
959 ///
960 /// # Safety
961 ///
962 /// This may only be called when
963 /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`).
964 /// - `N != 0`.
965 ///
966 /// # Examples
967 ///
968 /// ```
969 /// use array_util::SliceExt;
970 ///
971 /// let slice: &mut [char] = &mut ['l', 'o', 'r', 'e', 'm', '!'];
972 /// let chunks: &mut [[char; 1]] =
973 /// // SAFETY: 1-element chunks never have remainder
974 /// unsafe { slice.as_chunks_unchecked_mut_ext() };
975 /// chunks[0] = ['L'];
976 /// assert_eq!(chunks, &[['L'], ['o'], ['r'], ['e'], ['m'], ['!']]);
977 /// let chunks: &mut [[char; 3]] =
978 /// // SAFETY: The slice length (6) is a multiple of 3
979 /// unsafe { slice.as_chunks_unchecked_mut_ext() };
980 /// chunks[1] = ['a', 'x', '?'];
981 /// assert_eq!(slice, &['L', 'o', 'r', 'a', 'x', '?']);
982 ///
983 /// // These would be unsound:
984 /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked_mut_ext() // The slice length is not a multiple of 5
985 /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut_ext() // Zero-length chunks are never allowed
986 /// ```
987 #[must_use]
988 unsafe fn as_chunks_unchecked_mut_ext<const N: usize>(&mut self) -> &mut [[Self::T; N]];
989
990 /// Splits the slice into a slice of `N`-element arrays,
991 /// starting at the end of the slice,
992 /// and a remainder slice with length strictly less than `N`.
993 ///
994 /// # Panics
995 ///
996 /// Panics if `N` is 0. This check will most probably get changed to a compile time
997 /// error before this method gets stabilized.
998 ///
999 /// # Examples
1000 ///
1001 /// ```
1002 /// use array_util::SliceExt;
1003 ///
1004 /// let slice = ['l', 'o', 'r', 'e', 'm'];
1005 /// let (remainder, chunks) = slice.as_rchunks_ext();
1006 /// assert_eq!(remainder, &['l']);
1007 /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]);
1008 /// ```
1009 #[must_use]
1010
1011 fn as_rchunks_ext<const N: usize>(&self) -> (&[Self::T], &[[Self::T; N]]);
1012 /// Splits the slice into a slice of `N`-element arrays,
1013 /// starting at the end of the slice,
1014 /// and a remainder slice with length strictly less than `N`.
1015 ///
1016 /// # Panics
1017 ///
1018 /// Panics if `N` is 0. This check will most probably get changed to a compile time
1019 /// error before this method gets stabilized.
1020 ///
1021 /// # Examples
1022 ///
1023 /// ```
1024 /// use array_util::SliceExt;
1025 ///
1026 /// let v = &mut [0, 0, 0, 0, 0];
1027 /// let mut count = 1;
1028 ///
1029 /// let (remainder, chunks) = v.as_rchunks_mut_ext();
1030 /// remainder[0] = 9;
1031 /// for chunk in chunks {
1032 /// *chunk = [count; 2];
1033 /// count += 1;
1034 /// }
1035 /// assert_eq!(v, &[9, 1, 1, 2, 2]);
1036 /// ```
1037 #[must_use]
1038 fn as_rchunks_mut_ext<const N: usize>(&mut self) -> (&mut [Self::T], &mut [[Self::T; N]]);
1039}
1040
1041impl<T> SliceExt for [T] {
1042 type T = T;
1043
1044 /// Returns an iterator over `N` elements of the slice at a time, starting at the
1045 /// beginning of the slice.
1046 ///
1047 /// The chunks are array references and do not overlap. If `N` does not divide the
1048 /// length of the slice, then the last up to `N-1` elements will be omitted and can be
1049 /// retrieved from the `remainder` function of the iterator.
1050 ///
1051 /// This method is the const generic equivalent of [`chunks_exact`].
1052 ///
1053 /// # Panics
1054 ///
1055 /// Panics if `N` is 0. This check will most probably get changed to a compile time
1056 /// error before this method gets stabilized.
1057 ///
1058 /// # Examples
1059 ///
1060 /// ```
1061 /// use array_util::SliceExt;
1062 ///
1063 /// let slice = ['l', 'o', 'r', 'e', 'm'];
1064 /// let mut iter = slice.array_chunks_ext();
1065 /// assert_eq!(iter.next().unwrap(), &['l', 'o']);
1066 /// assert_eq!(iter.next().unwrap(), &['r', 'e']);
1067 /// assert!(iter.next().is_none());
1068 /// assert_eq!(iter.remainder(), &['m']);
1069 /// ```
1070 ///
1071 /// [`chunks_exact`]: prim@slice#method.chunks_exact
1072 #[inline]
1073 fn array_chunks_ext<const N: usize>(&self) -> ArrayChunks<'_, Self::T, N> {
1074 array_chunks(self)
1075 }
1076
1077 /// Returns an iterator over `N` elements of the slice at a time, starting at the
1078 /// beginning of the slice.
1079 ///
1080 /// The chunks are mutable array references and do not overlap. If `N` does not divide
1081 /// the length of the slice, then the last up to `N-1` elements will be omitted and
1082 /// can be retrieved from the `into_remainder` function of the iterator.
1083 ///
1084 /// This method is the const generic equivalent of [`chunks_exact_mut`].
1085 ///
1086 /// # Panics
1087 ///
1088 /// Panics if `N` is 0. This check will most probably get changed to a compile time
1089 /// error before this method gets stabilized.
1090 ///
1091 /// # Examples
1092 ///
1093 /// ```
1094 /// use array_util::SliceExt;
1095 ///
1096 /// let v = &mut [0, 0, 0, 0, 0];
1097 /// let mut count = 1;
1098 ///
1099 /// for chunk in v.array_chunks_mut_ext() {
1100 /// *chunk = [count; 2];
1101 /// count += 1;
1102 /// }
1103 /// assert_eq!(v, &[1, 1, 2, 2, 0]);
1104 /// ```
1105 ///
1106 /// [`chunks_exact_mut`]: prim@slice#method.chunks_exact_mut
1107 #[inline]
1108 fn array_chunks_mut_ext<const N: usize>(&mut self) -> ArrayChunksMut<'_, Self::T, N> {
1109 array_chunks_mut(self)
1110 }
1111
1112 /// Splits the slice into a slice of `N`-element arrays,
1113 /// starting at the beginning of the slice,
1114 /// and a remainder slice with length strictly less than `N`.
1115 ///
1116 /// # Panics
1117 ///
1118 /// Panics if `N` is 0. This check will most probably get changed to a compile time
1119 /// error before this method gets stabilized.
1120 ///
1121 /// # Examples
1122 ///
1123 /// ```
1124 /// use array_util::SliceExt;
1125 ///
1126 /// let slice = ['l', 'o', 'r', 'e', 'm'];
1127 /// let (chunks, remainder) = slice.as_chunks_ext();
1128 /// assert_eq!(chunks, &[['l', 'o'], ['r', 'e']]);
1129 /// assert_eq!(remainder, &['m']);
1130 /// ```
1131 ///
1132 /// If you expect the slice to be an exact multiple, you can combine
1133 /// `let`-`else` with an empty slice pattern:
1134 /// ```
1135 /// use array_util::SliceExt;
1136 ///
1137 /// let slice = ['R', 'u', 's', 't'];
1138 /// let (chunks, []) = slice.as_chunks_ext::<2>() else {
1139 /// panic!("slice didn't have even length")
1140 /// };
1141 /// assert_eq!(chunks, &[['R', 'u'], ['s', 't']]);
1142 /// ```
1143 #[inline]
1144 #[must_use]
1145 fn as_chunks_ext<const N: usize>(&self) -> (&[[Self::T; N]], &[Self::T]) {
1146 as_chunks(self)
1147 }
1148
1149 /// Splits the slice into a slice of `N`-element arrays,
1150 /// assuming that there's no remainder.
1151 ///
1152 /// # Safety
1153 ///
1154 /// This may only be called when
1155 /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`).
1156 /// - `N != 0`.
1157 ///
1158 /// # Examples
1159 ///
1160 /// ```
1161 /// use array_util::SliceExt;
1162 ///
1163 /// let slice: &[char] = &['l', 'o', 'r', 'e', 'm', '!'];
1164 /// let chunks: &[[char; 1]] =
1165 /// // SAFETY: 1-element chunks never have remainder
1166 /// unsafe { slice.as_chunks_unchecked_ext() };
1167 /// assert_eq!(chunks, &[['l'], ['o'], ['r'], ['e'], ['m'], ['!']]);
1168 /// let chunks: &[[char; 3]] =
1169 /// // SAFETY: The slice length (6) is a multiple of 3
1170 /// unsafe { slice.as_chunks_unchecked_ext() };
1171 /// assert_eq!(chunks, &[['l', 'o', 'r'], ['e', 'm', '!']]);
1172 ///
1173 /// // These would be unsound:
1174 /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked_ext() // The slice length is not a multiple of 5
1175 /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_ext() // Zero-length chunks are never allowed
1176 /// ```
1177 #[inline]
1178 #[must_use]
1179 unsafe fn as_chunks_unchecked_ext<const N: usize>(&self) -> &[[Self::T; N]] {
1180 as_chunks_unchecked(self)
1181 }
1182
1183 /// Splits the slice into a slice of `N`-element arrays,
1184 /// starting at the beginning of the slice,
1185 /// and a remainder slice with length strictly less than `N`.
1186 ///
1187 /// # Panics
1188 ///
1189 /// Panics if `N` is 0. This check will most probably get changed to a compile time
1190 /// error before this method gets stabilized.
1191 ///
1192 /// # Examples
1193 ///
1194 /// ```
1195 /// use array_util::SliceExt;
1196 ///
1197 /// let v = &mut [0, 0, 0, 0, 0];
1198 /// let mut count = 1;
1199 ///
1200 /// let (chunks, remainder) = v.as_chunks_mut_ext();
1201 /// remainder[0] = 9;
1202 /// for chunk in chunks {
1203 /// *chunk = [count; 2];
1204 /// count += 1;
1205 /// }
1206 /// assert_eq!(v, &[1, 1, 2, 2, 9]);
1207 /// ```
1208 #[inline]
1209 #[must_use]
1210 fn as_chunks_mut_ext<const N: usize>(&mut self) -> (&mut [[Self::T; N]], &mut [Self::T]) {
1211 as_chunks_mut(self)
1212 }
1213
1214 /// Splits the slice into a slice of `N`-element arrays,
1215 /// assuming that there's no remainder.
1216 ///
1217 /// # Safety
1218 ///
1219 /// This may only be called when
1220 /// - The slice splits exactly into `N`-element chunks (aka `self.len() % N == 0`).
1221 /// - `N != 0`.
1222 ///
1223 /// # Examples
1224 ///
1225 /// ```
1226 /// use array_util::SliceExt;
1227 ///
1228 /// let slice: &mut [char] = &mut ['l', 'o', 'r', 'e', 'm', '!'];
1229 /// let chunks: &mut [[char; 1]] =
1230 /// // SAFETY: 1-element chunks never have remainder
1231 /// unsafe { slice.as_chunks_unchecked_mut_ext() };
1232 /// chunks[0] = ['L'];
1233 /// assert_eq!(chunks, &[['L'], ['o'], ['r'], ['e'], ['m'], ['!']]);
1234 /// let chunks: &mut [[char; 3]] =
1235 /// // SAFETY: The slice length (6) is a multiple of 3
1236 /// unsafe { slice.as_chunks_unchecked_mut_ext() };
1237 /// chunks[1] = ['a', 'x', '?'];
1238 /// assert_eq!(slice, &['L', 'o', 'r', 'a', 'x', '?']);
1239 ///
1240 /// // These would be unsound:
1241 /// // let chunks: &[[_; 5]] = slice.as_chunks_unchecked_mut_ext() // The slice length is not a multiple of 5
1242 /// // let chunks: &[[_; 0]] = slice.as_chunks_unchecked_mut_ext() // Zero-length chunks are never allowed
1243 /// ```
1244 #[inline]
1245 #[must_use]
1246 unsafe fn as_chunks_unchecked_mut_ext<const N: usize>(&mut self) -> &mut [[Self::T; N]] {
1247 as_chunks_unchecked_mut(self)
1248 }
1249
1250 /// Splits the slice into a slice of `N`-element arrays,
1251 /// starting at the end of the slice,
1252 /// and a remainder slice with length strictly less than `N`.
1253 ///
1254 /// # Panics
1255 ///
1256 /// Panics if `N` is 0. This check will most probably get changed to a compile time
1257 /// error before this method gets stabilized.
1258 ///
1259 /// # Examples
1260 ///
1261 /// ```
1262 /// use array_util::SliceExt;
1263 ///
1264 /// let slice = ['l', 'o', 'r', 'e', 'm'];
1265 /// let (remainder, chunks) = slice.as_rchunks_ext();
1266 /// assert_eq!(remainder, &['l']);
1267 /// assert_eq!(chunks, &[['o', 'r'], ['e', 'm']]);
1268 /// ```
1269 #[inline]
1270 #[must_use]
1271 fn as_rchunks_ext<const N: usize>(&self) -> (&[Self::T], &[[Self::T; N]]) {
1272 as_rchunks(self)
1273 }
1274
1275 /// Splits the slice into a slice of `N`-element arrays,
1276 /// starting at the end of the slice,
1277 /// and a remainder slice with length strictly less than `N`.
1278 ///
1279 /// # Panics
1280 ///
1281 /// Panics if `N` is 0. This check will most probably get changed to a compile time
1282 /// error before this method gets stabilized.
1283 ///
1284 /// # Examples
1285 ///
1286 /// ```
1287 /// use array_util::SliceExt;
1288 ///
1289 /// let v = &mut [0, 0, 0, 0, 0];
1290 /// let mut count = 1;
1291 ///
1292 /// let (remainder, chunks) = v.as_rchunks_mut_ext();
1293 /// remainder[0] = 9;
1294 /// for chunk in chunks {
1295 /// *chunk = [count; 2];
1296 /// count += 1;
1297 /// }
1298 /// assert_eq!(v, &[9, 1, 1, 2, 2]);
1299 /// ```
1300 #[inline]
1301 #[must_use]
1302 fn as_rchunks_mut_ext<const N: usize>(&mut self) -> (&mut [Self::T], &mut [[Self::T; N]]) {
1303 as_rchunks_mut(self)
1304 }
1305}
1306
1307/// A helper extension trait for slices of arrays
1308pub trait SliceOfArrayExt {
1309 #[doc(hidden)]
1310 type T;
1311
1312 /// Takes a `&[[T; N]]`, and flattens it to a `&[T]`.
1313 ///
1314 /// # Panics
1315 ///
1316 /// This panics if the length of the resulting slice would overflow a `usize`.
1317 ///
1318 /// This is only possible when flattening a slice of arrays of zero-sized
1319 /// types, and thus tends to be irrelevant in practice. If
1320 /// `size_of::<T>() > 0`, this will never panic.
1321 ///
1322 /// # Examples
1323 ///
1324 /// ```
1325 /// use array_util::SliceOfArrayExt;
1326 ///
1327 /// assert_eq!([[1, 2, 3], [4, 5, 6]].flatten_ext(), &[1, 2, 3, 4, 5, 6]);
1328 ///
1329 /// assert_eq!(
1330 /// [[1, 2, 3], [4, 5, 6]].flatten_ext(),
1331 /// [[1, 2], [3, 4], [5, 6]].flatten_ext(),
1332 /// );
1333 ///
1334 /// let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []];
1335 /// assert!(slice_of_empty_arrays.flatten_ext().is_empty());
1336 ///
1337 /// let empty_slice_of_arrays: &[[u32; 10]] = &[];
1338 /// assert!(empty_slice_of_arrays.flatten_ext().is_empty());
1339 /// ```
1340 fn flatten_ext(&self) -> &[Self::T];
1341
1342 /// Takes a `&mut [[T; N]]`, and flattens it to a `&mut [T]`.
1343 ///
1344 /// # Panics
1345 ///
1346 /// This panics if the length of the resulting slice would overflow a `usize`.
1347 ///
1348 /// This is only possible when flattening a slice of arrays of zero-sized
1349 /// types, and thus tends to be irrelevant in practice. If
1350 /// `size_of::<T>() > 0`, this will never panic.
1351 ///
1352 /// # Examples
1353 ///
1354 /// ```
1355 /// use array_util::SliceOfArrayExt;
1356 ///
1357 /// fn add_5_to_all(slice: &mut [i32]) {
1358 /// for i in slice {
1359 /// *i += 5;
1360 /// }
1361 /// }
1362 ///
1363 /// let mut array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
1364 /// add_5_to_all(array.flatten_mut_ext());
1365 /// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]);
1366 /// ```
1367 fn flatten_mut_ext(&mut self) -> &mut [Self::T];
1368}
1369
1370impl<T, const N: usize> SliceOfArrayExt for [[T; N]] {
1371 type T = T;
1372
1373 /// Takes a `&[[T; N]]`, and flattens it to a `&[T]`.
1374 ///
1375 /// # Panics
1376 ///
1377 /// This panics if the length of the resulting slice would overflow a `usize`.
1378 ///
1379 /// This is only possible when flattening a slice of arrays of zero-sized
1380 /// types, and thus tends to be irrelevant in practice. If
1381 /// `size_of::<T>() > 0`, this will never panic.
1382 ///
1383 /// # Examples
1384 ///
1385 /// ```
1386 /// use array_util::SliceOfArrayExt;
1387 ///
1388 /// assert_eq!([[1, 2, 3], [4, 5, 6]].flatten_ext(), &[1, 2, 3, 4, 5, 6]);
1389 ///
1390 /// assert_eq!(
1391 /// [[1, 2, 3], [4, 5, 6]].flatten_ext(),
1392 /// [[1, 2], [3, 4], [5, 6]].flatten_ext(),
1393 /// );
1394 ///
1395 /// let slice_of_empty_arrays: &[[i32; 0]] = &[[], [], [], [], []];
1396 /// assert!(slice_of_empty_arrays.flatten_ext().is_empty());
1397 ///
1398 /// let empty_slice_of_arrays: &[[u32; 10]] = &[];
1399 /// assert!(empty_slice_of_arrays.flatten_ext().is_empty());
1400 /// ```
1401 fn flatten_ext(&self) -> &[Self::T] {
1402 flatten(self)
1403 }
1404
1405 /// Takes a `&mut [[T; N]]`, and flattens it to a `&mut [T]`.
1406 ///
1407 /// # Panics
1408 ///
1409 /// This panics if the length of the resulting slice would overflow a `usize`.
1410 ///
1411 /// This is only possible when flattening a slice of arrays of zero-sized
1412 /// types, and thus tends to be irrelevant in practice. If
1413 /// `size_of::<T>() > 0`, this will never panic.
1414 ///
1415 /// # Examples
1416 ///
1417 /// ```
1418 /// use array_util::SliceOfArrayExt;
1419 ///
1420 /// fn add_5_to_all(slice: &mut [i32]) {
1421 /// for i in slice {
1422 /// *i += 5;
1423 /// }
1424 /// }
1425 ///
1426 /// let mut array = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
1427 /// add_5_to_all(array.flatten_mut_ext());
1428 /// assert_eq!(array, [[6, 7, 8], [9, 10, 11], [12, 13, 14]]);
1429 /// ```
1430 fn flatten_mut_ext(&mut self) -> &mut [Self::T] {
1431 flatten_mut(self)
1432 }
1433}