Skip to content

Commit

Permalink
Rust: add option for path to wit-bindgen runtime. (#619)
Browse files Browse the repository at this point in the history
* Rust: add option for path to wit-bindgen runtime.

This change adds an optional path to the `wit-bindgen` runtime to use for Rust
code generation.

This will allow a different crate from `wit-bindgen` to generate bindings while
also re-exporting `wit-bindgen::rt` at a known path for the generated code to
use.

* Rust: add `runtime_path` macro option and a test.
  • Loading branch information
peterhuene authored Jul 14, 2023
1 parent cce4af4 commit 4e2dcd4
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 30 deletions.
16 changes: 8 additions & 8 deletions crates/rust-lib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,11 +65,11 @@ pub trait RustGenerator<'a> {
true
}

/// Return the fully-qualified name for the `Vec` type to use.
fn vec_name(&self) -> &'static str;
/// Pushes the name of the `Vec` type to use.
fn push_vec_name(&mut self);

/// Return the fully-qualified name for the `String` type to use.
fn string_name(&self) -> &'static str;
/// Pushes the name of the `String` type to use.
fn push_string_name(&mut self);

/// Return true iff the generator should use `&[u8]` instead of `&str` in bindings.
fn use_raw_strings(&self) -> bool {
Expand Down Expand Up @@ -238,10 +238,10 @@ pub trait RustGenerator<'a> {
}
TypeMode::Owned => {
if self.use_raw_strings() {
self.push_str(self.vec_name());
self.push_vec_name();
self.push_str("::<u8>");
} else {
self.push_str(self.string_name());
self.push_string_name();
}
}
},
Expand Down Expand Up @@ -405,14 +405,14 @@ pub trait RustGenerator<'a> {
if self.resolve().all_bits_valid(ty) {
self.print_borrowed_slice(false, ty, lt, next_mode);
} else {
self.push_str(self.vec_name());
self.push_vec_name();
self.push_str("::<");
self.print_ty(ty, next_mode);
self.push_str(">");
}
}
TypeMode::Owned => {
self.push_str(self.vec_name());
self.push_vec_name();
self.push_str("::<");
self.print_ty(ty, next_mode);
self.push_str(">");
Expand Down
7 changes: 7 additions & 0 deletions crates/rust-macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ impl Parse for Config {
Opt::MacroCallPrefix(prefix) => opts.macro_call_prefix = Some(prefix.value()),
Opt::ExportMacroName(name) => opts.export_macro_name = Some(name.value()),
Opt::Skip(list) => opts.skip.extend(list.iter().map(|i| i.value())),
Opt::RuntimePath(path) => opts.runtime_path = Some(path.value()),
}
}
} else {
Expand Down Expand Up @@ -148,6 +149,7 @@ mod kw {
syn::custom_keyword!(path);
syn::custom_keyword!(inline);
syn::custom_keyword!(ownership);
syn::custom_keyword!(runtime_path);
}

enum Opt {
Expand All @@ -161,6 +163,7 @@ enum Opt {
ExportMacroName(syn::LitStr),
Skip(Vec<syn::LitStr>),
Ownership(Ownership),
RuntimePath(syn::LitStr),
}

impl Parse for Opt {
Expand Down Expand Up @@ -240,6 +243,10 @@ impl Parse for Opt {
syn::bracketed!(contents in input);
let list = Punctuated::<_, Token![,]>::parse_terminated(&contents)?;
Ok(Opt::Skip(list.iter().cloned().collect()))
} else if l.peek(kw::runtime_path) {
input.parse::<kw::runtime_path>()?;
input.parse::<Token![:]>()?;
Ok(Opt::RuntimePath(input.parse()?))
} else {
Err(l.error())
}
Expand Down
78 changes: 57 additions & 21 deletions crates/rust/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,12 @@ pub struct Opts {
/// types for borrowing and owning, if necessary.
#[cfg_attr(feature = "clap", arg(long))]
pub ownership: Ownership,

/// The optional path to the wit-bindgen runtime module to use.
///
/// This defaults to `wit_bindgen::rt`.
#[cfg_attr(feature = "clap", arg(long))]
pub runtime_path: Option<String>,
}

impl Opts {
Expand Down Expand Up @@ -149,6 +155,13 @@ impl RustWasm {
uwriteln!(self.src, "}}");
}
}

fn runtime_path(&self) -> &str {
self.opts
.runtime_path
.as_deref()
.unwrap_or("wit_bindgen::rt")
}
}

impl WorldGenerator for RustWasm {
Expand Down Expand Up @@ -414,12 +427,13 @@ impl InterfaceGenerator<'_> {
self.src,
"
#[allow(unused_imports)]
use wit_bindgen::rt::{{alloc, vec::Vec, string::String}};
use {rt}::{{alloc, vec::Vec, string::String}};
#[repr(align({align}))]
struct _RetArea([u8; {size}]);
static mut _RET_AREA: _RetArea = _RetArea([0; {size}]);
",
rt = self.gen.runtime_path(),
align = self.return_pointer_area_align,
size = self.return_pointer_area_size,
);
Expand Down Expand Up @@ -498,12 +512,13 @@ impl InterfaceGenerator<'_> {
self.src.push_str("#[allow(clippy::all)]\n");
let params = self.print_signature(func, param_mode, &sig);
self.src.push_str("{\n");
self.src.push_str(
self.src.push_str(&format!(
"
#[allow(unused_imports)]
use wit_bindgen::rt::{alloc, vec::Vec, string::String};
use {rt}::{{alloc, vec::Vec, string::String}};
",
);
rt = self.gen.runtime_path()
));
self.src.push_str("unsafe {\n");

let mut f = FunctionBindgen::new(self, params);
Expand Down Expand Up @@ -613,7 +628,7 @@ impl InterfaceGenerator<'_> {
self.src,
"
#[allow(unused_imports)]
use wit_bindgen::rt::{{alloc, vec::Vec, string::String}};
use {rt}::{{alloc, vec::Vec, string::String}};
// Before executing any other code, use this function to run all static
// constructors, if they have not yet been run. This is a hack required
Expand All @@ -627,9 +642,10 @@ impl InterfaceGenerator<'_> {
// https://github.com/bytecodealliance/preview2-prototyping/issues/99
// for more details.
#[cfg(target_arch=\"wasm32\")]
wit_bindgen::rt::run_ctors_once();
{rt}::run_ctors_once();
"
",
rt = self.gen.runtime_path()
);

// Finish out the macro-generated export implementation.
Expand Down Expand Up @@ -774,12 +790,15 @@ impl<'a> RustGenerator<'a> for InterfaceGenerator<'a> {
self.gen.opts.raw_strings
}

