I have a custom type called Streamlines. It's a list of lines in 3D, implemented as a vector of offsets and a vector of points to avoid allocating too much. Iterating on a Streamlines returns slices of points. It returns slices because all the points are in a single vector and I do not want to copy uselessly.
I created my own Reader to read the streamlines files written on disk. It reads the file streamline per streamline. Iterating on a Reader returns a vector of points. It returns owned data because the data doesn't exist anywhere. It's created while reading.
I tried to write a function that accept both kind of data
fn wathever<I>(streamlines: I)
I: IntoIterator<Item = &'a [Point]> // Works only for the Streamlines
OR
I: IntoIterator<Item = Vec<Point>, // Works only for the Reader
{
for streamline in &streamlines {
// Do something with the points (no modification)
}
}
I understand why both versions work only on a single type. This is normal and simple enough. What I don't understand is how to make it work for both types. I tried using AsRef and Borrow but I don't think it's supposed to be used in an iterator. Is it possible to write such a function in Rust?
You're using a traitAsRef<[Point]> in a place where a type is expected. In principle this doesn't work at all; in practice, AsRef<[Point]> is also a (deprecated) way of writing dyn AsRef<[Point]>; which is a type .. more accurately the type of trait objects for the AsRef<[Point]> trait. Trait objects are unsized and iterator items are sized which is why you're getting the error message.
The right place for a trait to go it on the right-hand-side of a trait bound, i.e. a bound Type: Trait where it constrains a type. That type is the type I::Item. If it was a thing, perhaps something like IntoIterator<Item: AsRef<[Point]>> would be a reasonable notational equivalent, too, but rust doesn't support such syntax, so it needs to go on a separate line. One (mostly) equivalent alternative is to write IntoIterator<Item = T> where T is a new type variable, and put a trait bound T: AsRef<[Point]> separately.
error[E0782]: trait objects must include the `dyn` keyword
--> src/lib.rs:4:34
|
4 | where I: IntoIterator<Item = AsRef<[Point]>>
| ^^^^^^^^^^^^^^
Now, that's still imperfect for this case since you don't wantdyn AsRef there, but at least it starts talking about dyn so you're more likely to notice what's going on.