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::*;