Iterator returning a reference to itself - iterator

I'm aware of Lifetime in Iterator impl, but I'd like some more detail to help me properly understand.
I want to write an infinite Iterator that returns &[0], &[0, 1], &[0, 1, 2], etc... . I'd like to write this:
struct Countings(Vec<usize>);
impl Countings {
fn new() -> Countings { Countings(vec![]) }
}
impl Iterator for Countings {
type Item = &[usize];
fn next(&mut self) -> Option<Self::Item> {
self.0.push(self.0.len());
Some(self.0.as_slice())
}
}
I can't because the type Countings::Item does not have a lifetime.
error[E0106]: missing lifetime specifier
--> src/lib.rs:8:17
|
8 | type Item = &[usize];
| ^ expected lifetime parameter
So I add one. It has to be bound by the impl Iterator. That, in turn, requires a lifetime parameter on struct Countings. So far, I'm here:
struct Countings<'a>(Vec<usize>);
impl<'a> Countings<'a> {
fn new() -> Countings<'a> { Countings(vec![]) }
}
impl<'a> Iterator for Countings<'a> {
type Item = &'a [usize];
fn next(&mut self) -> Option<Self::Item> {
self.0.push(self.0.len());
Some(self.0.as_slice())
}
}
Now I have a different error:
error[E0392]: parameter `'a` is never used
--> src/lib.rs:1:18
|
1 | struct Countings<'a>(Vec<usize>);
| ^^
|
= help: consider removing `'a` or using a marker such as `std::marker::PhantomData`
I seriously consider it:
use std::marker::PhantomData;
struct Countings<'a>(Vec<usize>, PhantomData<&'a [usize]>);
impl<'a> Countings<'a> {
fn new() -> Countings<'a> { Countings(vec![], PhantomData) }
}
impl<'a> Iterator for Countings<'a> {
type Item = &'a [usize];
fn next(&mut self) -> Option<Self::Item> {
self.0.push(self.0.len());
Some(self.0.as_slice())
}
}
but to no avail:
error[E0495]: cannot infer an appropriate lifetime for autoref due to conflicting requirements
--> src/lib.rs:14:25
|
14 | Some(self.0.as_slice())
| ^^^^^^^^
Question 1: What are the "conflicting requirements"?
Question 2: The answer cited above says that Item must borrow from something that the Iterator wraps. I have read the source for std::slice::Windows which is a good example. However, in my case I want to mutate the Vec each time next() is called. Is that possible?

Question 1: What are the "conflicting requirements"?
The borrow you try to return does not have lifetime 'a, as promised. Rather, it has the same lifetime as self. If the signature for next was written in full, it would be:
fn next<'b>(&'b mut self) -> Option<&'a [usize]>
Returning an Option<&'b [usize]> (with lifetime 'b instead of 'a) would be valid if it weren't for the fact that it violates the contract for the Iterator trait. However, it would freeze self until the result is dropped; i.e. you could not call next twice and use the result of both calls together. That's because each call to next can potentially invalidate the previously returned slices; pushing to a Vec can relocate the storage in memory to make room for additional elements, so the pointers in the slices would no longer be valid.
Question 2: The answer cited above says that Item must borrow from something that the Iterator wraps. I have read the source for std::slice::Windows which is a good example. However, in my case I want to mutate the Vec each time next() is called. Is that possible?
It's not possible to do this with the Iterator trait, so you won't be able to use a for loop on your struct. However, you can do it (with the caveat mentioned above) with an ordinary method.
struct Countings(Vec<usize>);
impl Countings {
fn new() -> Countings { Countings(vec![]) }
fn next<'a>(&'a mut self) -> &'a [usize] {
let item = self.0.len();
self.0.push(item);
self.0.as_slice()
}
}

