Skip to content
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

Missing WebIDL processing features overview #3921

Open
MOZGIII opened this issue Apr 10, 2024 · 3 comments
Open

Missing WebIDL processing features overview #3921

MOZGIII opened this issue Apr 10, 2024 · 3 comments

Comments

@MOZGIII
Copy link

MOZGIII commented Apr 10, 2024

I was doing a manual implementation for the WebTransport types, and here's case-study-based a list of missing features that makes WebIDL codegen really unusable:

  1. Lack of getters support for dictionaries. A lot of dictionaries are used in return positions: ReadableStream, pretty much everywhere in the getStats for WebTransport, etc.
  2. Dictionaries setters do not allow unsetting values (for the most part) - we might want to either make them all take Option<T> instead of T, or generate an additional accessor to allow unset_....
  3. Untyped async calls - the WebIDL has enough data to properly deduce the type, but that is not done, and an untype js_sys::Promise it returned instead. We should consider adding types support to the js_sys::Promise, and also generating the calls that return promises as real async fns. This is, however, blocked by Add .into() to the generated code for async fns #3919, as async fn generation is broken.
  4. Well, Add .into() to the generated code for async fns #3919. The async fn generation is broken.
  5. The catch is not generated correctly. This is an issue with WebIDL definitions, as they lack the machine-readable data on whether a call can throw or not - but nonetheless I count this towards the list of issues of the WebIDL-generated rust code.
  6. ReadableStream/WriteableStream should have a generic indicating what type they produce - they are capable of streaming not just the bytes (i.e. binary data, where they act like Read/Write), but objects too (acting more like a stream / async iterator in rust sense).
  7. Inability to turn certain hot calls final at the codegen level.
  8. I can't just install the latest wasm_bindgen_webidl as a dependency and use it in my crate - as the latest version is not published, and the last published is very old and conflicts with the rest of the crates. This is by far the easiest issue to solve.
  9. Errors types are not properly indicated anywhere, while the WebIDL has relevant info.

Also, some nits I encountered while implementing things manually.

  1. missing_docs lint is triggered for wasm_bindgen macro enums.
  2. No explicit support for attributes as wasm_bindgen macro, as in syntax sugar for generating both getter and setter from the same attribute.
  3. Declaring dictionaries manually is too verbose, they should really be a first-class item in the macro.

Not sure this is the right place for this, and those issue are most definitely reported before - but this is a case study organized in one place, and will hopefully act like a concise roadmap towards a better support for WebIDL. Hopefully if all those are solved somehow we'd get a way nicer codegen.
For now, using WebIDL is much more painful than using custom type declarations.

@pablosichert
Copy link

Dictionaries setters do not allow unsetting values (for the most part) - we might want to either make them all take Option<T> instead of T, or generate an additional accessor to allow unset_....

Just a quick comment on this one: allowing to unset values would effectively void the conditions that should hold for reading the properties. Meaning that all getters would need to be wrapped in an Option.

I guess you could implement the unset_... functions anyway and mark them unsafe?

@MOZGIII
Copy link
Author

MOZGIII commented Apr 25, 2024

Not all of them - the attribute ? (with ? at the end) - ones only, those should be unsettable, as they can effectively be not set and read as null (as I understand - null specifically, not undefined). For those values we absolutely need getters to return Option.

UPD: oh, yeah, dictionaries, right. They don't have definitions like that, and thus must absolutely always do the explicit Option<T> for all values. In my opinion, it is not about the ergonomics - but about correctness. In the context of a dictionaries, WebIDL does not actually encode the expected default values - so we can't procedurally generate them - but the spec itself usually does, so it is possible for a developer to properly deduce what value will be in effect if a dictionary value is unset, on a case-by-case basis via reading the docs. Combined with limitations of panics at wasm, and this becomes the only solution to avoid super-fragile apps imo.

@pablosichert
Copy link

pablosichert commented Apr 25, 2024

In the context of a dictionaries, WebIDL does not actually encode the expected default values

They actually do, so I think your suggestion of allowing to unset optional values only would work great.

E.g. the first dictionary declaration I could find going alphabetically in the enabled WebIDLs:

dictionary AnalyserOptions : AudioNodeOptions {
unsigned long fftSize = 2048;
double maxDecibels = -30;
double minDecibels = -100;
double smoothingTimeConstant = 0.8;
};

It just looks like the code generation for dictionary constructors produces undefined behavior by not setting default values in new:

impl AnalyserOptions {
#[doc = "Construct a new `AnalyserOptions`."]
#[doc = ""]
#[doc = "*This API requires the following crate features to be activated: `AnalyserOptions`*"]
pub fn new() -> Self {
#[allow(unused_mut)]
let mut ret: Self = ::wasm_bindgen::JsCast::unchecked_into(::js_sys::Object::new());
ret
}

I'll open a separate issue for that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants