gtk-rs-core icon indicating copy to clipboard operation
gtk-rs-core copied to clipboard

Add an Iterator for ListModel

Open V02460 opened this issue 3 years ago • 10 comments

This PR implements an Iterator for the ListModel interface.

The Iterator can be created by the interface’s iter method. Example usage:

for member in members.iter::<User>() {
    …
}

As you can see, the iter method takes a type parameter T that is the type of the yielded items. At creation time of the Iterator a type check is performed to make sure it is a subtype of the model’s item type. Having a type-wise more convenient Iterator is also the reason I decided against implementing IntoIterator as it forces you to yield Object-type items. (This restriction could be lifted, if ListModel itself had the correct type parameter.)

The Iterator gives always sensible results, even if the model underneath it changes. That means no duplicates or unnecessary omissions. It accomplishes that cheaply by listening to the items-changed signal of the underlying model and adjusting its internal index accordingly.

Implementing DoubleEndedIterator and ExactSizeIterator should be possible, too, I might do that after a round of feedback.

V02460 avatar Jul 22 '21 19:07 V02460

What happens when an item gets removed while you're iterating through the list model?

bilelmoussaoui avatar Jul 24 '21 20:07 bilelmoussaoui

What happens when an item gets removed while you're iterating through the list model?

Funny, I asked the same question. I also asked for an alternative: what happens if you remove the current item and all the following ones?

GuillaumeGomez avatar Jul 24 '21 20:07 GuillaumeGomez

First of all, the iterator never panics.

What happens when an item gets removed while you're iterating through the list model?

The iterator does the natural thing and continues relative to the items it was working on before the change of model. More specifically, I differentiate three cases: before, after and inside the change. The before and after cases continue relative to where they were before. For the inside case, I used the hopefully least unexpected thing and skip to after the change. The exact function of adjusting the underlying index can be seen at adjust_index.

what happens if you remove the current item and all the following ones?

The next method of the iterator returns None, so the iteration ends when it is called the next time.

V02460 avatar Jul 25 '21 18:07 V02460

I think a test case that ensures that it works as expected is needed here

bilelmoussaoui avatar Jul 25 '21 18:07 bilelmoussaoui

This definitely needs many tests and documentation for the behaviour, and some justification why this is the right behaviour. @bilelmoussaoui as someone actually doing things with list models, would this behaviour be the one you would expect?

sdroege avatar Jul 27 '21 05:07 sdroege

@GuillaumeGomez @bilelmoussaoui What do you think, which behaviour would make most sense here? Personally I think the Result/transactional way would make sense.

sdroege avatar Aug 31 '21 07:08 sdroege

I'm new to this thread, so sorry if I've missed something.

Since a list model contains a list of GObjects, it's just a list of pointers. They're cheap to clone. Can't we just get the entire list of GObjects in a sweep, put them in a Vec<glib::Object> and then return Vec::into_iter? It's not the best solution, but hey, it works, it's transactional, and it's better than nothing. It can be improved later

ranfdev avatar Dec 17 '21 20:12 ranfdev

That would be possible, yes.

sdroege avatar Dec 17 '21 22:12 sdroege

That… yes. :sweat_smile:

V02460 avatar Dec 17 '21 23:12 V02460

That one is merged now but I'd still like to get something around this here in

sdroege avatar Dec 22 '21 11:12 sdroege