-
-
Notifications
You must be signed in to change notification settings - Fork 1.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support returning Iterator<Item=T>
via an iterable iterator
#4142
Comments
I think as a more general solution, it would be best if we start by support defining AFAIU So I'm mostly in favor of your 3. alternative. I believe it would be reasonable to add a conversion from Let me know what you think! |
That's a good point. Is there already an issue for it?
Ah true. JS and TS is mostly one thing in my head, so sometimes I mix things up.
I don't think this is a bad idea, but this might become a pitfall. Rust programmers might naturally assume that they should use I wonder whether we could make On that note: binding the JS |
I'm not aware of one.
I guess this would cover all three variants then. But yes, this will be a problem to figure out without a breaking change. |
Motivation
Right now, returning Rust iterators is a pain. While collecting everything into a vec (so the JS side can get an
Array<T>
) can work for some scenarios, this approach is simply not possible when iterators contain infinite elements and undesirable when computing individual elements is costly. #1478 has more context. I made this a separate issue, because I want to talk about a specific solution.Determined users might attempt to make their own iterator wrapper, but this comes with some pitfalls. While very similar, the iterator protocols for Rust and JS have subtle differences. One important one is what happens after iteration is done. Rust says that calling
next
may return pretty much anything (=unspecified but not UB; it may even panic), while JS requires thatnext
returns{ done: true }
.In my specific case, I had an iterator with between 1 and 248 elements, where each element can take a few milliseconds to compute, with no way to know how many elements there will be before having computed the first element. The idea was that the JS side can decide how many elements to take based on a time budget and user input while showing a little animation in the browser. I made my own wrapper and fell right into that pitfall.
Proposed Solution
Add a
struct IterableIterator<T>
type tojs_sys
and implementFrom<Iterator<Item=T>>
for it. The idea is to allow users to write code like this:or even better:
The generated JS code would then look something like this:
The basic idea is to return an object that implements the Rust iterator protocol (
next(&mut self) -> Option<Item>
) can convert it to the JS iterator protocol (next(): IteratorResult
).Alternatively, much of the JS
next
method could also be done in Rust depending on what would be easier/more efficient.I would also like to suggest wrapping the returned JS object with
Iterator.from
if available. Since this API is brand new (currently stage 3), this would only be done when the JS environment supports it.Alternatives
js_sys::IterableIterator
. This has the huge downside of losing type information for the generated TS types. I would like iterators to be strongly typed on both sides.Symbol.iterator
) or pure iterable (nonext
) on the JS side. Both are viable since most built-in JS APIs support both, but the same is not true for libraries. Most libraries take iterables, most often explicitly typed asIterable<T>
, because standard container types likeArray
andSet
are iterables but not iterators. So returning a pure iterator is not as useful in the wider JS ecosystem. A pure iterable would be viable, but anIterableIterator<T>
communicates that it can only be iterated once. This is the current expectation, becauseIterableIterator<T>
is most notably returned by generator functions.Additional Context
A similar solution could also be used to support the upcoming Rust 2024
gen
blocks/fns. This will create a nice symmetry between Rust generators and JS generators.I would like to discuss this solution and then make a PR for it. However, I'll likely need some guidance on it
The text was updated successfully, but these errors were encountered: