konst/iter.rs
1//! Const equivalent of iterators with a specific `next` function signature.
2//!
3//! The docs for [`IntoIterKind`] has more information on
4//! const equivalents of IntoIterator and Iterator.
5//!
6
7#[cfg(any(not(doctest), feature = "rust_1_56"))]
8pub mod iterator_dsl;
9
10/// Iterates over all elements of an [iterator](crate::iter#iterator),
11/// const equivalent of [`Iterator::for_each`]
12///
13/// # Iterator methods
14///
15/// This macro supports emulating iterator methods by expanding to equivalent code.
16///
17/// The supported iterator methods are documented in the [`iterator_dsl`] module,
18/// because they are also supported by other `konst::iter` macros.
19///
20/// # Examples
21///
22/// ### Custom iterator
23///
24/// ```rust
25/// use konst::iter::{IntoIterKind, IsIteratorKind};
26///
27/// struct Upto10(u8);
28///
29/// impl IntoIterKind for Upto10 { type Kind = IsIteratorKind; }
30///
31/// impl Upto10 {
32/// const fn next(mut self) -> Option<(u8, Self)> {
33/// if self.0 < 10 {
34/// let ret = self.0;
35/// self.0 += 1;
36/// Some((ret, self))
37/// } else {
38/// None
39/// }
40/// }
41/// }
42///
43/// const N: u32 = {
44/// let mut n = 0u32;
45/// konst::iter::for_each!{elem in Upto10(7) =>
46/// n = n * 10 + elem as u32;
47/// }
48/// n
49/// };
50///
51/// assert_eq!(N, 789);
52///
53/// ```
54///
55/// ### Summing pairs
56///
57/// This example requires the `"rust_1_51"` feature, because it uses const generics.
58///
59#[cfg_attr(feature = "rust_1_51", doc = "```rust")]
60#[cfg_attr(not(feature = "rust_1_51"), doc = "```ignore")]
61/// use konst::iter::for_each;
62///
63/// const fn add_pairs<const N: usize>(l: [u32; N], r: [u32; N]) -> [u32; N] {
64/// let mut out = [0u32; N];
65///
66/// for_each!{(i, val) in &l,zip(&r),map(|(l, r)| *l + *r),enumerate() =>
67/// out[i] = val;
68/// }
69///
70/// out
71/// }
72///
73/// assert_eq!(add_pairs([], []), []);
74/// assert_eq!(add_pairs([3], [5]), [8]);
75/// assert_eq!(add_pairs([3, 5], [8, 13]), [11, 18]);
76///
77/// ```
78///
79/// [`iterator_dsl`]: crate::iter::iterator_dsl
80pub use konst_macro_rules::for_each;
81
82/// Wrapper for `IntoIterKind` implementors,
83/// that defines different methods depending on the
84/// value of `<T as IntoIterKind>::Kind`.
85#[doc(inline)]
86pub use konst_macro_rules::into_iter::IntoIterWrapper;
87
88/// Marker type for proving that `T: IntoIterKind<Kind = K>`
89#[doc(inline)]
90pub use konst_macro_rules::into_iter::IsIntoIterKind;
91
92/// Macro for converting [`IntoIterKind`] implementors into const iterators.
93///
94#[doc(inline)]
95pub use konst_macro_rules::into_iter_macro as into_iter;
96
97/// Const analog of the [`IntoIterator`] trait.
98///
99/// # Implementor
100///
101/// Implementors are expected to be:
102///
103/// - [Types that have an associated iterator](#isnoniteratorkind),
104/// that have [`IsNonIteratorKind`](crate::iter::IsNonIteratorKind)
105/// as the [`IntoIterKind::Kind`] associated type.
106///
107/// - [Iterators themselves](#isiteratorkind),
108/// that have [`IsIteratorKind`](crate::iter::IsIteratorKind)
109/// as the [`IntoIterKind::Kind`] associated type.
110///
111/// - Standard library types, of the [`IsStdKind`] kind
112///
113/// ### `IsNonIteratorKind`
114///
115/// These types are expected to define this inherent method for converting to
116/// a const iterator:
117///
118/// ```rust
119/// # struct II;
120/// # struct SomeIterator;
121/// # impl II {
122/// const fn const_into_iter(self) -> SomeIterator {
123/// # loop{}
124/// # }
125/// # }
126/// ```
127///
128/// [full example below](#non-iter-example)
129///
130/// ### `IsIteratorKind`
131///
132/// These types are expected to have this inherent method:
133///
134/// ```rust
135/// # struct SomeIterator;
136/// # type Item = u8;
137/// # impl SomeIterator {
138/// // Equivalent to `Iterator::next`
139/// const fn next(self) -> Option<(Item, Self)> {
140/// # loop{}
141/// # }
142/// # }
143/// ```
144/// Where `Item` can be any type.
145///
146/// These are other methods that you can optionaly define,
147/// which most iterators from the `konst` crate define:
148/// ```rust
149/// # struct SomeIterator;
150/// # struct SomeIteratorRev;
151/// # type Item = u8;
152/// # impl SomeIterator {
153/// // equivalent to `DoubleEndedÃŒterator::mext_back`
154/// const fn next_back(self) -> Option<(Item, Self)> {
155/// # loop{}
156/// // ... some code...
157/// }
158///
159/// // Reverses the itereator, equivalent to `Iterator::rev`
160/// const fn rev(self) -> SomeIteratorRev {
161/// # loop{}
162/// // ... some code...
163/// }
164///
165/// // Clones the iterator, equivalent to `Clone::clone`
166/// const fn copy(&self) -> Self {
167/// # loop{}
168/// // ... some code...
169/// }
170/// # }
171/// ```
172/// Where `SomeIteratorRev` should be a `IntoIterKind<Kind = IsIteratorKind>`
173/// which has the same inherent methods for iteration.
174///
175/// [full example below](#iter-example)
176///
177/// # Examples
178///
179/// <span id = "non-iter-example"></span>
180/// ### Implementing for a non-iterator
181///
182/// ```rust
183/// use konst::{iter, slice};
184///
185/// struct GetSlice<'a, T>{
186/// slice: &'a [T],
187/// up_to: usize,
188/// }
189///
190/// impl<T> iter::IntoIterKind for GetSlice<'_, T> {
191/// type Kind = iter::IsNonIteratorKind;
192/// }
193///
194/// impl<'a, T> GetSlice<'a, T> {
195/// const fn const_into_iter(self) -> konst::slice::Iter<'a, T> {
196/// slice::iter(slice::slice_up_to(self.slice, self.up_to))
197/// }
198/// }
199///
200/// const fn sum_powers(up_to: usize) -> u64 {
201/// let gs = GetSlice{slice: &[1, 2, 4, 8, 16, 32, 64, 128], up_to};
202///
203/// iter::eval!(gs,fold(0, |l, &r| l + r))
204/// }
205///
206/// assert_eq!(sum_powers(0), 0);
207/// assert_eq!(sum_powers(1), 1);
208/// assert_eq!(sum_powers(2), 3);
209/// assert_eq!(sum_powers(3), 7);
210/// assert_eq!(sum_powers(4), 15);
211/// assert_eq!(sum_powers(5), 31);
212///
213/// ```
214///
215/// <span id = "iter-example"></span>
216/// ### Implementing for an iterator
217///
218/// This example requires Rust 1.47.0 (because of `u8::checked_sub`)
219///
220#[cfg_attr(feature = "rust_1_51", doc = "```rust")]
221#[cfg_attr(not(feature = "rust_1_51"), doc = "```ignore")]
222/// use konst::iter::{self, IntoIterKind};
223///
224/// struct Countdown(u8);
225///
226/// impl IntoIterKind for Countdown { type Kind = iter::IsIteratorKind; }
227///
228/// impl Countdown {
229/// const fn next(mut self) -> Option<(u8, Self)> {
230/// konst::option::map!(self.0.checked_sub(1), |ret| {
231/// self.0 = ret;
232/// (ret, self)
233/// })
234/// }
235/// }
236///
237/// const fn sum(initial: u8) -> u16 {
238/// iter::eval!(Countdown(initial),fold(0u16, |accum, elem| accum + elem as u16))
239/// }
240///
241/// assert_eq!(sum(0), 0);
242/// assert_eq!(sum(1), 0);
243/// assert_eq!(sum(2), 1);
244/// assert_eq!(sum(3), 3);
245/// assert_eq!(sum(4), 6);
246/// assert_eq!(sum(5), 10);
247///
248/// ```
249///
250/// ### Implementing for a double-ended iterator
251///
252/// ```rust
253/// use konst::iter;
254///
255/// assert_eq!(HOURS, [1, 2, 3, 4, 5, 6, 12, 11, 10, 9, 8, 7]);
256///
257/// const HOURS: [u8; 12] = {
258/// let mut arr = [0; 12];
259/// let hours = Hours::new();
260///
261/// iter::for_each!{(i, hour) in 0..6,zip(hours.copy()) =>
262/// arr[i] = hour;
263/// }
264/// iter::for_each!{(i, hour) in 6..12,zip(hours.rev()) =>
265/// arr[i] = hour;
266/// }
267///
268/// arr
269/// };
270///
271///
272/// struct Hours{
273/// start: u8,
274/// end: u8,
275/// }
276///
277/// impl iter::IntoIterKind for Hours {
278/// type Kind = iter::IsIteratorKind;
279/// }
280///
281/// impl Hours {
282/// const fn new() -> Self {
283/// Self {start: 1, end: 13}
284/// }
285///
286/// const fn next(mut self) -> Option<(u8, Self)> {
287/// if self.start == self.end {
288/// None
289/// } else {
290/// let ret = self.start;
291/// self.start += 1;
292/// Some((ret, self))
293/// }
294/// }
295///
296/// const fn next_back(mut self) -> Option<(u8, Self)> {
297/// if self.start == self.end {
298/// None
299/// } else {
300/// self.end -= 1;
301/// Some((self.end, self))
302/// }
303/// }
304///
305/// const fn rev(self) -> HoursRev {
306/// HoursRev(self)
307/// }
308///
309/// /// Since `Clone::clone` isn't const callable on stable,
310/// /// clonable iterators must define an inherent method to be cloned
311/// const fn copy(&self) -> Self {
312/// let Self{start, end} = *self;
313/// Self{start, end}
314/// }
315/// }
316///
317/// struct HoursRev(Hours);
318///
319/// impl iter::IntoIterKind for HoursRev {
320/// type Kind = iter::IsIteratorKind;
321/// }
322///
323/// impl HoursRev {
324/// const fn next(self) -> Option<(u8, Self)> {
325/// konst::option::map!(self.0.next_back(), |(a, h)| (a, HoursRev(h)))
326/// }
327///
328/// const fn next_back(self) -> Option<(u8, Self)> {
329/// konst::option::map!(self.0.next(), |(a, h)| (a, HoursRev(h)))
330/// }
331///
332/// const fn rev(self) -> Hours {
333/// self.0
334/// }
335///
336/// const fn copy(&self) -> Self {
337/// Self(self.0.copy())
338/// }
339/// }
340///
341///
342/// ```
343///
344#[doc(inline)]
345pub use konst_macro_rules::into_iter::IntoIterKind;
346
347/// For marking some type as being from std
348/// in its [`IntoIterKind::Kind`] associated type.
349#[doc(inline)]
350pub use konst_macro_rules::into_iter::IsStdKind;
351
352/// For marking some type as being convertible to an iterator
353/// in its [`IntoIterKind::Kind`] associated type.
354#[doc(inline)]
355pub use konst_macro_rules::into_iter::IsNonIteratorKind;
356
357/// For marking some type as being an iterator
358/// in its [`IntoIterKind::Kind`] associated type.
359#[doc(inline)]
360pub use konst_macro_rules::into_iter::IsIteratorKind;
361
362include! {"./iter/collect_const.rs"}
363include! {"./iter/iter_eval.rs"}