Problem with Generics and Iterator


#1

Hi,

I want to implement a Iterator for a type that has a bunch of generics in it and my Rust generics isn’t real that strong (yet!)

So this is what I’m trying to do

https://play.rust-lang.org/?gist=067b3b0323d62c0aa6b70081eaff97aa&version=stable

And here is a “manual” version where I have implemented it with concrete types: https://play.rust-lang.org/?gist=f675be733c1d0a28b26b903790bede5d&version=stable and it’s something in this direction I want for the generic one but I’m not really sure how to achieve it.

Cheers!


#2

With this line here: impl<T, F> Iterator for Array<T, F> { we can see that there are no trait bounds for T, F. And traits are what we need to use in Rust to do most of the interesting things with a type parameter or generic items in general.

It looks like to me that you will just use F with a pointer cast, and you will ensure this is correct some place else, where you create the Array iterator. But for the T parameter you have a requirement: being able to create a T value from an F value. So you need a trait that has a method that allows that. It doesn’t have to be the From trait; if you have your own requirements, usually a custom trait is better.

Safety Notes

Your iterator takes a raw pointer from PUListWidgetItem but uses no lifetime so it doesn’t borrow it. Thus unless PUListWidgetItem is indefinitely in memory, the Array iterator is not memory safe.

You are also doing a simple pointer bumping along a contiguous part of memory. Why not re-use the slice iterator for this? You get the benefits of reusing a well written iterator, and it gets easy to do the borrowing correctly. Create a slice with the right element type (F) using std::slice::from_raw_parts and then an .iter() from that)


#3

Yeah that makes sense. I guess I need to figure out how to setup some trait(s) to wrap this.

Well the thing is that I don’t want to return F to the sure but I want to return T (ListWidgetItem in this case) T will wrap around F. I can of course do a Vec<T> and stuff all the data in but I would like to avoid the allocation if possible.


#4

Your iterator could wrap the slice iterator and map F to the right output type. That said, the ownership situation behind these raw pointers is not entirely clear to me, so it could be a bit more work to do.


#5

That makes sense. The ownership of the raw pointers is owned by the C(++) side so the “common” rules of the C++ API currently applies to the Rust side (if you destroy some widget and keep pointers to internal data and try to use it things will go bad) I haven’t looked into how to solve this on the Rust side as it’s kinda tricky but I will look into it later once I have something working.

Most of the code is auto-generated so it’s possible to apply lifetime changes later on at least.

Thanks!


#6

Oh I need to throw in a caution for the slice iterator. I’m very much in favour of composing new features on top of such things (slices, slice iterator, Vec) if possible. The caution about the slice is that it is invalid to create one with a null pointer. An empty slice uses a non-null pointer, either it uses align_of::<Elem>() as *const Elem or it uses something you get from a static empty array – [].as_ptr() !


#7

Thanks! I will take that into account.


#8

I see @bluss has you covered but here’s a quick playground example: https://play.rust-lang.org/?gist=4bf2493360360ecfa837408d9d385d49&version=stable

This uses std::convert::From. The suggestion to use a custom trait is fine but unless there are other requirements, From seems appropriate.


#9

Thanks!