gat_lending_iterator/lib.rs
1//! This crate uses generic associated types to supply an iterator trait
2//! that allows the items to \[mutably\] borrow from the iterator.
3//! See [the GAT anouncement](https://blog.rust-lang.org/2022/10/28/gats-stabilization.html)
4//!
5//! Most `Iterator` methods can work as is on `LendingIterator`s, but some wouldn't make sense.
6//! Basically any method that needs to look at more than one element at once isn't possible, or needs to be modified.
7//!
8//! Some `LendingIterator` methods *may* return something that can act as an `Iterator`.
9//! For example `cloned`, or `map`, when the function passed to it
10//! returns a value that isn't tied to the lifetime of its input.
11//! In these cases, my design choice was to conditionally implement `IntoIterator` for the adapter.
12//!
13//! This crate also provides an extension trait `ToLendingIterator: Iterator` for iterators
14//! that allows turning them into lending iterators (over windows of elements).
15//! There may be more methods added to this trait in the future.
16//!
17//! # Examples
18//!
19//! Using [`windows`](crate::ToLendingIterator::windows) on a range, filtering it and chaining it:
20//! ```
21//! use gat_lending_iterator::{LendingIterator, ToLendingIterator};
22//!
23//! (0..5)
24//! .windows(3)
25//! .filter(|x| x[0] % 2 == 0)
26//! .chain((0..6).windows(2))
27//! .for_each(|x| println!("{x:?}"));
28//! ```
29//!
30//! Prints:
31//! ```ignore
32//! [0, 1, 2]
33//! [2, 3, 4]
34//! [0, 1]
35//! [1, 2]
36//! [2, 3]
37//! [3, 4]
38//! [4, 5]
39//! ```
40//!
41//! Using [`windows_mut`](crate::ToLendingIterator::windows_mut) on a range, mutating it and mapping it:
42//! ```
43//! use gat_lending_iterator::{LendingIterator, ToLendingIterator};
44//!
45//! for sum in (0..7).windows_mut(2).map(|slice: &mut [usize]| {
46//! slice[1] += slice[0];
47//! slice[1]
48//! }) {
49//! println!("{sum}");
50//! }
51//! ```
52//!
53//! Prints:
54//! ```ignore
55//! 1
56//! 3
57//! 6
58//! 10
59//! 15
60//! 21
61//! ```
62//!
63//! Using [`windows`](crate::ToLendingIterator::windows) on a range, and mapping it:
64//! ```
65//! use gat_lending_iterator::{LendingIterator, ToLendingIterator};
66//! fn second(slice: &[usize]) -> &usize {
67//! &slice[1]
68//! }
69//!
70//! for n in (0..5).windows(3).map(second).cloned() {
71//! println!("{n}");
72//! }
73//! ```
74//!
75//! Prints:
76//! ```ignore
77//! 1
78//! 2
79//! 3
80//! ```
81
82#![deny(missing_docs)]
83#![warn(clippy::pedantic)]
84
85mod adapters;
86mod to_lending;
87mod traits;
88pub use self::adapters::*;
89pub use self::to_lending::*;
90pub use self::traits::*;
91
92#[cfg(test)]
93mod tests {
94 use super::*;
95
96 fn second(slice: &[usize]) -> &usize {
97 &slice[1]
98 }
99
100 #[test]
101 fn playground() {
102 (0..5)
103 .windows(3)
104 .filter(|x| x[0] % 2 == 0)
105 .chain((0..6).windows(2))
106 .for_each(|x| println!("{x:?}"));
107
108 println!();
109
110 for sum in (0..7).windows_mut(2).map(|slice: &mut [usize]| {
111 slice[1] += slice[0];
112 slice[1]
113 }) {
114 println!("{sum}");
115 }
116
117 println!();
118
119 for n in (0..5).windows(3).map(second).cloned() {
120 println!("{n}");
121 }
122
123 println!();
124
125 (0..5)
126 .windows(4)
127 .zip([0, 1].into_lending())
128 .for_each(|(a, b)| {
129 println!("{a:?}, {b:?}");
130 });
131
132 (0..5)
133 .windows(2)
134 .skip_while(|w| w[0] < 2)
135 .fold(0, |acc, x| acc + x[1]);
136 }
137}