As Francis mentioned, it is not possible to modify the underlying vector during iteration. However, if you were to somehow have the possibility to specify the iteration bound, then things would be much easier:
You would create the vector [0, 1, 2, ...]
And then create an iterator that returns an ever-growing slice, up to the length of the vector
Just the iterator:
struct EverGrowingIterator<'a, T: 'a> {
slice: &'a [T],
current: usize,
}
impl<'a, T> Iterator for EverGrowingIterator<'a, T> {
type Item = &'a [T];
fn next(&mut self) -> Option<&'a [T]> {
if self.current >= self.slice.len() {
None
} else {
self.current += 1;
Some(&self.slice[0..self.current])
}
}
}
And then:
fn ever_growing<'a, T>(slice: &'a [T]) -> EverGrowingIterator<'a, T> {
EverGrowingIterator { slice: slice, current: 0 }
}
fn main() {
let v = vec![0, 1, 2];
for s in ever_growing(&v) {
println!("{:?}", s);
}
}
Will print:
[0]
[0, 1]
[0, 1, 2]
If you need to adapt this for infinite growth, you need to look into creating a custom container (not a Vec) that will grow while preserving references to previous slices. Something like a RefCell<Vec<Box<[T]>>> could be used.

Related

Type mismatch resolving iterator Item to a pointer with an explicit lifetime

I'm trying to add functions to Iterator where the associated type Item is a reference to a struct with an explicit lifetime.
When I've wanted to modify the iterator state or return a new value I've had no problems, but when I attempt to return a new Iterator where Item is a reference with an explicit lifetime, the compiler complains.
Example
use std::marker::PhantomData;
/// First, an "Inner" struct to be contained in my custom iterator
pub struct Inner {
text: String,
}
/// Then, the "CustomIterator" in question. Notice that `Item` is `&'a Inner`.
pub struct CustomIterator<'a, I: Iterator<Item = &'a Inner>> {
iter: I,
_marker: PhantomData<&'a i8>,
}
/// Implementing Iterator for CustomIterator so as to define the `next()` function, as you do...
impl<'a, I: Iterator<Item = &'a Inner>> Iterator for CustomIterator<'a, I> {
type Item = &'a Inner;
fn next(&mut self) -> Option<Self::Item> {
println!("Custom next called");
self.iter.next()
}
}
/// Now, creating a custom trait definition called IterateMore that:
/// 1. inherits Iterator
/// 2. includes a default method called `more` which returns a `CustomIterator`
pub trait IterateMore<'a>: Iterator {
type Item;
fn more(self) -> CustomIterator<'a, Self>
where
Self: Sized;
}
/// Implementing `IterateMore` for an iterator of the specific type `Iterator<Item=&'a Inner>`
impl<'a, I: Iterator<Item = &'a Inner>> IterateMore<'a> for I
where
I: Iterator,
{
type Item = &'a Inner;
fn more(self) -> CustomIterator<'a, Self>
where
Self: Sized,
{
CustomIterator {
iter: self,
_marker: PhantomData,
}
}
}
fn main() {
let inner = Inner {
text: "Hello world".to_string(),
};
let inners = vec![&inner];
inners.iter().more().next();
}
(See it on repl.it)
Error
error[E0271]: type mismatch resolving `<Self as std::iter::Iterator>::Item == &'a Inner`
--> src/main.rs:28:5
|
28 | / fn more(self) -> CustomIterator<'a, Self>
29 | | where
30 | | Self: Sized;
| |____________________^ expected associated type, found reference
|
= note: expected type `<Self as std::iter::Iterator>::Item`
found type `&'a Inner`
= note: required by `CustomIterator`
Why is Item not being resolved here? It is a bit frustrating as the compiler also complains if I try to set &'a Inner as the default Item type in the trait definition, saying:
error: associated type defaults are unstable (see issue #29661)
How could this be fixed or done differently?
It is unclear to me why you'd want to restrict the wrapped iterator to some custom type (given that you still have to write down the restriction every time you use the type, although that might change). But perhaps your "real" next function does something funny.
PhantomData doesn't seem to be necessary (anymore) to "use" the lifetime when it is used in a where-clause.
IterateMore shouldn't have an Item associated type, given Iterator already has it. (If you'd really need a new type pick a different name)
As IterateMore uses the CustomIterator type it needs to repeat the requirements, in this case Iterator<Item = &'a Inner> (that is what the type mismatch error is about); this is not the same as saying type Item = &'a Inner in the trait definition.
Playground
/// an "Inner" struct to be contained in my custom iterator
pub struct Inner {
text: String,
}
pub struct CustomIterator<'a, I>
where
I: Iterator<Item = &'a Inner>,
{
iter: I,
}
impl<'a, I> Iterator for CustomIterator<'a, I>
where
I: Iterator<Item = &'a Inner>,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
println!("Custom next called");
self.iter.next()
}
}
pub trait IterateMore<'a>: Iterator<Item = &'a Inner> + Sized {
fn more(self) -> CustomIterator<'a, Self>;
}
impl<'a, I> IterateMore<'a> for I
where
I: Iterator<Item = &'a Inner>,
{
fn more(self) -> CustomIterator<'a, Self> {
CustomIterator { iter: self }
}
}
fn main() {
let inner = Inner {
text: "Hello world".to_string(),
};
let inners = vec![inner];
inners.iter().more().next();
}
You could also remove the type restrictions everywhere like this (and only add it back in the place you actually need/want it):
Playground
pub struct CustomIterator<I> {
iter: I,
}
impl<I> Iterator for CustomIterator<I>
where
I: Iterator,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
println!("Custom next called");
self.iter.next()
}
}
pub trait IterateMore: Iterator + Sized {
fn more(self) -> CustomIterator<Self>;
}
impl<I> IterateMore for I
where
I: Iterator,
{
fn more(self) -> CustomIterator<Self>
{
CustomIterator { iter: self }
}
}
fn main() {
let inners = vec!["Hello world".to_string()];
inners.iter().more().next();
}

