Rust tells me this does not work, because map has a type parameter and thus makes TokenIter not object-safe:
error[E0038]: the trait `TokenIter` cannot be made into an object
--> src/parser.rs:5:37
|
5 | fn parse(&self, token_iter: Box<dyn TokenIter<I>>) -> Result<A, ParseError>;
| ^^^^^^^^^^^^^^^^ `TokenIter` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> src/token/token_iter.rs:10:8
|
9 | pub trait TokenIter<I>: Iterator<Item=TokenResult<I>> {
| --------- this trait cannot be made into an object...
10 | fn map<J, F: FnMut(I) -> J>(self, f: F) -> Map<I, J, F>;
| ^^^ ...because method `map` has generic type parameters
= help: consider moving `map` to another trait
I was hoping to take inspiration from the standard Iterator and its map method, but I can't figure out why Iterator is object-safe even though map has type parameters?
Let's look at the full signature for Iterator::map()
That where Self: Sized clause means the map() method will only be available when Self has a known size, allowing the rest of the interface to be object-safe.
Trait objects don't implement Sized, so if you require Self: Sized in a method it won't be included in the trait object. This also means it won't be considered when checking if the trait is object-safe, but note that this also means you won't be able to call it on a trait object. The stdlib solved this final problem by implementing Iterator for Box<dyn Iterator> and &mut dyn Iterator by reimplementing all the methods in terms of next, which is object safe and thus included in the trait object.
Actually, I can't implement Box<dyn TokenIter<I>>, because it's not my type. Maybe I'll work around by making TokenIter<I> a struct that owns a Box<dyn Iterator<Item=TokenResult<I>>>. Not what I hoped for, but what can I do.
You could just copy the stdlib, adding where Self: Sized to map and then implementing TokenIter<I> for Box<dyn TokenIter<I>>. This will work because you're implementing your own trait for another type.