-
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
Add support for iterators using js_sys::Iterator
#1913
base: main
Are you sure you want to change the base?
Conversation
I've modified the implementation to use typed output values for the iterators. |
To make progress with this (assuming you want to merge it), I would need to know if creating a |
Thanks for this! I wonder if we could perhaps get by though without dealing with the generics in webidl? We don't, for example, handle anything about promises/futures, we just sling around bland In terms of implementation I think we're still currently in a mode of "if it works it works", no need to worry too too much about speed and such here I think. |
3246c80
to
cde783e
Compare
I've moved back to using |
It looks like there's still some typing support and traits like |
Hi yeah sorry this isn't ready for review yet. I'll ping once it is. |
Ready for review :). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking great to me, thanks for this!
crates/webidl/src/first_pass.rs
Outdated
key: weedle::types::Type<'src>, | ||
value: weedle::types::Type<'src>, | ||
}, | ||
ArrayLike(weedle::types::Type<'src>), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think the types here can probably be removed?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah I left them in so that in future they could be used to generate rust types, but yep they could be removed now. Shall I remove them?
It would be great if we could support proper static types, so |
Ah, I see you already tried that before. I'm surprised at @alexcrichton 's reasoning: if we use And we already have enough information in the WebIDL to do the correct thing. All of the other WebIDL methods return the correct static type, so why not Iterators as well? |
I'm not necessarily opposed to having a more typed interface, but originally it was relatively complicated with new traits and such which I felt was a bit overblown. If we want a typed interface I think we'll want to eschew complexity in favor of being pretty simple. |
If you have an idea you're keen on and could sketch out your thinking, I can implement it. i can't remember why I felt like I needed the trait, I'll try to remind myself. |
@alexcrichton That's fair. I think it's possible to get proper static types with only some minor tweaks: Since it's already generating a brand new pub fn iter(&self)
-> impl std::iter::Iterator<Item=(#key, #value)>
{
struct Iter(js_sys::Iterator);
impl Iterator for Iter {
type Item = (#key, #value);
fn next(&mut self) -> Option<Self::Item> {
// ...
let key = entry.get(0).unchecked_into();
let value = entry.get(1).unchecked_into();
// ...
}
}
// ...
} |
@Pauan I think I need to copy whatever the webidl crate does to generate rust types from webidl types. I'm reading through that code now. |
What I think now would be the best way to do typed iter would be the following (ignoring the map case for simplicity) fn iter(&self) -> impl Iterator<Item=Ty> {
// ...
} when called runs the following code in js return self[Symbol.iterator]; and returns the value to rust fn iter(&self) -> impl Iterator<Item=Ty> {
as_rust_owned(run_js_code(as_js(self)))
} Then, say this value is called struct MyIter {
inner: HandleToIterator
}
impl MyIter {
#[wasm-bindgen]
extern "C" fn next_js(&self) -> Option<Ty>;
}
impl Iterator for MyIter {
type Item=Ty;
fn next(&self) -> Option<Self::Item> {
self.next_js()
}
} where in javascript next_js looks like function next_js(self) {
const next = self.next();
if next.done {
return js_none;
} else {
return js_some(next.value);
}
} Given this I need the following js-rust glue
If I were writing this using the #[wasm_bindgen]
extern {
pub struct IterableThing; // This could be anything to iterate over, e.g. a `web_sys::Headers`
pub struct AnonIter;
#[wasm_bindgen(method)]
pub fn iter_js(thing: &IterableThing) -> AnonIter;
#[wasm_bindgen(method, js_name="next")]
pub fn next_js(iter: AnonIter) -> Option<ItemType>;
}
impl Iterator for AnonIter {
type Item = ItemType;
fn next(&mut self) -> Option<Self::Item> {
self.next_js()
}
}
impl IterableThing {
fn iter(&self) -> impl Iterator<Item=ItemType> {
self.iter_js()
}
} |
I think I need a little bit of guidance on how to proceed with typing the output of the iterator. |
@derekdreery Does my suggestion not work? You would just add in a couple calls to |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Something like this should work.
let entry = next.value(); | ||
debug_assert!(entry.has_type::<js_sys::Array>()); | ||
let entry: js_sys::Array = entry.unchecked_into(); | ||
let key = entry.get(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let key = entry.get(0); | |
let key = entry.get(0).unchecked_into(); |
debug_assert!(entry.has_type::<js_sys::Array>()); | ||
let entry: js_sys::Array = entry.unchecked_into(); | ||
let key = entry.get(0); | ||
let value = entry.get(1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let value = entry.get(1); | |
let value = entry.get(1).unchecked_into(); |
crates/backend/src/codegen.rs
Outdated
let iter_name = Ident::new(&format!("{}Iter", rust_name), rust_name.span()); | ||
|
||
let item = match iterable { | ||
ast::Iterable::MapLike { .. } => quote!((::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue)), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ast::Iterable::MapLike { .. } => quote!((::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue)), | |
ast::Iterable::MapLike { key, value } => quote!((#key, #value)), |
crates/backend/src/codegen.rs
Outdated
|
||
let item = match iterable { | ||
ast::Iterable::MapLike { .. } => quote!((::wasm_bindgen::JsValue, ::wasm_bindgen::JsValue)), | ||
ast::Iterable::ArrayLike { .. } => quote!(::wasm_bindgen::JsValue), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ast::Iterable::ArrayLike { .. } => quote!(::wasm_bindgen::JsValue), | |
ast::Iterable::ArrayLike { value } => value, |
crates/backend/src/codegen.rs
Outdated
let value = entry.get(1); | ||
Some((key, value)) | ||
}, | ||
ast::Iterable::ArrayLike { .. } => quote!(Some(next.value())), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ast::Iterable::ArrayLike { .. } => quote!(Some(next.value())), | |
ast::Iterable::ArrayLike { .. } => quote!(Some(next.value().unchecked_into())), |
So I tried your suggestions and got the errors
and
The problem is that to generate good bindings we want to run the string import code and present the rust side as a string, rather than a |
@derekdreery Hmm, that's annoying, I guess it should be using As for stdweb handles it so much better: it just has As for this specific issue, maybe we can ignore those types somehow? It means we'll be missing some |
@Pauan I think maybe work on the types should be in a separate PR. |
3f50918
to
455a05b
Compare
squashed. |
@derekdreery Well, I'm personally okay with having it done in a second PR, but that second PR would have to be done before we release, because changing the type is a breaking change. |
I think the CI fail was spurious. |
just for information, here are all the
so
Also the
and the same for |
@derekdreery Great, so if we use |
@Pauan yes - but there would be 2 remaining issues
Alternatively we could do whatever the rest of wasm-bindgen does to emit glue code and actually use |
Note that in the meantime we have addressed this without specific type support: #3962. |
This PR adds an
iter
method toiterable
webidl elements, meaning that they can be iterated over in rust.