wit-bindgen
wit-bindgen copied to clipboard
"associated functions" and "associated methods" on non-resource types
Given the following wit:
record color {
r: float32,
g: float32,
b: float32,
a: float32
}
record vec4 {
x: float32,
y: float32,
z: float32,
w: float32
}
// (pseudocode) associated method for color
color.from-rgba: func(r: u8, g: u8, b: u8, a: u8) -> color;
// (pseudocode) associated function
color.to-vec: func(self: color) -> vec4;
when Rust bindings are generated, I'd like to allow a Rust guest to write:
let foo = Color { r: 0.1, g: 0.2, b: 0.3, a: 1.0 }; // can construct the type by struct literal syntax
let r = foo.r; // can access a field
let bar = Color::from_rgba(180, 180, 180, 255); // can construct the type with an associated function
let vec: Vec4 = bar.to_vec(); // can call an associated method
The closest I could find to this in the wit IDL document is a resource
.
As syntactic sugar, resource statements can also declare any number of methods, which are functions that implicitly take a
self
parameter that is a handle. A resource statement can also contain any number of static functions, which do not have an implicitself
parameter but are meant to be lexically nested in the scope of the resource type. Lastly, a resource statement can contain at most one constructor function, which is syntactic sugar for a function returning a handle of the containing resource type.For example, the following resource definition:
resource blob { constructor(init: list<u8>); write: func(bytes: list<u8>); read: func(n: u32) -> list<u8>; merge: static func(lhs: borrow<blob>, rhs: borrow<blob>) -> blob; }
desugars into:
resource blob; %[constructor]blob: func(self: borrow<blob>, bytes: list<u8>) -> blob; %[method]blob.write: func(self: borrow<blob>, bytes: list<u8>); %[method]blob.read: func(self: borrow<blob>, n: u32) -> list<u8>; %[static]blob.merge: func(lhs: borrow<blob>, rhs: borrow<blob>) -> blob;
These
%
-prefixedname
s embed the resource type name so that bindings generators can generate idiomatic syntax for the target language or (for languages like C) fall back to an appropriately-prefixed free function name.
The wit IDL document refers to these as syntactic sugar, and references a "desugaring" of sub-definitions within a resource
.
This seems to imply (if it isn't purely illustrative) that %[method]blob.write: func(self: borrow<blob>, bytes: list<u8>);
should be valid wit.
And in the component model document, a plainname
like this is valid:
exportname ::= <plainname> | <interfacename> importname ::= <exportname> | <depname> | <urlname> | <hashname> plainname ::= <label> | '[constructor]' <label> | '[method]' <label> '.' <label> | '[static]' <label> '.' <label> label ::= <word> | <label> '-' <word> word ::= [a-z] [0-9a-z]* | [A-Z] [0-9A-Z]* ...
The obvious attempt was to do:
%[constructor]color: func(r: float32, g: float32, b: float32, a: float32) -> color;
%[static]color.from-rgba: func(r: u8, g: u8, b: u8, a: u8) -> color;
%[static]color.from-hex: func(hex: u32) -> color;
%[method]color.to-vec: func(self: borrow<color>) -> vec4;
%[static]color.from-vec: func(vec: vec4) -> vec4;
However, this fails like so:
Caused by:
identifiers must have characters between '-'s
--> C:\Users\...\host.wit:43:3
|
43 | %[constructor]color: func(r: float32, g: float32, b: float32, a: float32) -> color;
| ^
So there seems no wit-bindgen
-compatible way to express a plainname
of '[constructor]' <label> | '[method]' <label> '.' <label> | '[static]' <label> '.' <label>
and/or no wit-bindgen
-compatible way to express "associated functions" and "associated methods" on non-resource types.
Is this something that is supported by wit? Is this something supported by the component model itself?
Ah yes the "desugars into" text there is a bit handwavy and as you've discovered it's not intended that the literal desugaring works. The method naming here with [constructor]
and such actually plays into validation of the component itself, and depends on resources being "nominal" types, so it wouldn't be easy to allow such constructs for arbitrary types like records and such.
There's probably two different ways this issue could be tackled, however:
- Add "fanciness" to the
wit-bindgen
Rust generator (and possibly others) to generate methods where free functions would otherwise be generated. This is just an idea, I've no idea what this would concretely look like. - Propose upstream in the component-model repository that
[method]
and friends be allowed for more than just resources but additionally records and other types.