Wrong number of lifetime parameters when using a modified `Chars` iterator

I want to implement the IntoIterator trait for a struct containing a String. The iterator is based on the chars() iterator, is supposed to count the '1' chars and accumulate the result. This is a simplified version of what I got so far:
use std::iter::Map;
use std::str::Chars;
fn main() {
let str_struct = StringStruct { system_string: String::from("1101") };
for a in str_struct {
println!("{}", a);
}
}
struct StringStruct {
system_string: String
}
impl IntoIterator for StringStruct {
type Item = u32;
type IntoIter = Map<Chars, Fn(char) -> u32>;
fn into_iter(self) -> Self::IntoIter {
let count = 0;
return self.system_string.chars().map(|c| match c {
Some('1') => {
count += 1;
return Some(count);
},
Some(chr) => return Some(count),
None => return None
});
}
}
Expected output: 1, 2, 2, 3
This fails with:
error[E0107]: wrong number of lifetime parameters: expected 1, found 0
--> src/main.rs:17:25
|
17 | type IntoIter = Map<Chars, Fn(char) -> u32>;
| ^^^^^ expected 1 lifetime parameter
The chars iterator should have the same lifetime as the StringStruct::system_string, but I have no idea how to express this or if this approach is viable at all.
To answer the question you asked, I'd recommend to impl IntoIterator for &StringStruct (a reference to a StringStruct instead of the struct directly). The code would look like this:
impl<'a> IntoIterator for &'a StringStruct {
type Item = u32;
type IntoIter = Map<Chars<'a>, Fn(char) -> u32>;
// ...
}
However, you will notice many more errors that have a different origin afterwards. The next error that pops up is that Fn(char) -> u32 does not have a constant size at compile time.
The problem is that you try to name the type of your closure by writing Fn(char) -> u32. But this is not the type of your closure, but merely a trait which is implemented by the closure. The type of a closure can't be named (sometimes called "Voldemort type").
This means that, right now, you can't specify the type of a Map<_, _> object. This is a known issue; the recently accepted impl Trait-RFC might offer a workaround for cases like this. But right now, it's not possible, sorry.
So how to solve it then? You need to create your own type that implements Iterator and use it instead of Map<_, _>. Note that you can still use the Chars iterator. Here is the full solution:
struct StringStructIter<'a> {
chars: Chars<'a>,
count: u32,
}
impl<'a> Iterator for StringStructIter<'a> {
type Item = u32;
fn next(&mut self) -> Option<Self::Item> {
self.chars.next().map(|c| {
if c == '1' {
self.count += 1;
}
self.count
})
}
}
impl<'a> IntoIterator for &'a StringStruct {
type Item = u32;
type IntoIter = StringStructIter<'a>;
fn into_iter(self) -> Self::IntoIter {
StringStructIter {
chars: self.system_string.chars(),
count: 0,
}
}
}
fn main() {
let str_struct = StringStruct { system_string: String::from("1101") };
for a in &str_struct {
println!("{}", a);
}
}
And just a small note: an explicit return when not necessary is considered bad style in Rust. Better stick to rule and write idiomatic code by removing return whenever possible ;-)

