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}