wit-bindgen-rust: enable standalone code generation.#193
Conversation
|
Putting this up as a proposed solution to a few things:
Regarding the above, I'm completely open to alternative solutions; this was needed as currently proposed simply to make progress on the component tooling. If we have the following interface: say-something: function() -> stringThen the "standalone" generated code for this as an import would be: pub fn say_something() -> String {
unsafe {
let ptr0 = IMPORT_RET_AREA.as_mut_ptr() as i32;
#[link(wasm_import_module = "import-0.1.0")]
extern "C" {
#[cfg_attr(target_arch = "wasm32", link_name = "say-something")]
#[cfg_attr(not(target_arch = "wasm32"), link_name = "import-0.1.0_say-something")]
fn wit_import(_: i32);
}
wit_import(ptr0);
let len1 = *((ptr0 + 8) as *const i32) as usize;
String::from_utf8(Vec::from_raw_parts(
*((ptr0 + 0) as *const i32) as *mut _,
len1,
len1,
))
.unwrap()
}
}
static mut IMPORT_RET_AREA: [i64; 2] = [0; 2];And for the export: /// Declares the export of the interface for the given type.
#[macro_export]
macro_rules! export(($t:ident) => {
#[export_name = "export-0.1.0#say-something"]
unsafe extern "C" fn __wit_bindgen_export_say_something() -> i32{
#[allow(unused_imports)]
use wit_bindgen_rust;
use export::*;
let result0 = <$t as Export>::say_something();
let vec1 = (result0.into_bytes()).into_boxed_slice();
let ptr1 = vec1.as_ptr() as i32;
let len1 = vec1.len() as i32;
core::mem::forget(vec1);
let ptr2 = EXPORT_RET_AREA.as_mut_ptr() as i32;
*((ptr2 + 8) as *mut i32) = len1;
*((ptr2 + 0) as *mut i32) = ptr1;
ptr2
}
static mut EXPORT_RET_AREA: [i64; 2] = [0; 2];
});
pub trait Export {
fn say_something() -> String;
}And used like this from a user's project, assuming use export::Export;
struct Component;
impl Export for Component {
fn say_something() -> String {
import::say_something()
}
}
export::export!(Component); // one export macro invocation per exported interface |
|
I should also add that the changes here are entirely opt-in and used by the component tooling, not the proc-macros. The existing proc-macro-based generation output should remain the same. |
|
This all seems pretty reasonable to me! I'd prefer though to not maintain multiple modes if we can. Could the new mode be just how the proc-macro works? |
|
I think I can remove the The rest of the changes can remain and we'll need to update the examples/tests to use the generated wit_bindgen_rust::export!("export.wit");
wit_bindgen_rust::import!("import.wit");
struct Component;
impl export::Export for Component {
fn say_something() -> String {
import::say_something()
}
}
export::export!(Component); // one export macro invocation per exported interfaceHow does that sound? |
|
Sounds reasonable to me! |
|
Argh...I've been trying to get this to play nice with resources and failing (not something necessary for the component model right this minute, so this PR punted on that for now with the "standalone" support); lots of assumptions on My first attempt was "oh I'll just add a type to the interface trait so that the type implementing the trait can specify resource implementation types" and that made some of the resource test cases happy. But then I got to the handles test case where handles to resource types are inside of the type definitions and not just the exported function signatures; those need to exist outside of the I'm still thinking about how best to accomplish this. |
|
I like this I had been thinking of something similar for work so we can publish a helper crate that wraps WIT file imports and exports, plus some convenience functions, so downstream users just need to add a single crate as a dependency.
FWIW, you can do |
Effectively. I meant that I would put the generated By having the mod always present and just have the standalone tooling add an additional The problems I'm running into right now relate to what to do about resources as they also reference If we didn't support resources (we don't yet in the component model, but will soon enough), then there would be no issues with removing the "standalone" mode from this PR using the technique described above. |
|
I think it's an open option to removing resource support for now and re-adding it back in when the component model gets it. We'll probably have to solve the same questions you're running into now but we can hope that the intervening time gave us inspiration. In general this is starting to age relative to the recent changes in the canonical ABI as well so it's due for a number of updates. |
|
Great timing, I just also asked for this in #191 . My idea there was to add an |
534c910 to
4c5430f
Compare
4c5430f to
f737b3a
Compare
|
What's the status on this? Any blockers? I'm happy to help out if needed. |
This commit enables a "standalone" mode to the Rust bindings generator. The general idea is that this mode may be used to generate bindings that can be built as separate crates and depended upon like normal Rust crates. For both import and export bindings, this means not nesting the bindings inside of a module. For export bindings, this means generating a macro that consuming crates can use to export an interface for a given type. Additionally, this allows users to export multiple interfaces from the same type. An optional `module` field was added to `Interface` to also allow users some control over the exported and imported symbol names. When specified, it is used as the module name for import bindings. For export bindings, it is used as part of a formatted export name of `<module>#<function>`; this format is what is currently expected of `wit-component` for exported (non-default) interfaces. This also removes support for the `crate_alias` option that was used in some prototypes to internally alias the `wit_bindgen_rust` crate references; the option is no longer necessary.
f737b3a to
25b7ee6
Compare
|
@theduke sorry, I missed your ping last week. I've been focused entirely on component model proposal work these past few weeks and haven't given this PR any attention. However, this PR doesn't quite implement what is needed to close out #191 since it just makes it easier for the code to live in separate crates and doesn't do the "use this from an external crate" part; baby steps, I think. @alexcrichton it's been a little time since we last talked about this PR. It is currently what Plus, it's not that much in terms of change to back out at a later date once we settle on what code generation for resources should look like if we want to users might prefer to generate them into a external crate rather than inline from a proc macro. What are your thoughts on this? If you're super opposed to it, I can keep |
|
Ok that sounds reasonble to me yeah. Would you be ok writing up an issue on removing this option and using it by default so we can track that? |
|
@alexcrichton opened #243 to track that. |
This PR enables a "standalone" mode to the Rust bindings generator.
The general idea is that this mode may be used to generate bindings that can be
built as separate crates and depended upon like normal Rust crates.
For both import and export bindings, this means not nesting the bindings inside
of a module.
For export bindings, this means generating a macro that consuming crates can
use to export an interface for a given type. Additionally, this allows users to
export multiple interfaces from the same type (e.g. a single
Componentstruct).An optional
modulefield was added toInterfaceto also allow users somecontrol over the exported and imported symbol names. When specified, it is used
as the module name for import bindings. For export bindings, it is used as part
of a formatted export name of
<module>#<function>; this format is what iscurrently expected of
wit-componentfor exported (non-default) interfaces.