How do I write an iterator that returns references to itself?

I am having trouble expressing the lifetime of the return value of an Iterator implementation. How can I compile this code without changing the return value of the iterator? I'd like it to return a vector of references.
It is obvious that I am not using the lifetime parameter correctly but after trying various ways I just gave up, I have no idea what to do with it.
use std::iter::Iterator;
struct PermutationIterator<T> {
vs: Vec<Vec<T>>,
is: Vec<usize>,
}
impl<T> PermutationIterator<T> {
fn new() -> PermutationIterator<T> {
PermutationIterator {
vs: vec![],
is: vec![],
}
}
fn add(&mut self, v: Vec<T>) {
self.vs.push(v);
self.is.push(0);
}
}
impl<T> Iterator for PermutationIterator<T> {
type Item = Vec<&'a T>;
fn next(&mut self) -> Option<Vec<&T>> {
'outer: loop {
for i in 0..self.vs.len() {
if self.is[i] >= self.vs[i].len() {
if i == 0 {
return None; // we are done
}
self.is[i] = 0;
self.is[i - 1] += 1;
continue 'outer;
}
}
let mut result = vec![];
for i in 0..self.vs.len() {
let index = self.is[i];
result.push(self.vs[i].get(index).unwrap());
}
*self.is.last_mut().unwrap() += 1;
return Some(result);
}
}
}
fn main() {
let v1: Vec<_> = (1..3).collect();
let v2: Vec<_> = (3..5).collect();
let v3: Vec<_> = (1..6).collect();
let mut i = PermutationIterator::new();
i.add(v1);
i.add(v2);
i.add(v3);
loop {
match i.next() {
Some(v) => {
println!("{:?}", v);
}
None => {
break;
}
}
}
}
(Playground link)
error[E0261]: use of undeclared lifetime name `'a`
--> src/main.rs:23:22
|
23 | type Item = Vec<&'a T>;
| ^^ undeclared lifetime
As far as I understand, you want want the iterator to return a vector of references into itself, right? Unfortunately, it is not possible in Rust.
This is the trimmed down Iterator trait:
trait Iterator {
type Item;
fn next(&mut self) -> Option<Item>;
}
Note that there is no lifetime connection between &mut self and Option<Item>. This means that next() method can't return references into the iterator itself. You just can't express a lifetime of the returned references. This is basically the reason that you couldn't find a way to specify the correct lifetime - it would've looked like this:
fn next<'a>(&'a mut self) -> Option<Vec<&'a T>>
except that this is not a valid next() method for Iterator trait.
Such iterators (the ones which can return references into themselves) are called streaming iterators. You can find more here, here and here, if you want.
Update. However, you can return a reference to some other structure from your iterator - that's how most of collection iterators work. It could look like this:
pub struct PermutationIterator<'a, T> {
vs: &'a [Vec<T>],
is: Vec<usize>
}
impl<'a, T> Iterator for PermutationIterator<'a, T> {
type Item = Vec<&'a T>;
fn next(&mut self) -> Option<Vec<&'a T>> {
...
}
}
Note how lifetime 'a is now declared on impl block. It is OK to do so (required, in fact) because you need to specify the lifetime parameter on the structure. Then you can use the same 'a both in Item and in next() return type. Again, that's how most of collection iterators work.
#VladimirMatveev's answer is correct in how it explains why your code cannot compile. In a nutshell, it says that an Iterator cannot yield borrowed values from within itself.
However, it can yield borrowed values from something else. This is what is achieved with Vec and Iter: the Vec owns the values, and the the Iter is just a wrapper able to yield references within the Vec.
Here is a design which achieves what you want. The iterator is, like with Vec and Iter, just a wrapper over other containers who actually own the values.
use std::iter::Iterator;
struct PermutationIterator<'a, T: 'a> {
vs : Vec<&'a [T]>,
is : Vec<usize>
}
impl<'a, T> PermutationIterator<'a, T> {
fn new() -> PermutationIterator<'a, T> { ... }
fn add(&mut self, v : &'a [T]) { ... }
}
impl<'a, T> Iterator for PermutationIterator<'a, T> {
type Item = Vec<&'a T>;
fn next(&mut self) -> Option<Vec<&'a T>> { ... }
}
fn main() {
let v1 : Vec<i32> = (1..3).collect();
let v2 : Vec<i32> = (3..5).collect();
let v3 : Vec<i32> = (1..6).collect();
let mut i = PermutationIterator::new();
i.add(&v1);
i.add(&v2);
i.add(&v3);
loop {
match i.next() {
Some(v) => { println!("{:?}", v); }
None => {break;}
}
}
}
(Playground)
Unrelated to your initial problem. If this were just me, I would ensure that all borrowed vectors are taken at once. The idea is to remove the repeated calls to add and to pass directly all borrowed vectors at construction:
use std::iter::{Iterator, repeat};
struct PermutationIterator<'a, T: 'a> {
...
}
impl<'a, T> PermutationIterator<'a, T> {
fn new(vs: Vec<&'a [T]>) -> PermutationIterator<'a, T> {
let n = vs.len();
PermutationIterator {
vs: vs,
is: repeat(0).take(n).collect(),
}
}
}
impl<'a, T> Iterator for PermutationIterator<'a, T> {
...
}
fn main() {
let v1 : Vec<i32> = (1..3).collect();
let v2 : Vec<i32> = (3..5).collect();
let v3 : Vec<i32> = (1..6).collect();
let vall: Vec<&[i32]> = vec![&v1, &v2, &v3];
let mut i = PermutationIterator::new(vall);
}
(Playground)
(EDIT: Changed the iterator design to take a Vec<&'a [T]> rather than a Vec<Vec<&'a T>>. It's easier to take a ref to container than to build a container of refs.)
As mentioned in other answers, this is called a streaming iterator and it requires different guarantees from Rust's Iterator. One crate that provides such functionality is aptly called streaming-iterator and it provides the StreamingIterator trait.
Here is one example of implementing the trait:
extern crate streaming_iterator;
use streaming_iterator::StreamingIterator;
struct Demonstration {
scores: Vec<i32>,
position: usize,
}
// Since `StreamingIterator` requires that we be able to call
// `advance` before `get`, we have to start "before" the first
// element. We assume that there will never be the maximum number of
// entries in the `Vec`, so we use `usize::MAX` as our sentinel value.
impl Demonstration {
fn new() -> Self {
Demonstration {
scores: vec![1, 2, 3],
position: std::usize::MAX,
}
}
fn reset(&mut self) {
self.position = std::usize::MAX;
}
}
impl StreamingIterator for Demonstration {
type Item = i32;
fn advance(&mut self) {
self.position = self.position.wrapping_add(1);
}
fn get(&self) -> Option<&Self::Item> {
self.scores.get(self.position)
}
}
fn main() {
let mut example = Demonstration::new();
loop {
example.advance();
match example.get() {
Some(v) => {
println!("v: {}", v);
}
None => break,
}
}
example.reset();
loop {
example.advance();
match example.get() {
Some(v) => {
println!("v: {}", v);
}
None => break,
}
}
}
Unfortunately, streaming iterators will be limited until generic associated types (GATs) from RFC 1598 are implemented.
I wrote this code not long ago and somehow stumbled on this question here. It does exactly what the question asks: it shows how to implement an iterator that passes its callbacks a reference to itself.
It adds an .iter_map() method to IntoIterator instances. Initially I thought it should be implemented for Iterator itself, but that was a less flexible design decision.
I created a small crate for it and posted my code to GitHub in case you want to experiment with it, you can find it here.
WRT the OP's trouble with defining lifetimes for the items, I didn't run into any such trouble implementing this while relying on the default elided lifetimes.
Here's an example of usage. Note the parameter the callback receives is the iterator itself, the callback is expected to pull the data from it and either pass it along as is or do whatever other operations.
use iter_map::IntoIterMap;
let mut b = true;
let s = "hello world!".chars().peekable().iter_map(|iter| {
if let Some(&ch) = iter.peek() {
if ch == 'o' && b {
b = false;
Some('0')
} else {
b = true;
iter.next()
}
} else { None }
}).collect::<String>();
assert_eq!(&s, "hell0o w0orld!");
Because the IntoIterMap generic trait is implemented for IntoIterator, you can get an "iter map" off anything that supports that interface. For instance, one can be created directly off an array, like so:
use iter_map::*;
fn main()
{
let mut i = 0;
let v = [1, 2, 3, 4, 5, 6].iter_map(move |iter| {
i += 1;
if i % 3 == 0 {
Some(0)
} else {
iter.next().copied()
}
}).collect::<Vec<_>>();
assert_eq!(v, vec![1, 2, 0, 3, 4, 0, 5, 6, 0]);
}
Here's the full code - it was amazing it took such little code to implement, and everything just seemed to work smoothly while putting it together. It gave me a new appreciation for the flexibility of Rust itself and its design decisions.
/// Adds `.iter_map()` method to all IntoIterator classes.
///
impl<F, I, J, R, T> IntoIterMap<F, I, R, T> for J
//
where F: FnMut(&mut I) -> Option<R>,
I: Iterator<Item = T>,
J: IntoIterator<Item = T, IntoIter = I>,
{
/// Returns an iterator that invokes the callback in `.next()`, passing it
/// the original iterator as an argument. The callback can return any
/// arbitrary type within an `Option`.
///
fn iter_map(self, callback: F) -> ParamFromFnIter<F, I>
{
ParamFromFnIter::new(self.into_iter(), callback)
}
}
/// A trait to add the `.iter_map()` method to any existing class.
///
pub trait IntoIterMap<F, I, R, T>
//
where F: FnMut(&mut I) -> Option<R>,
I: Iterator<Item = T>,
{
/// Returns a `ParamFromFnIter` iterator which wraps the iterator it's
/// invoked on.
///
/// # Arguments
/// * `callback` - The callback that gets invoked by `.next()`.
/// This callback is passed the original iterator as its
/// parameter.
///
fn iter_map(self, callback: F) -> ParamFromFnIter<F, I>;
}
/// Implements an iterator that can be created from a callback.
/// does pretty much the same thing as `std::iter::from_fn()` except the
/// callback signature of this class takes a data argument.
pub struct ParamFromFnIter<F, D>
{
callback: F,
data: D,
}
impl<F, D, R> ParamFromFnIter<F, D>
//
where F: FnMut(&mut D) -> Option<R>,
{
/// Creates a new `ParamFromFnIter` iterator instance.
///
/// This provides a flexible and simple way to create new iterators by
/// defining a callback.
/// # Arguments
/// * `data` - Data that will be passed to the callback on each
/// invocation.
/// * `callback` - The callback that gets invoked when `.next()` is invoked
/// on the returned iterator.
///
pub fn new(data: D, callback: F) -> Self
{
ParamFromFnIter { callback, data }
}
}
/// Implements Iterator for ParamFromFnIter.
///
impl<F, D, R> Iterator for ParamFromFnIter<F, D>
//
where F: FnMut(&mut D) -> Option<R>,
{
type Item = R;
/// Iterator method that returns the next item.
/// Invokes the client code provided iterator, passing it `&mut self.data`.
///
fn next(&mut self) -> Option<Self::Item>
{
(self.callback)(&mut self.data)
}
}

How can I add new methods to Iterator?

I want to define a .unique() method on iterators that enables me to iterate without duplicates.
use std::collections::HashSet;
struct UniqueState<'a> {
seen: HashSet<String>,
underlying: &'a mut Iterator<Item = String>,
}
trait Unique {
fn unique(&mut self) -> UniqueState;
}
impl Unique for Iterator<Item = String> {
fn unique(&mut self) -> UniqueState {
UniqueState {
seen: HashSet::new(),
underlying: self,
}
}
}
impl<'a> Iterator for UniqueState<'a> {
type Item = String;
fn next(&mut self) -> Option<String> {
while let Some(x) = self.underlying.next() {
if !self.seen.contains(&x) {
self.seen.insert(x.clone());
return Some(x);
}
}
None
}
}
This compiles. However, when I try to use in the same file:
fn main() {
let foo = vec!["a", "b", "a", "cc", "cc", "d"];
for s in foo.iter().unique() {
println!("{}", s);
}
}
I get the following error:
error[E0599]: no method named `unique` found for type `std::slice::Iter<'_, &str>` in the current scope
--> src/main.rs:37:25
|
37 | for s in foo.iter().unique() {
| ^^^^^^
|
= help: items from traits can only be used if the trait is implemented and in scope
= note: the following trait defines an item `unique`, perhaps you need to implement it:
candidate #1: `Unique`
What am I doing wrong? How would I extend this arbitrary hashable types?
In your particular case, it's because you have implemented your trait for an iterator of String, but your vector is providing an iterator of &str. Here's a more generic version:
use std::collections::HashSet;
use std::hash::Hash;
struct Unique<I>
where
I: Iterator,
{
seen: HashSet<I::Item>,
underlying: I,
}
impl<I> Iterator for Unique<I>
where
I: Iterator,
I::Item: Hash + Eq + Clone,
{
type Item = I::Item;
fn next(&mut self) -> Option<Self::Item> {
while let Some(x) = self.underlying.next() {
if !self.seen.contains(&x) {
self.seen.insert(x.clone());
return Some(x);
}
}
None
}
}
trait UniqueExt: Iterator {
fn unique(self) -> Unique<Self>
where
Self::Item: Hash + Eq + Clone,
Self: Sized,
{
Unique {
seen: HashSet::new(),
underlying: self,
}
}
}
impl<I: Iterator> UniqueExt for I {}
fn main() {
let foo = vec!["a", "b", "a", "cc", "cc", "d"];
for s in foo.iter().unique() {
println!("{}", s);
}
}
Broadly, we create a new extension trait called UniqueExt which has Iterator as a supertrait. When Iterator is a supertrait, we will have access to the associated type Iterator::Item.
This trait defines the unique method, which is only valid to call when then iterated item can be:
Hashed
Compared for total equality
Cloned
Additionally, it requires that the item implementing Iterator have a known size at compile time. This is done so that the iterator can be consumed by the Unique iterator adapter.
The other important part is the blanket implementation of the trait for any type that also implements Iterator:
impl<I: Iterator> UniqueExt for I {}

How do I pass a function pointer recursively?

I want to write an Iterator adaptor which applies a function recursively to its underlying Iterator. Recursively because the variant IR::Loop includes a Vec<IR>, of which an iterator should also be passed to the function.
The function should take an &mut Iterator<Item = IR> and use it to compute the next value of the iterator, (like itertools::batching).
use std::iter::Peekable;
#[derive(Clone)]
enum IR {
OperationA,
OperationB,
Loop(Vec<IR>),
}
pub trait MyItertools: Iterator {
fn apply_recursive<F: Fn(&mut Peekable<Self>) -> Option<Self::Item>>(
self,
f: F,
) -> ApplyRecursive<Self, F>
where
Self: Sized,
Self::Item: Clone,
{
ApplyRecursive {
iter: self.peekable(),
f: f,
}
}
}
impl<T: ?Sized> MyItertools for T
where
T: Iterator,
{
}
//applies a function recursively to some Iterator with Item=IR
#[derive(Clone)]
struct ApplyRecursive<I, F>
where
I: Iterator,
I::Item: Clone,
{
iter: Peekable<I>,
f: F,
}
impl<I: Iterator<Item = IR>, F> Iterator for ApplyRecursive<I, F>
where
F: Fn(&mut Peekable<I>)
-> Option<I::Item>,
{
type Item = I::Item;
fn next(&mut self) -> Option<I::Item> {
match self.iter.peek() {
Some(&IR::Loop(code)) => {
self.iter.next(); //advance the iterator
let code: Vec<IR> = code.into_iter().apply_recursive(self.f).collect();
Some(IR::Loop(code))
}
Some(x) => (self.f)(&mut self.iter),
None => None,
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.iter.size_hint()
}
}
fn main() {}
playground
What am I doing wrong? I don't even understand the error message:
error[E0277]: the trait bound `for<'r> F: std::ops::Fn<(&'r mut std::iter::Peekable<std::vec::IntoIter<IR>>,)>` is not satisfied
--> src/main.rs:54:54
|
54 | let code: Vec<IR> = code.into_iter().apply_recursive(self.f).collect();
| ^^^^^^^^^^^^^^^ the trait `for<'r> std::ops::Fn<(&'r mut std::iter::Peekable<std::vec::IntoIter<IR>>,)>` is not implemented for `F`
|
= help: consider adding a `where for<'r> F: std::ops::Fn<(&'r mut std::iter::Peekable<std::vec::IntoIter<IR>>,)>` bound
error[E0277]: the trait bound `for<'r> F: std::ops::FnOnce<(&'r mut std::iter::Peekable<std::vec::IntoIter<IR>>,)>` is not satisfied
--> src/main.rs:54:54
|
54 | let code: Vec<IR> = code.into_iter().apply_recursive(self.f).collect();
| ^^^^^^^^^^^^^^^ the trait `for<'r> std::ops::FnOnce<(&'r mut std::iter::Peekable<std::vec::IntoIter<IR>>,)>` is not implemented for `F`
|
= help: consider adding a `where for<'r> F: std::ops::FnOnce<(&'r mut std::iter::Peekable<std::vec::IntoIter<IR>>,)>` bound
error: no method named `collect` found for type `ApplyRecursive<std::vec::IntoIter<IR>, F>` in the current scope
--> src/main.rs:54:78
|
54 | let code: Vec<IR> = code.into_iter().apply_recursive(self.f).collect();
| ^^^^^^^
|
= note: the method `collect` exists but the following trait bounds were not satisfied: `F : std::ops::Fn<(&mut std::iter::Peekable<std::vec::IntoIter<IR>>,)>`, `ApplyRecursive<std::vec::IntoIter<IR>, F> : std::iter::Iterator`
= help: items from traits can only be used if the trait is implemented and in scope; the following trait defines an item `collect`, perhaps you need to implement it:
= help: candidate #1: `std::iter::Iterator`
The last error indicates that you don't have an Iterator. Iterator is only implemented for your struct under certain conditions, and you aren't meeting them. The second error explains why.
the trait for<'r> Fn<(&'r mut IntoIter<IR>,)> is not implemented for the type F
So, why does the compiler think this won't work? Let's look at your constraints:
impl<I, F> Iterator for ApplyRecursive<I, F>
where
I: Iterator<Item = IR>
F: Fn(&mut Peekable<I>) -> Option<I::Item>,
This structure refers to a concrete type I that implements Iterator. Then F is a concrete type that accepts a mutable reference to the same concrete type as I. However, you try to use your function (specialized for whatever type it happens to be) on the concrete type IntoIter - but this might be a different concrete type!
The easiest fix is to remove the generics here:
impl<F> Iterator for ApplyRecursive<vec::IntoIter<IR>, F>
where
F: Fn(&mut vec::IntoIter<IR>) -> Option<IR>,
{
type Item = IR;
fn next(&mut self) -> Option<IR> {
This unlocks a whole other slew of errors about mutability, accessing private fields, and exporting private types, but I think it gets over this hump.
Alternatively, we can change F to accept a trait object, and not worry about specializing it:
pub trait CustomIter: Iterator {
fn apply_recursive<F>(self, f: F) -> ApplyRecursive<Self, F>
where
F: Fn(&mut Iterator<Item = Self::Item>) -> Option<Self::Item>,
Self: Sized,
Self::Item: Clone,
{
ApplyRecursive { iter: self.peekable(), f: f }
}
}
impl<I, F> Iterator for ApplyRecursive<I, F>
where
I: Iterator<Item = IR>,
F: Fn(&mut Iterator<Item = IR>) -> Option<IR>,
{
type Item = I::Item;
fn next(&mut self) -> Option<IR> {