-
Notifications
You must be signed in to change notification settings - Fork 16
Upgrade to witx 0.9 #4
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
Conversation
Thank you! This is great! Strings producing |
No more |
Cargo.toml
Outdated
@@ -1,11 +1,11 @@ | |||
[package] | |||
name = "as-witx" | |||
version = "0.1.0" | |||
version = "1.2.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.
Sounds a bit premature. Maybe we should stick with 0.x
for now :)
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.
Whoops, good catch! I updated it to 0.20
as originally intended
BTW, there's a |
I haven't looked at 0.10 at all, but given the explainer hasn't been modified at all I'm hopeful it'll have fewer breaking changes. flags and strings still exist within witx files but they get de sugared into simpler defs under the hood via these equivalencies:
So flags should still work as expected, it's mainly problematic for string because a list of char is a list of unicode scalars as opposed to like a utf16 string we'd want to expose to people consuming the generated assembly. I think it should be pretty easy to special case logic for |
The output now includes Rust (???) like code: export declare function options_close(
handle: options
): union<Result<(), crypto_errno>> /* error */; Any idea where that could come from? |
I do not, what's the input file you used to generate that output? I'll try to debug it |
I tried with the which previously generated https://github.com/WebAssembly/wasi-crypto/blob/main/implementations/bindings/assemblyscript/assembly/wasi_crypto.ts |
Thanks you that looks like the kind of thing that would be really handy to add as tests. I took a look and it was due to me adding a line in |
Unions can have name, there wouldn't be anything wrong with that. But Rust code is not a name :) Maybe a bug in The correct type everywhere in the example above should be Prior to
was represented as
In
with "error" being a union ("variant") with two members, So, what the function actually returns is So complicated :( |
So, |
Ah, no, the
is then represented in the witx object as
head -> | wall |
Yeah my understanding at the moment is the expected variant is basically a translation of rust's Result to witx. Past that So I'd imagine we could do the same for now without too much trouble. It sounds like the restriction to a single return value is temporary and eventually it will support full multi value (as wasm does) but we can burn that bridge when we get there. That being said should union's still translate to |
Oh no, this is worse. From the (param $symmetric_key $symmetric_key)
(param $symmetric_key_id (@witx pointer u8))
(param $symmetric_key_id_max_len $size)
- (result $error $crypto_errno)
- (result $symmetric_key_id_len $size)
- (result $version $version)
+ (result $error (expected (tuple $size $version) (error $crypto_errno))) If there is more than 1 result, the list must be wrapped in a tuple. |
The union should be decomposed into its I'm currently trying to do something along these lines // func.results doesn't contain the actual results; it's an array with only one element named "error";
// this is a union that contains both the error type and the first returned value.
// Unlike other return values, the first returned value (which is not the value the function returns -- that is the error)
// is not encoded as a pointer, but must be transformed into one.
let results = &func.results;
assert_eq!(results.len(), 1);
let results = &results[0];
assert_eq!(results.name, "error");
let v = match results.tref.type_().as_ref() {
witx::Type::Variant(x) => &x.cases,
_ => panic!("Unexpected type for the result wrapper"),
};
assert_eq!(v.len(), 2);
let mut error_ref = None;
let mut results_ref = None;
for vv in v {
match vv.name.as_str() {
"err" => {
error_ref = vv.tref.as_ref();
}
"ok" => {
results_ref= vv.tref.as_ref();
}
_ => panic!("Unexpected member in the result wrapper"),
}
}
let error_ref = match error_ref {
None => panic!("Incomplete result wrapper"),
Some(error_ref) => error_ref,
};
let return_value = &Self::param_to_as("err", error_ref);
// The returned value must be representable as a single word
assert_eq!(return_value.len(), 1);
let return_value = &return_value[0];
...
// and now explode `results_ref` into an actual array if we have a tuple, or a single element if we don't |
The union for the result and returned values doesn't make sense; it doesn't represent the actual binary interface. |
|
tuple is one of the new syntax sugars. It desugars to a record with numerical fields |
Got it. So there must be something like a These two structures are actually very different. I don't expect the generated code to be the same in both cases, even less so in documentation. So maybe we should introduce a proper In fact all the types with |
Honestly, this is getting so confusing that I'd rather delete everything and start over from scratch based on |
I'm not sure I follow, in my mind this is simpler than 0.8. we only need to support the base set of types
and generate code for them, and then if we want we can handle special case behavior such as |
But taking the example of a tuple. The emitted code would be... a tuple. Not a structure with field names. A
The code to generate is completely different for each of them. |
Right I'm saying we don't need to emit all those special cases at outset. Like with variant, as long as we emit a valid assemblyscript object that represents a Similarly for records, as long as we emit reasonable assemblyscript for |
That would be horrible to use, especially with things such as tuples and flags that are completely different (how would you
It would be nice to keep it generic and eventually useful for other languages. |
I think I'm not making my point clearly so let me try to tackle it from a different angle. RecordDatatype has to be exposed to users regardless of tuple or flags existing. When you generating bindings for something like
whether or not we have tuples or flags we'd still want something like
and we'd want to generate something similar in text or zig respectively. Given that is the case, tuple and flags both desugar into an instance of |
Taking the example of returned values. If the returned value is a |
That is not the case, both a tuple and a struct would be converted to a record and then we would return a pointer to that record. Atleast for an MVP, as I said we can always layer specialized handling on top of the general base codegen. But the point is we don't have to, we can ignore the specialized variants of thing and still generate correct code. |
Was there an ABI change? Previously, when the WITX file had multiple This change is assumed to not change the ABI, but we now have a |
The change you linked is a change in the original witx file. What does it have to do with what code gets generated? I believe they just changed that function to return a tuple instead of using output parameters. |
Ouch, good to know. I didn't expect that change to also change the function signature. |
Details of the underlying changes to witx can be found here.
This was mainly a simplification, a lot of things that previously were a standalone type (flags, strings, enums, unions) are now syntax sugar for one of the underlying primitives (List, Variant, etc.).
Given String no longer exists it might make sense to remove the WasiString type. It would also be nice to recognize something like
(list char)
and convert it to the WasiString type when we see it. Currently a string converts toWasmArray<u32>
which is not super usable. I haven't looked into what that would involve though