konst/slice/
slice_iter_methods.rs

1use crate::{
2    iter::{IntoIterKind, IsIteratorKind},
3    option, slice,
4};
5
6use konst_macro_rules::iterator_shared;
7
8/// Gets a const iterator over `slice`, const equivalent of
9/// [`<[T]>::iter`
10/// ](https://doc.rust-lang.org/std/primitive.slice.html#method.iter)
11///
12/// # Example
13///
14/// ### Normal
15///
16/// ```rust
17/// use konst::iter::for_each;
18/// use konst::slice;
19///
20/// const ARR: &[usize] = &{
21///     let mut arr = [0usize; 3];
22///     // the `slice::iter` call here is unnecessary,
23///     // you can pass a slice reference to `for_each*`
24///     for_each!{(i, elem) in slice::iter(&["foo", "hello", "That box"]), enumerate() =>
25///         arr[i] = elem.len();
26///     }
27///     arr
28/// };
29///
30/// assert_eq!(ARR, [3, 5, 8]);
31///
32/// ```
33///
34/// ### Reversed
35///
36/// ```rust
37/// use konst::iter::for_each;
38/// use konst::slice;
39///
40/// const ARR: &[usize] = &{
41///     let mut arr = [0usize; 3];
42///     for_each!{(i, elem) in slice::iter(&["foo", "hello", "That box"]).rev(),enumerate() =>
43///         arr[i] = elem.len();
44///     }
45///     arr
46/// };
47///
48/// assert_eq!(ARR, [8, 5, 3]);
49///
50/// ```
51pub use konst_macro_rules::into_iter::slice_into_iter::iter;
52
53/// Const equivalent of [`core::slice::Iter`].
54///
55/// This is constructed in either of these ways:
56/// ```rust
57/// # let a_slice = &[3];
58/// # let _ = (
59/// konst::slice::iter(a_slice)
60/// # ,
61/// konst::iter::into_iter!(a_slice)
62/// # );
63/// ```
64pub use konst_macro_rules::into_iter::slice_into_iter::Iter;
65
66/// Const equivalent of `core::iter::Rev<core::slice::Iter<_>>`
67///
68/// This is constructed in either of these ways:
69/// ```rust
70/// # let a_slice = &[3];
71/// # let _ = (
72/// konst::slice::iter(a_slice).rev()
73/// # ,
74/// konst::iter::into_iter!(a_slice).rev()
75/// # );
76/// ```
77pub use konst_macro_rules::into_iter::slice_into_iter::IterRev;
78
79/// A const equivalent of `slice.iter().copied()`
80///
81/// # Version compatibility
82///
83/// This requires the `"rust_1_61"` feature.
84///
85/// # Example
86///
87/// ```rust
88/// use konst::{iter, slice};
89///
90/// const fn find_even(slice: &[u32]) -> Option<u32> {
91///     iter::eval!(slice::iter_copied(slice),find(|elem| *elem % 2 == 0))
92/// }
93///
94/// assert_eq!(find_even(&[]), None);
95/// assert_eq!(find_even(&[1]), None);
96/// assert_eq!(find_even(&[1, 2]), Some(2));
97/// assert_eq!(find_even(&[5, 4, 3, 2, 1]), Some(4));
98///
99/// ```
100///
101#[cfg(feature = "rust_1_61")]
102#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_61")))]
103pub use konst_macro_rules::into_iter::slice_into_iter::iter_copied;
104
105/// A const equivalent of `iter::Copied<slice::Iter<'a, T>>`.
106///
107/// This const iterator can be created with [`iter_copied`].
108///
109/// # Version compatibility
110///
111/// This requires the `"rust_1_61"` feature.
112///
113#[cfg(feature = "rust_1_61")]
114#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_61")))]
115pub use konst_macro_rules::into_iter::slice_into_iter::IterCopied;
116
117/// A const equivalent of `iter::Rev<iter::Copied<slice::Iter<'a, T>>>`
118///
119/// This const iterator can be created with
120/// ```rust
121/// # let slice = &[3, 5, 8];
122/// # let _: konst::slice::IterCopiedRev<'_, u32> =
123/// konst::slice::iter_copied(slice).rev()
124/// # ;
125/// ```
126///
127/// # Version compatibility
128///
129/// This requires the `"rust_1_61"` feature.
130///
131/// # Example
132///
133/// ```rust
134/// use konst::iter;
135/// use konst::slice::{self, IterCopiedRev};
136///
137/// const fn rfind_even(slice: &[u32]) -> Option<u32> {
138///     let iter: IterCopiedRev<'_, u32> = slice::iter_copied(slice).rev();
139///     iter::eval!(iter,find(|&elem| elem % 2 == 0))
140/// }
141///
142/// assert_eq!(rfind_even(&[]), None);
143/// assert_eq!(rfind_even(&[1]), None);
144/// assert_eq!(rfind_even(&[1, 2]), Some(2));
145/// assert_eq!(rfind_even(&[1, 2, 3, 4, 5]), Some(4));
146///
147/// ```
148///
149#[cfg(feature = "rust_1_61")]
150#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_61")))]
151pub use konst_macro_rules::into_iter::slice_into_iter::IterCopiedRev;
152
153///////////////////////////////////////////////////////////////////////////////
154
155#[cfg(feature = "rust_1_64")]
156mod requires_rust_1_64 {
157    use super::*;
158
159    #[inline(always)]
160    pub(crate) const fn some_if_nonempty<T>(slice: &[T]) -> Option<&[T]> {
161        if let [] = slice {
162            None
163        } else {
164            Some(slice)
165        }
166    }
167
168    /// Const equivalent of
169    /// [`<[T]>::windows`
170    /// ](https://doc.rust-lang.org/std/primitive.slice.html#method.windows)
171    ///
172    /// # Example
173    ///
174    /// ```rust
175    /// use konst::{iter, slice};
176    ///
177    /// const fn is_sorted(slice: &[u8]) -> bool {
178    ///     iter::eval!(slice::windows(slice, 2),all(|w| w[1] > w[0]))
179    /// }
180    ///
181    /// assert!(is_sorted(&[3, 5, 8]));
182    /// assert!(!is_sorted(&[8, 13, 0]));
183    ///
184    ///
185    ///
186    /// ```
187    #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_64")))]
188    #[track_caller]
189    pub const fn windows<T>(slice: &[T], size: usize) -> Windows<'_, T> {
190        assert!(size != 0, "window size must be non-zero");
191
192        Windows { slice, size }
193    }
194
195    macro_rules! windows_shared {
196        (is_forward = $is_forward:ident) => {
197            iterator_shared! {
198                is_forward = $is_forward,
199                item = &'a [T],
200                iter_forward = Windows<'a, T>,
201                iter_reversed = WindowsRev<'a, T>,
202                next(self){
203                    if self.slice.len() < self.size {
204                        None
205                    } else {
206                        let up_to = slice::slice_up_to(self.slice, self.size);
207                        self.slice = slice::slice_from(self.slice, 1);
208                        Some((up_to, self))
209                    }
210                },
211                next_back {
212                    let len = self.slice.len();
213                    if len < self.size {
214                        None
215                    } else {
216                        let up_to = slice::slice_from(self.slice, len - self.size);
217                        self.slice = slice::slice_up_to(self.slice, len - 1);
218                        Some((up_to, self))
219                    }
220                },
221                fields = {slice, size},
222            }
223        };
224    }
225
226    /// Const equivalent of [`core::slice::Windows`]
227    ///
228    /// This is constructed with [`windows`] like this:
229    /// ```rust
230    /// # let slice = &[3];
231    /// # let _ =
232    /// konst::slice::windows(slice, 1)
233    /// # ;
234    /// ```
235    #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_64")))]
236    pub struct Windows<'a, T> {
237        slice: &'a [T],
238        size: usize,
239    }
240    impl<T> IntoIterKind for Windows<'_, T> {
241        type Kind = IsIteratorKind;
242    }
243
244    /// Const equivalent of `core::iter::Rev<core::slice::Windows>`
245    ///
246    /// This is constructed with [`windows`] like this:
247    /// ```rust
248    /// # let slice = &[3];
249    /// # let _ =
250    /// konst::slice::windows(slice, 1).rev()
251    /// # ;
252    /// ```
253    #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_64")))]
254    pub struct WindowsRev<'a, T> {
255        slice: &'a [T],
256        size: usize,
257    }
258    impl<T> IntoIterKind for WindowsRev<'_, T> {
259        type Kind = IsIteratorKind;
260    }
261
262    impl<'a, T> Windows<'a, T> {
263        windows_shared! {is_forward = true}
264    }
265
266    impl<'a, T> WindowsRev<'a, T> {
267        windows_shared! {is_forward = false}
268    }
269
270    ///////////////////////////////////////////////////////////////////////////
271    ///////////////////////////////////////////////////////////////////////////
272
273    /// Const equivalent of
274    /// [`<[T]>::chunks`](https://doc.rust-lang.org/std/primitive.slice.html#method.chunks)
275    ///
276    /// # Example
277    ///
278    /// ```rust
279    /// use konst::iter::for_each;
280    /// use konst::slice;
281    ///
282    /// const CHUNKS: &[&[u8]] = &{
283    ///     let mut out = [&[] as &[u8]; 3] ;
284    ///     let fibb = &[3, 5, 8, 13, 21, 34, 55, 89];
285    ///     for_each!{(i, chunk) in slice::chunks(fibb, 3),enumerate() =>
286    ///         out[i] = chunk;
287    ///     }
288    ///     out
289    /// };
290    ///
291    /// let expected: &[&[u8]] = &[&[3, 5, 8], &[13, 21, 34], &[55, 89]];
292    ///
293    /// assert_eq!(CHUNKS, expected)
294    ///
295    /// ```
296    ///
297    #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_64")))]
298    #[track_caller]
299    pub const fn chunks<T>(slice: &[T], size: usize) -> Chunks<'_, T> {
300        assert!(size != 0, "chunk size must be non-zero");
301
302        Chunks {
303            slice: some_if_nonempty(slice),
304            size,
305        }
306    }
307
308    macro_rules! chunks_shared {
309        (is_forward = $is_forward:ident) => {
310            iterator_shared! {
311                is_forward = $is_forward,
312                item = &'a [T],
313                iter_forward = Chunks<'a, T>,
314                iter_reversed = ChunksRev<'a, T>,
315                next(self) {
316                    option::map!(self.slice, |slice| {
317                        let (ret, next) = slice::split_at(slice, self.size);
318                        self.slice = some_if_nonempty(next);
319                        (ret, self)
320                    })
321                },
322                next_back{
323                    option::map!(self.slice, |slice| {
324                        let at = (slice.len() - 1) / self.size * self.size;
325                        let (next, ret) = slice::split_at(slice, at);
326                        self.slice = some_if_nonempty(next);
327                        (ret, self)
328                    })
329                },
330                fields = {slice, size},
331            }
332        };
333    }
334
335    /// Const equivalent of [`core::slice::Chunks`]
336    ///
337    /// This is constructed with [`chunks`] like this:
338    /// ```rust
339    /// # let slice = &[3];
340    /// # let _ =
341    /// konst::slice::chunks(slice, 1)
342    /// # ;
343    /// ```
344    #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_64")))]
345    pub struct Chunks<'a, T> {
346        slice: Option<&'a [T]>,
347        size: usize,
348    }
349    impl<T> IntoIterKind for Chunks<'_, T> {
350        type Kind = IsIteratorKind;
351    }
352
353    /// Const equivalent of `core::iter::Rev<core::slice::Chunks>`
354    ///
355    /// This is constructed with [`chunks`] like this:
356    /// ```rust
357    /// # let slice = &[3];
358    /// # let _ =
359    /// konst::slice::chunks(slice, 1).rev()
360    /// # ;
361    /// ```
362    #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_64")))]
363    pub struct ChunksRev<'a, T> {
364        slice: Option<&'a [T]>,
365        size: usize,
366    }
367    impl<T> IntoIterKind for ChunksRev<'_, T> {
368        type Kind = IsIteratorKind;
369    }
370
371    impl<'a, T> Chunks<'a, T> {
372        chunks_shared! {is_forward = true}
373    }
374
375    impl<'a, T> ChunksRev<'a, T> {
376        chunks_shared! {is_forward = false}
377    }
378
379    ///////////////////////////////////////////////////////////////////////////
380    ///////////////////////////////////////////////////////////////////////////
381
382    /// Const equivalent of
383    /// [`<[T]>::chunks_exact`
384    /// ](https://doc.rust-lang.org/std/primitive.slice.html#method.chunks_exact)
385    ///
386    /// # Example
387    ///
388    /// ```rust
389    /// use konst::{for_range, option, slice};
390    ///
391    /// const FOUND: [&[u8]; 3] = {
392    ///     let iter = slice::chunks_exact(&[3, 5, 8, 13, 21, 34, 55, 89], 3);
393    ///     let (elem0, iter) = option::unwrap!(iter.next());
394    ///     let (elem1, iter) = option::unwrap!(iter.next());
395    ///     [elem0, elem1, iter.remainder()]
396    /// };
397    ///
398    /// let expected: [&[u8]; 3] = [&[3u8, 5, 8], &[13, 21, 34], &[55, 89]];
399    ///
400    /// assert_eq!(FOUND, expected);
401    ///
402    /// ```
403    ///
404    #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_64")))]
405    #[track_caller]
406    pub const fn chunks_exact<T>(slice: &[T], size: usize) -> ChunksExact<'_, T> {
407        assert!(size != 0, "chunk size must be non-zero");
408
409        ChunksExact { slice, size }
410    }
411
412    macro_rules! chunks_exact_shared {
413        (is_forward = $is_forward:ident) => {
414            iterator_shared! {
415                is_forward = $is_forward,
416                item = &'a [T],
417                iter_forward = ChunksExact<'a, T>,
418                iter_reversed = ChunksExactRev<'a, T>,
419                next(self) {
420                    if self.slice.len() < self.size {
421                        None
422                    } else {
423                        let (ret, next) = slice::split_at(self.slice, self.size);
424                        self.slice = next;
425                        Some((ret, self))
426                    }
427                },
428                next_back {
429                    if let Some(mut at) = self.slice.len().checked_sub(self.size) {
430                        at = at / self.size * self.size;
431                        let (next, ret) = slice::split_at(self.slice, at);
432                        self.slice = next;
433                        Some((slice::slice_up_to(ret, self.size), self))
434                    } else {
435                        None
436                    }
437                },
438                fields = {slice, size},
439            }
440
441            /// Returns the remainder of the slice that not returned by [`next`](Self::next),
442            /// because it is shorter than the chunk size.
443            pub const fn remainder(&self) -> &'a [T] {
444                self.slice
445            }
446        };
447    }
448
449    /// Const equivalent of [`core::slice::ChunksExact`]
450    ///
451    /// This is constructed with [`chunks_exact`] like this:
452    /// ```rust
453    /// # let slice = &[3];
454    /// # let _ =
455    /// konst::slice::chunks_exact(slice, 1)
456    /// # ;
457    /// ```
458    #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_64")))]
459    pub struct ChunksExact<'a, T> {
460        slice: &'a [T],
461        size: usize,
462    }
463    impl<T> IntoIterKind for ChunksExact<'_, T> {
464        type Kind = IsIteratorKind;
465    }
466
467    /// Const equivalent of `core::iter::Rev<core::slice::ChunksExact>`
468    ///
469    /// This is constructed with [`chunks_exact`] like this:
470    /// ```rust
471    /// # let slice = &[3];
472    /// # let _ =
473    /// konst::slice::chunks_exact(slice, 1).rev()
474    /// # ;
475    /// ```
476    #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_64")))]
477    pub struct ChunksExactRev<'a, T> {
478        slice: &'a [T],
479        size: usize,
480    }
481    impl<T> IntoIterKind for ChunksExactRev<'_, T> {
482        type Kind = IsIteratorKind;
483    }
484
485    impl<'a, T> ChunksExact<'a, T> {
486        chunks_exact_shared! {is_forward = true}
487    }
488
489    impl<'a, T> ChunksExactRev<'a, T> {
490        chunks_exact_shared! {is_forward = false}
491    }
492}
493
494#[cfg(feature = "rust_1_64")]
495pub use requires_rust_1_64::*;