Reputation: 3419
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() {}
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`
Upvotes: 0
Views: 185
Reputation: 430671
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 typeF
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> {
Upvotes: 2