fn vec_name(&self) -> &'static str {
"wit_bindgen::rt::vec::Vec"
fn push_vec_name(&mut self) {
self.push_str(&format!("{rt}::vec::Vec", rt = self.gen.runtime_path()));
}

fn string_name(&self) -> &'static str {
"wit_bindgen::rt::string::String"
fn push_string_name(&mut self) {
self.push_str(&format!(
"{rt}::string::String",
rt = self.gen.runtime_path()
));
}

fn push_str(&mut self, s: &str) {
Expand Down Expand Up @@ -1090,7 +1109,10 @@ impl Bindgen for FunctionBindgen<'_, '_> {

Instruction::I64FromU64 | Instruction::I64FromS64 => {
let s = operands.pop().unwrap();
results.push(format!("wit_bindgen::rt::as_i64({})", s));
results.push(format!(
"{rt}::as_i64({s})",
rt = self.gen.gen.runtime_path()
));
}
Instruction::I32FromChar
| Instruction::I32FromU8
Expand All @@ -1100,16 +1122,25 @@ impl Bindgen for FunctionBindgen<'_, '_> {
| Instruction::I32FromU32
| Instruction::I32FromS32 => {
let s = operands.pop().unwrap();
results.push(format!("wit_bindgen::rt::as_i32({})", s));
results.push(format!(
"{rt}::as_i32({s})",
rt = self.gen.gen.runtime_path()
));
}

Instruction::F32FromFloat32 => {
let s = operands.pop().unwrap();
results.push(format!("wit_bindgen::rt::as_f32({})", s));
results.push(format!(
"{rt}::as_f32({s})",
rt = self.gen.gen.runtime_path()
));
}
Instruction::F64FromFloat64 => {
let s = operands.pop().unwrap();
results.push(format!("wit_bindgen::rt::as_f64({})", s));
results.push(format!(
"{rt}::as_f64({s})",
rt = self.gen.gen.runtime_path()
));
}
Instruction::Float32FromF32
| Instruction::Float64FromF64
Expand Down Expand Up @@ -1604,7 +1635,8 @@ impl Bindgen for FunctionBindgen<'_, '_> {
self.push_str("}\n");
results.push(result);
self.push_str(&format!(
"wit_bindgen::rt::dealloc({base}, ({len} as usize) * {size}, {align});\n",
"{rt}::dealloc({base}, ({len} as usize) * {size}, {align});\n",
rt = self.gen.gen.runtime_path(),
));
}

Expand Down Expand Up @@ -1742,15 +1774,18 @@ impl Bindgen for FunctionBindgen<'_, '_> {

Instruction::GuestDeallocate { size, align } => {
self.push_str(&format!(
"wit_bindgen::rt::dealloc({}, {}, {});\n",
operands[0], size, align
"{rt}::dealloc({op}, {size}, {align});\n",
rt = self.gen.gen.runtime_path(),
op = operands[0]
));
}

Instruction::GuestDeallocateString => {
self.push_str(&format!(
"wit_bindgen::rt::dealloc({}, ({}) as usize, 1);\n",
operands[0], operands[1],
"{rt}::dealloc({op0}, ({op1}) as usize, 1);\n",
rt = self.gen.gen.runtime_path(),
op0 = operands[0],
op1 = operands[1],
));
}

Expand Down Expand Up @@ -1802,7 +1837,8 @@ impl Bindgen for FunctionBindgen<'_, '_> {
self.push_str("\n}\n");
}
self.push_str(&format!(
"wit_bindgen::rt::dealloc({base}, ({len} as usize) * {size}, {align});\n",
"{rt}::dealloc({base}, ({len} as usize) * {size}, {align});\n",
rt = self.gen.gen.runtime_path(),
));
}

Expand Down
22 changes: 22 additions & 0 deletions crates/rust/tests/codegen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,25 @@ mod symbol_does_not_conflict {

export_foo!(Component);
}

mod alternative_runtime_path {
wit_bindgen::generate!({
inline: "
package my:inline
world foo {
export foo: func()
}
",
runtime_path: "my_rt",
});

pub(crate) use wit_bindgen::rt as my_rt;

struct Component;

impl Foo for Component {
fn foo() {}
}

export_foo!(Component);
}
2 changes: 1 addition & 1 deletion tests/runtime/records.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ impl test_imports::Host for MyImports {

fn roundtrip_flags1(&mut self, a: test_imports::F1) -> Result<test_imports::F1> {
drop(format!("{:?}", a));
drop(a & test_imports::F1::all());
let _ = a & test_imports::F1::all();
Ok(a)
}

Expand Down

0 comments on commit 4e2dcd4

Please sign in to comment.