Streaming iteration for non-IterQueryData#23218
Streaming iteration for non-IterQueryData#23218alice-i-cecile merged 6 commits intobevyengine:mainfrom
IterQueryData#23218Conversation
…ltiple items concurrently.
…multiple items concurrently.
…where necessary.
kfc35
left a comment
There was a problem hiding this comment.
I sat with this pull request for a while to understand what’s going on, probably for an embarrassingly long time. That being said, I can at least approve on the grounds that
- The safety comments are an improvement and are correct from what I can understand of Queries and by looking at the unsafe functions called
- The code changes reflect the intention in the PR description and what is stated in the migration guide, except for maybe one thing I commented on (I may be incorrect). The PR description was very helpful in describing the complete picture of iterators.
That being said, my approval may have blindspots if something else should be considered in the world of query iterators.
I’ll let my learnings of IterQueryData simmer a bit more in my brain.
alice-i-cecile
left a comment
There was a problem hiding this comment.
Changes LGTM, and I'm happy to get this in, but I think we can do a little better on docs to help users who stumble over the edge cases.
I updated the docs some more. I think everything is covered now, but it's always hard to be sure, so let me know if you think of anything else I missed! |
Objective
Follow-up to #21557
Support streaming iteration (a.k.a. lending iteration) for
QueryIterandQuerySortedIterso that it's possible to iterateQuery<Parent<&mut T>>.Double-check that all the
IterQueryDatabounds are correct and that the safety comments are correct. A few were not!Solution
Offer a
fetch_nextmethod onQueryIterandQuerySortedIterthat borrows the entire iterator to prevent aliasing, similar toQueryManyIter::QueryManyIter.Offer a
Query::iter_innermethod to produceQueryItereven when it is not anIterator. We cannot rely onIntoIteratorin that case, and Clippy objects to an inherent method calledinto_iter()that is not the standard trait method. This supersedes the existingiter_innermethod that only worked onReadOnlyQueryData.Add a missing
IterQueryDatabound toiter_combinations_mut. It yields multiple entities concurrently, so is never sound to use with non-IterQueryData. I think the reason I missed this originally is that it already has afetch_nextmethod and conditionalIteratorimpl. But evenfetch_nextyields multiple entities at once forQueryCombinationIter!Add a
ContiguousQueryData: IterQueryDatasupertrait bound.QueryContiguousIteralso yields multiple entities concurrently, so it does not make sense on non-iterable data. This was not actually unsound, though, asQueryContiguousIterdoes not callfetch.Finally, update some missing or incorrect safety comments.
Verify bounds on the other iterator types
To verify I didn't miss any bounds on iterator types, here is a list of every
Query*Itertype, and whether they support non-IterQueryData:Iter?CombinationIterContiguousIterIterManyIterManyUniqueIterParIterParManyIterParManyUniqueIterSortedIterSortedManyIterIterandSortedIterwere changed in this PR to support streaming iteration for allQueryData, while only implementingIteratorforIterQueryData.ManyIterandSortedManyIteralready had streaming iteration, and only implementIteratorwith a stricterReadOnlyQueryDatabound, since they may yield the same entity multiple times.ManyUniqueItercould theoretically be used with non-IterQueryData... but if you need to do streaming iteration anyway then you can calliter_many_mut()instead ofiter_many_unique_mut().CombinationIter,ContiguousIter, and thePar*Itertypes are all fundamentally about accessing multiple entities concurrently, and should always requireIterQueryData.CombinationIterandContiguousIterdid not haveIterQueryDatabounds, so fix that!Showcase
This is cheating a bit because we don't yet have
Parent<&mut T>, but once we do it would look like: