Description
Many tools might want to add additional metadata to WIT declarations that modify code generation behaviour.
A concrete example would be the async
option of wit-bindgen-wasmtime
, which marks functions as async and currently has to be specified in a macro or on the command line.
I realize that that is only temporary until the component model gains async support, but there are many other use cases.
Examples:
- Deprecating types/fields/variants, allowing generators to produce respective annotations in languages that support those
- Customizing ownership semantics (eg don't implement
Clone
in Rust), or make functions consume a value - Rust: deriving additional traits on generates types
(likeEq
,Hash
,serde::Serialize
, ...) - Controlling the visibility of items
Some languages like Rust make this easy with wrapper modules that selectively re-export, but that's not the case for others like Python, Javascript, etc where you might want to keep the generated types private (orprotected
in eg Java) and provide custom wrappers - Customizing field types
- ...
If there is no standard way to declare these, generators will always need some custom metadata layer for customization, which seems suboptimal.
Prior Art
Protobuf
Protobuf has custom options, which is a particularly fancy system that allows defining well-typed options that are even restricted to specific scopes.
import "google/protobuf/descriptor.proto";
extend google.protobuf.MessageOptions {
optional string my_option = 51234;
}
message MyMessage {
option (my_option) = "Hello world!";
}
Cap'n Proto
Capn' Proto also has a well-typed annotation system.
annotation foo(struct, enum) :Text;
# Declare an annotation 'foo' which applies to struct and enum types.
struct MyType $foo("bar") {
# Apply 'foo' to to MyType.
# ...
}
Proposal
I'd personally love a well-typed annotation system inspired by the above, but I also understand if that is currently not appreciated / too complex.
I'd be happy to come up with a concrete proposal and implement it in wit-bindgen
, but I wanted to get some opinions first.
An alternative would be untyped annotations that can be attached to a set of AST items (type declarations, fields, variants, functions, ...) and allow all valid tokens within delimiters.
For example:
@rust(derive = ["PartialEq", "Eq"])
record r {
@deprecated
a: string,
@deprecated(reason = "use b2 instead")
b: u64,
b2: i64,
}
@deprecated
f = func()