diff --git a/crates/gen-guest-rust/src/lib.rs b/crates/gen-guest-rust/src/lib.rs index f882ae286..7c0c4fd39 100644 --- a/crates/gen-guest-rust/src/lib.rs +++ b/crates/gen-guest-rust/src/lib.rs @@ -53,6 +53,10 @@ pub struct Opts { /// crate. #[cfg_attr(feature = "clap", arg(skip))] pub standalone: bool, + + /// If true, code generation should avoid any features that depend on `std`. + #[cfg_attr(feature = "clap", arg(long))] + pub no_std: bool, } #[derive(Default)] @@ -92,6 +96,10 @@ impl RustWasm { } impl RustGenerator for RustWasm { + fn use_std(&self) -> bool { + !self.opts.no_std + } + fn default_param_mode(&self) -> TypeMode { if self.in_import { // We default to borrowing as much as possible to maximize the ability @@ -167,6 +175,10 @@ impl Generator for RustWasm { )); } + self.src.push_str("#[allow(unused_imports)]"); + self.src + .push_str("use wit_bindgen_guest_rust::rt::{alloc, vec::Vec, string::String};"); + self.sizes.fill(iface); } @@ -758,14 +770,14 @@ impl FunctionBindgen<'_> { fn emit_cleanup(&mut self) { for (ptr, layout) in mem::take(&mut self.cleanup) { self.push_str(&format!( - "if {layout}.size() != 0 {{\nstd::alloc::dealloc({ptr}, {layout});\n}}\n" + "if {layout}.size() != 0 {{\nalloc::dealloc({ptr}, {layout});\n}}\n" )); } if self.needs_cleanup_list { self.push_str( "for (ptr, layout) in cleanup_list {\n if layout.size() != 0 {\n - std::alloc::dealloc(ptr, layout);\n + alloc::dealloc(ptr, layout);\n }\n }\n", ); @@ -1231,7 +1243,7 @@ impl Bindgen for FunctionBindgen<'_> { assert_eq!(none, "()"); let operand = &operands[0]; let invalid = if unchecked { - "std::hint::unreachable_unchecked()" + "core::hint::unreachable_unchecked()" } else { "panic!(\"invalid enum discriminant\")" }; @@ -1268,7 +1280,7 @@ impl Bindgen for FunctionBindgen<'_> { let ok = self.blocks.pop().unwrap(); let operand = &operands[0]; let invalid = if unchecked { - "std::hint::unreachable_unchecked()" + "core::hint::unreachable_unchecked()" } else { "panic!(\"invalid enum discriminant\")" }; @@ -1400,15 +1412,15 @@ impl Bindgen for FunctionBindgen<'_> { let size = self.gen.sizes.size(element); let align = self.gen.sizes.align(element); self.push_str(&format!( - "let {layout} = core::alloc::Layout::from_size_align_unchecked({vec}.len() * {size}, {align});\n", + "let {layout} = alloc::Layout::from_size_align_unchecked({vec}.len() * {size}, {align});\n", )); self.push_str(&format!( - "let {result} = if {layout}.size() != 0\n{{\nlet ptr = std::alloc::alloc({layout});\n", + "let {result} = if {layout}.size() != 0\n{{\nlet ptr = alloc::alloc({layout});\n", )); self.push_str(&format!( - "if ptr.is_null()\n{{\nstd::alloc::handle_alloc_error({layout});\n}}\nptr\n}}", + "if ptr.is_null()\n{{\nalloc::handle_alloc_error({layout});\n}}\nptr\n}}", )); - self.push_str(&format!("else {{\nstd::ptr::null_mut()\n}};\n",)); + self.push_str(&format!("else {{\ncore::ptr::null_mut()\n}};\n",)); self.push_str(&format!("for (i, e) in {vec}.into_iter().enumerate() {{\n",)); self.push_str(&format!( "let base = {result} as i32 + (i as i32) * {size};\n", diff --git a/crates/gen-rust-lib/src/lib.rs b/crates/gen-rust-lib/src/lib.rs index ff568b383..d4314af6f 100644 --- a/crates/gen-rust-lib/src/lib.rs +++ b/crates/gen-rust-lib/src/lib.rs @@ -14,6 +14,11 @@ pub enum TypeMode { } pub trait RustGenerator { + /// Return true iff the generator can use `std` features in its output. + fn use_std(&self) -> bool { + true + } + fn push_str(&mut self, s: &str); fn info(&self, ty: TypeId) -> TypeInfo; fn types_mut(&mut self) -> &mut Types; @@ -828,9 +833,11 @@ pub trait RustGenerator { self.push_str("}\n"); self.push_str("}\n"); self.push_str("\n"); - self.push_str("impl std::error::Error for "); - self.push_str(&name); - self.push_str("{}\n"); + if self.use_std() { + self.push_str("impl std::error::Error for "); + self.push_str(&name); + self.push_str("{}\n"); + } } else { self.print_rust_enum_debug( id, diff --git a/crates/guest-rust-macro/src/lib.rs b/crates/guest-rust-macro/src/lib.rs index 52fe0b484..f5c6dd0cf 100644 --- a/crates/guest-rust-macro/src/lib.rs +++ b/crates/guest-rust-macro/src/lib.rs @@ -52,6 +52,7 @@ mod kw { syn::custom_keyword!(paths); syn::custom_keyword!(unchecked); syn::custom_keyword!(multi_module); + syn::custom_keyword!(no_std); } impl Parse for Opts { @@ -69,6 +70,7 @@ impl Parse for Opts { ConfigField::Unchecked => opts.unchecked = true, ConfigField::MultiModule => opts.multi_module = true, ConfigField::Interfaces(v) => interfaces = v, + ConfigField::NoStd => opts.no_std = true, } } if interfaces.is_empty() { @@ -104,6 +106,7 @@ enum ConfigField { Interfaces(Vec), Unchecked, MultiModule, + NoStd, } impl Parse for ConfigField { @@ -141,6 +144,9 @@ impl Parse for ConfigField { } else if l.peek(kw::multi_module) { input.parse::()?; Ok(ConfigField::MultiModule) + } else if l.peek(kw::no_std) { + input.parse::()?; + Ok(ConfigField::NoStd) } else { Err(l.error()) } diff --git a/crates/guest-rust/src/lib.rs b/crates/guest-rust/src/lib.rs index dcc002653..8613e784d 100644 --- a/crates/guest-rust/src/lib.rs +++ b/crates/guest-rust/src/lib.rs @@ -1,7 +1,12 @@ -use std::fmt; -use std::marker; -use std::mem; -use std::ops::Deref; +#![no_std] + +extern crate alloc; + +use alloc::boxed::Box; +use core::fmt; +use core::marker; +use core::mem; +use core::ops::Deref; #[cfg(feature = "macros")] pub use wit_bindgen_guest_rust_macro::{export, import}; @@ -123,7 +128,10 @@ pub unsafe trait LocalHandle: HandleType { #[doc(hidden)] pub mod rt { - use std::alloc::{self, Layout}; + use super::alloc::alloc::Layout; + + // Re-export things from liballoc for convenient use. + pub use super::alloc::{alloc, string, vec}; #[no_mangle] unsafe extern "C" fn cabi_realloc(