From 33c85cd90f7d226abf794ed48122e64c3bca3540 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 7 Dec 2022 08:52:24 -0800 Subject: [PATCH 01/10] wip --- Cargo.lock | 1 + crates/wasmtime/src/component/error.rs | 126 ---------------------- crates/wasmtime/src/component/mod.rs | 2 - crates/wit-bindgen/Cargo.toml | 1 + crates/wit-bindgen/src/lib.rs | 140 +++++++++++++++++-------- 5 files changed, 100 insertions(+), 170 deletions(-) delete mode 100644 crates/wasmtime/src/component/error.rs diff --git a/Cargo.lock b/Cargo.lock index a91b1554dd31..9e2870918080 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3781,6 +3781,7 @@ dependencies = [ name = "wasmtime-wit-bindgen" version = "5.0.0" dependencies = [ + "anyhow", "heck", "wit-parser", ] diff --git a/crates/wasmtime/src/component/error.rs b/crates/wasmtime/src/component/error.rs deleted file mode 100644 index 8ca532fb87b4..000000000000 --- a/crates/wasmtime/src/component/error.rs +++ /dev/null @@ -1,126 +0,0 @@ -/// Type alias for the standard library [`Result`](std::result::Result) type -/// to specifie [`Error`] as the error payload. -pub type Result = std::result::Result>; - -/// Error type used by the [`bindgen!`](crate::component::bindgen) macro. -/// -/// This error type represents either the typed error `T` specified here or a -/// trap, represented with [`anyhow::Error`]. -pub struct Error { - err: anyhow::Error, - ty: std::marker::PhantomData, -} - -impl Error { - /// Creates a new typed version of this error from the `T` specified. - /// - /// This error, if it makes its way to the guest, will be returned to the - /// guest and the guest will be able to act upon it. - /// - /// Alternatively errors can be created with [`Error::trap`] which will - /// cause the guest to trap and be unable to act upon it. - pub fn new(err: T) -> Error - where - T: std::error::Error + Send + Sync + 'static, - { - Error { - err: err.into(), - ty: std::marker::PhantomData, - } - } - - /// Creates a custom "trap" which will abort guest execution and have the - /// specified `err` as the payload context returned from the original - /// invocation. - /// - /// Note that if `err` here actually has type `T` then the error will not be - /// considered a trap and will instead be dynamically detected as a normal - /// error to communicate to the original module. - pub fn trap(err: impl std::error::Error + Send + Sync + 'static) -> Error { - Error { - err: anyhow::Error::from(err), - ty: std::marker::PhantomData, - } - } - - /// Attempts to dynamically downcast this error internally to the `T` - /// representation. - /// - /// If this error is internally represented as a `T` then `Ok(val)` will be - /// returned. If this error is instead represented as a trap then - /// `Err(trap)` will be returned instead. - pub fn downcast(self) -> anyhow::Result - where - T: std::error::Error + Send + Sync + 'static, - { - self.err.downcast::() - } - - /// Attempts to dynamically downcast this error to peek at the inner - /// contents of `T` if present. - pub fn downcast_ref(&self) -> Option<&T> - where - T: std::error::Error + Send + Sync + 'static, - { - self.err.downcast_ref::() - } - - /// Attempts to dynamically downcast this error to peek at the inner - /// contents of `T` if present. - pub fn downcast_mut(&mut self) -> Option<&mut T> - where - T: std::error::Error + Send + Sync + 'static, - { - self.err.downcast_mut::() - } - - /// Converts this error into an `anyhow::Error` which loses the `T` type - /// information tagged to this error. - pub fn into_inner(self) -> anyhow::Error { - self.err - } - - /// Same as [`anyhow::Error::context`], attaches a contextual message to - /// this error. - pub fn context(self, context: C) -> Error - where - C: std::fmt::Display + Send + Sync + 'static, - { - self.err.context(context).into() - } -} - -impl std::ops::Deref for Error { - type Target = dyn std::error::Error + Send + Sync + 'static; - fn deref(&self) -> &Self::Target { - self.err.deref() - } -} -impl std::ops::DerefMut for Error { - fn deref_mut(&mut self) -> &mut Self::Target { - self.err.deref_mut() - } -} - -impl std::fmt::Display for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.err.fmt(f) - } -} - -impl std::fmt::Debug for Error { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - self.err.fmt(f) - } -} - -impl std::error::Error for Error {} - -impl From for Error { - fn from(err: anyhow::Error) -> Error { - Error { - err, - ty: std::marker::PhantomData, - } - } -} diff --git a/crates/wasmtime/src/component/mod.rs b/crates/wasmtime/src/component/mod.rs index 339788b397c9..ad91e8fddb19 100644 --- a/crates/wasmtime/src/component/mod.rs +++ b/crates/wasmtime/src/component/mod.rs @@ -4,7 +4,6 @@ //! probably buggy implementation of the component model. mod component; -mod error; mod func; mod instance; mod linker; @@ -14,7 +13,6 @@ mod store; pub mod types; mod values; pub use self::component::Component; -pub use self::error::{Error, Result}; pub use self::func::{ ComponentNamedList, ComponentType, Func, Lift, Lower, TypedFunc, WasmList, WasmStr, }; diff --git a/crates/wit-bindgen/Cargo.toml b/crates/wit-bindgen/Cargo.toml index 7511f7b1cff0..fc50af8b42fa 100644 --- a/crates/wit-bindgen/Cargo.toml +++ b/crates/wit-bindgen/Cargo.toml @@ -9,5 +9,6 @@ documentation = "https://docs.rs/wasmtime-wit-bindgen/" edition.workspace = true [dependencies] +anyhow = { workspace = true } heck = { workspace = true } wit-parser = { workspace = true } diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index 87ce222b92f7..d83f37f3528a 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -1,5 +1,6 @@ use crate::rust::{to_rust_ident, RustGenerator, TypeMode}; use crate::types::{TypeInfo, Types}; +use anyhow::{anyhow, Result}; use heck::*; use std::collections::BTreeMap; use std::fmt::Write as _; @@ -53,6 +54,11 @@ pub struct Opts { /// Whether or not to use async rust functions and traits. #[cfg_attr(feature = "clap", arg(long = "async"))] pub async_: bool, + + /// For a given wit interface and type name, generate a "trappable error type" + /// of the following Rust type name + #[cfg_attr(feature = "clap", arg(long = "trappable_error_type"), clap(value_name="INTERFACE:TYPE=RUSTTYPE", value_parser = parse_trappable_error))] + pub trappable_error_type: Vec<(String, String, String)>, } impl Opts { @@ -63,6 +69,18 @@ impl Opts { } } +#[cfg(feature = "clap")] +// Argument looks like `INTERFACE:TYPE=RUSTTYPE` +fn parse_trappable_error(s: &str) -> Result<(String, String, String)> { + let (interface, after_colon) = s + .split_once(':') + .ok_or_else(|| anyhow!("expected `:` separator"))?; + let (ty, rustty) = after_colon + .split_once('=') + .ok_or_else(|| anyhow!("expected `=` separator"))?; + Ok((interface, ty, rustty)) +} + impl Wasmtime { fn generate(&mut self, world: &World) -> String { for (name, import) in world.imports.iter() { @@ -80,7 +98,7 @@ impl Wasmtime { fn import(&mut self, name: &str, iface: &Interface) { let mut gen = InterfaceGenerator::new(self, iface, TypeMode::Owned); gen.types(); - gen.generate_from_error_impls(); + gen.generate_trappable_error_types(); gen.generate_add_to_linker(name); let snake = name.to_snake_case(); @@ -105,7 +123,7 @@ impl Wasmtime { fn export(&mut self, name: &str, iface: &Interface) { let mut gen = InterfaceGenerator::new(self, iface, TypeMode::AllBorrowed("'a")); gen.types(); - gen.generate_from_error_impls(); + gen.generate_trappable_error_types(); let camel = name.to_upper_camel_case(); uwriteln!(gen.src, "pub struct {camel} {{"); @@ -183,7 +201,7 @@ impl Wasmtime { fn export_default(&mut self, _name: &str, iface: &Interface) { let mut gen = InterfaceGenerator::new(self, iface, TypeMode::AllBorrowed("'a")); gen.types(); - gen.generate_from_error_impls(); + gen.generate_trappable_error_types(); let fields = gen.extract_typed_functions(); for (name, getter) in fields { let prev = gen @@ -302,6 +320,22 @@ impl Wasmtime { } } +impl Wasmtime { + fn trappable_error_types<'a>( + &'a self, + iface: &'a Interface, + ) -> impl Iterator + 'a { + self.opts + .trappable_error_type + .iter() + .filter(|(interface_name, _, _)| iface.name == *interface_name) + .filter_map(|(_, wit_typename, rust_typename)| { + let wit_type = iface.type_lookup.get(wit_typename)?; + Some((wit_typename, wit_type, rust_typename)) + }) + } +} + struct InterfaceGenerator<'a> { src: Source, gen: &'a mut Wasmtime, @@ -774,16 +808,20 @@ impl<'a> InterfaceGenerator<'a> { } } - fn special_case_host_error(&self, results: &Results) -> Option<&Result_> { - // We only support the Error case when - // a function has just one result, which is itself a `result`, and the - // `e` is *not* a primitive (i.e. defined in std) type. + fn special_case_trappable_error(&self, results: &Results) -> Option<(Result_, String)> { + // We fillin a special trappable error type in the case when a function has just one + // result, which is itself a `result`, and the `e` is *not* a primitive + // (i.e. defined in std) type, and matches the typename given by the user. let mut i = results.iter_types(); if i.len() == 1 { match i.next().unwrap() { Type::Id(id) => match &self.iface.types[*id].kind { TypeDefKind::Result(r) => match r.err { - Some(Type::Id(_)) => Some(&r), + Some(Type::Id(error_typeid)) => self + .gen + .trappable_error_types(&self.iface) + .find(|(_, wit_error_typeid, _)| error_typeid == **wit_error_typeid) + .map(|(_, _, rust_errortype)| (r.clone(), rust_errortype.clone())), _ => None, }, _ => None, @@ -823,22 +861,18 @@ impl<'a> InterfaceGenerator<'a> { self.push_str(")"); self.push_str(" -> "); - if let Some(r) = self.special_case_host_error(&func.results).cloned() { + if let Some((r, error_typename)) = self.special_case_trappable_error(&func.results) { // Functions which have a single result `result` get special // cased to use the host_wasmtime_rust::Error, making it possible // for them to trap or use `?` to propogate their errors - self.push_str("wasmtime::component::Result<"); + self.push_str("Result<"); if let Some(ok) = r.ok { self.print_ty(&ok, TypeMode::Owned); } else { self.push_str("()"); } self.push_str(","); - if let Some(err) = r.err { - self.print_ty(&err, TypeMode::Owned); - } else { - self.push_str("()"); - } + self.push_str(&error_typename); self.push_str(">"); } else { // All other functions get their return values wrapped in an anyhow::Result. @@ -936,7 +970,7 @@ impl<'a> InterfaceGenerator<'a> { uwrite!(self.src, ");\n"); } - if self.special_case_host_error(&func.results).is_some() { + if self.special_case_trappable_error(&func.results).is_some() { uwrite!( self.src, "match r {{ @@ -1081,33 +1115,55 @@ impl<'a> InterfaceGenerator<'a> { self.src.push_str("}\n"); } - fn generate_from_error_impls(&mut self) { - for (id, ty) in self.iface.types.iter() { - if ty.name.is_none() { - continue; - } - let info = self.info(id); - if info.error { - for (name, mode) in self.modes_of(id) { - let name = name.to_upper_camel_case(); - if self.lifetime_for(&info, mode).is_some() { - continue; - } - self.push_str("impl From<"); - self.push_str(&name); - self.push_str("> for wasmtime::component::Error<"); - self.push_str(&name); - self.push_str("> {\n"); - self.push_str("fn from(e: "); - self.push_str(&name); - self.push_str(") -> wasmtime::component::Error::< "); - self.push_str(&name); - self.push_str("> {\n"); - self.push_str("wasmtime::component::Error::new(e)\n"); - self.push_str("}\n"); - self.push_str("}\n"); - } + fn generate_trappable_error_types(&mut self) { + for (wit_typename, wit_type, trappable_type) in self.gen.trappable_error_types(&self.iface) + { + let info = self.info(*wit_type); + if self.lifetime_for(&info, TypeMode::Owned).is_some() { + panic!( + "type {:?} in interface {:?} is not 'static", + wit_typename, self.iface.name + ) } + let abi_type = self.param_name(*wit_type); + uwriteln!( + self.src, + " + #[derive(Debug)] + pub struct {trappable_type} {{ + inner: anyhow::Error, + }} + impl std::fmt::Display for {trappable_type} {{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {{ + write!(f, \"{{}}\", self.inner) + }} + }} + impl std::error::Error for {trappable_type} {{ + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {{ + self.inner.source() + }} + }} + impl {trappable_type} {{ + pub fn trap(inner: anyhow::Error) -> Self {{ + Self {{ inner }} + }} + pub fn downcast(self) -> Result<{abi_type}, anyhow::Error> {{ + self.inner.downcast() + }} + pub fn downcast_ref(&self) -> Option<&{abi_type}> {{ + self.inner.downcast_ref() + }} + pub fn context(self, s: impl Into) -> Self {{ + Self {{ inner: self.inner.context(s.into()) }} + }} + }} + impl From<{abi_type}> for {trappable_type} {{ + fn from(abi: {abi_type}) -> {trappable_type} {{ + {trappable_type} {{ inner: anyhow::Error::from(abi) }} + }} + }} + " + ); } } From 4f40c974610f6f58ad55316d7f52560142f9689b Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 7 Dec 2022 16:57:33 -0800 Subject: [PATCH 02/10] start trying to write a runtime test --- tests/all/component_model/bindgen.rs | 2 + tests/all/component_model/bindgen/results.rs | 127 +++++++++++++++++++ 2 files changed, 129 insertions(+) create mode 100644 tests/all/component_model/bindgen/results.rs diff --git a/tests/all/component_model/bindgen.rs b/tests/all/component_model/bindgen.rs index 40f5ec42cbb6..a52655dbdc72 100644 --- a/tests/all/component_model/bindgen.rs +++ b/tests/all/component_model/bindgen.rs @@ -5,6 +5,8 @@ use wasmtime::{ Store, }; +mod results; + mod no_imports { use super::*; diff --git a/tests/all/component_model/bindgen/results.rs b/tests/all/component_model/bindgen/results.rs new file mode 100644 index 000000000000..7a58ce6b3125 --- /dev/null +++ b/tests/all/component_model/bindgen/results.rs @@ -0,0 +1,127 @@ +use super::engine; +use anyhow::{anyhow, Error}; +use wasmtime::{ + component::{Component, Linker}, + Store, +}; + +wasmtime::component::bindgen!({ + inline: " + world result-playground { + import imports: interface { + empty-error: func(a: float64) -> result + string-error: func(a: float64) -> result + + enum e1 { a, b, c } + enum-error1: func(a: float64) -> result + + record e2 { line: u32, column: u32 } + record-error2: func(a: float64) -> result + + variant e3 { e1(e1), e2(e2) } + variant-error3: func(a: float64) -> result + } + + default export interface { + empty-error: func(a: float64) -> result + string-error: func(a: float64) -> result + + enum e1 { a, b, c } + enum-error1: func(a: float64) -> result + + record e2 { line: u32, column: u32 } + record-error2: func(a: float64) -> result + + variant e3 { e1(e1), e2(e2) } + variant-error3: func(a: float64) -> result + } + }" +}); + +#[test] +fn run() -> Result<(), Error> { + let engine = engine(); + let component = Component::new( + &engine, + r#" + (component + (import "imports" (instance $i + (export "empty-error" (func (param "a" float64) (result (result float64)))) + )) + (core module $libc + (memory (export "memory") 1) + (func (export "realloc") (param i32 i32 i32 i32) (result i32) + unreachable) + ) + (core instance $libc (instantiate $libc)) + (core module $m + (import "" "core_empty_error" (func (param f64) (result i32))) + (export "core_empty_error" (func 0)) + ) + (core func $core_empty_error + (canon lower (func $i "empty-error") (memory $libc "memory")) + ) + (core instance $i (instantiate $m + (with "" (instance (export "core_empty_error" (func $core_empty_error)))) + )) + (func $f_empty_error + (export "empty-error") + (param "a" float64) + (result (result float64)) + (canon lift (core func $i "empty_error") (memory $libc "memory")) + ) + ) + "#, + )?; + + #[derive(Default)] + struct MyImports {} + + impl imports::Imports for MyImports { + fn empty_error(&mut self, a: f64) -> Result, Error> { + if a == 0.0 { + Ok(Ok(a)) + } else if a == 1.0 { + Ok(Err(())) + } else { + Err(anyhow!("empty_error: trap")) + } + } + fn string_error(&mut self, a: f64) -> Result, Error> { + todo!() + } + fn enum_error1(&mut self, a: f64) -> Result, Error> { + todo!() + } + fn record_error2(&mut self, a: f64) -> Result, Error> { + todo!() + } + fn variant_error3(&mut self, a: f64) -> Result, Error> { + todo!() + } + } + + let mut linker = Linker::new(&engine); + imports::add_to_linker(&mut linker, |f: &mut MyImports| f)?; + + let mut store = Store::new(&engine, MyImports::default()); + let (results, _) = ResultPlayground::instantiate(&mut store, &component, &linker)?; + + assert_eq!( + results + .empty_error(&mut store, 0.0) + .expect("no trap") + .expect("no error returned"), + 0.0 + ); + + results + .empty_error(&mut store, 1.0) + .expect("no trap") + .err() + .expect("() error returned"); + + results.empty_error(&mut store, 2.0).err().expect("trap"); + + Ok(()) +} From b757adb880bd23b53fb3ed8a2faae35f5d9a500f Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 7 Dec 2022 17:04:44 -0800 Subject: [PATCH 03/10] cut out all the more complex test cases until i get this one working --- tests/all/component_model/bindgen/results.rs | 117 +++++++------------ 1 file changed, 44 insertions(+), 73 deletions(-) diff --git a/tests/all/component_model/bindgen/results.rs b/tests/all/component_model/bindgen/results.rs index 7a58ce6b3125..0aa533f63218 100644 --- a/tests/all/component_model/bindgen/results.rs +++ b/tests/all/component_model/bindgen/results.rs @@ -5,45 +5,27 @@ use wasmtime::{ Store, }; -wasmtime::component::bindgen!({ - inline: " +mod empty_error { + use super::*; + wasmtime::component::bindgen!({ + inline: " world result-playground { import imports: interface { empty-error: func(a: float64) -> result - string-error: func(a: float64) -> result - - enum e1 { a, b, c } - enum-error1: func(a: float64) -> result - - record e2 { line: u32, column: u32 } - record-error2: func(a: float64) -> result - - variant e3 { e1(e1), e2(e2) } - variant-error3: func(a: float64) -> result } default export interface { empty-error: func(a: float64) -> result - string-error: func(a: float64) -> result - - enum e1 { a, b, c } - enum-error1: func(a: float64) -> result - - record e2 { line: u32, column: u32 } - record-error2: func(a: float64) -> result - - variant e3 { e1(e1), e2(e2) } - variant-error3: func(a: float64) -> result } }" -}); - -#[test] -fn run() -> Result<(), Error> { - let engine = engine(); - let component = Component::new( - &engine, - r#" + }); + + #[test] + fn run() -> Result<(), Error> { + let engine = engine(); + let component = Component::new( + &engine, + r#" (component (import "imports" (instance $i (export "empty-error" (func (param "a" float64) (result (result float64)))) @@ -72,56 +54,45 @@ fn run() -> Result<(), Error> { ) ) "#, - )?; - - #[derive(Default)] - struct MyImports {} - - impl imports::Imports for MyImports { - fn empty_error(&mut self, a: f64) -> Result, Error> { - if a == 0.0 { - Ok(Ok(a)) - } else if a == 1.0 { - Ok(Err(())) - } else { - Err(anyhow!("empty_error: trap")) + )?; + + #[derive(Default)] + struct MyImports {} + + impl imports::Imports for MyImports { + fn empty_error(&mut self, a: f64) -> Result, Error> { + if a == 0.0 { + Ok(Ok(a)) + } else if a == 1.0 { + Ok(Err(())) + } else { + Err(anyhow!("empty_error: trap")) + } } } - fn string_error(&mut self, a: f64) -> Result, Error> { - todo!() - } - fn enum_error1(&mut self, a: f64) -> Result, Error> { - todo!() - } - fn record_error2(&mut self, a: f64) -> Result, Error> { - todo!() - } - fn variant_error3(&mut self, a: f64) -> Result, Error> { - todo!() - } - } - let mut linker = Linker::new(&engine); - imports::add_to_linker(&mut linker, |f: &mut MyImports| f)?; + let mut linker = Linker::new(&engine); + imports::add_to_linker(&mut linker, |f: &mut MyImports| f)?; + + let mut store = Store::new(&engine, MyImports::default()); + let (results, _) = ResultPlayground::instantiate(&mut store, &component, &linker)?; - let mut store = Store::new(&engine, MyImports::default()); - let (results, _) = ResultPlayground::instantiate(&mut store, &component, &linker)?; + assert_eq!( + results + .empty_error(&mut store, 0.0) + .expect("no trap") + .expect("no error returned"), + 0.0 + ); - assert_eq!( results - .empty_error(&mut store, 0.0) + .empty_error(&mut store, 1.0) .expect("no trap") - .expect("no error returned"), - 0.0 - ); + .err() + .expect("() error returned"); - results - .empty_error(&mut store, 1.0) - .expect("no trap") - .err() - .expect("() error returned"); + results.empty_error(&mut store, 2.0).err().expect("trap"); - results.empty_error(&mut store, 2.0).err().expect("trap"); - - Ok(()) + Ok(()) + } } From 731a4fdf61a6a8a82ccd1f774c4b3e886cc5d37c Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 7 Dec 2022 17:34:10 -0800 Subject: [PATCH 04/10] add macro parsing for the trappable error type config --- crates/component-macro/src/bindgen.rs | 23 ++++++++++++++++++-- crates/wit-bindgen/src/lib.rs | 1 - tests/all/component_model/bindgen/results.rs | 4 +++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/crates/component-macro/src/bindgen.rs b/crates/component-macro/src/bindgen.rs index b132cfdf17b2..47342f080304 100644 --- a/crates/component-macro/src/bindgen.rs +++ b/crates/component-macro/src/bindgen.rs @@ -2,8 +2,7 @@ use proc_macro2::{Span, TokenStream}; use std::path::{Path, PathBuf}; use syn::parse::{Error, Parse, ParseStream, Result}; use syn::punctuated::Punctuated; -use syn::token; -use syn::Token; +use syn::{braced, token, Ident, Token}; use wasmtime_wit_bindgen::Opts; use wit_parser::World; @@ -68,6 +67,7 @@ impl Parse for Config { } Opt::Tracing(val) => ret.opts.tracing = val, Opt::Async(val) => ret.opts.async_ = val, + Opt::TrappableErrorType(val) => ret.opts.trappable_error_type = val, } } } else { @@ -99,6 +99,7 @@ mod kw { syn::custom_keyword!(path); syn::custom_keyword!(inline); syn::custom_keyword!(tracing); + syn::custom_keyword!(trappable_error_type); } enum Opt { @@ -106,6 +107,7 @@ enum Opt { Inline(Span, World), Tracing(bool), Async(bool), + TrappableErrorType(Vec<(String, String, String)>), } impl Parse for Opt { @@ -130,8 +132,25 @@ impl Parse for Opt { input.parse::()?; input.parse::()?; Ok(Opt::Async(input.parse::()?.value)) + } else if l.peek(kw::trappable_error_type) { + input.parse::()?; + input.parse::()?; + let contents; + let _lbrace = braced!(contents in input); + let fields: Punctuated<(String, String, String), Token![,]> = + contents.parse_terminated(trappable_error_field_parse)?; + Ok(Opt::TrappableErrorType(fields.into_iter().collect())) } else { Err(l.error()) } } } + +fn trappable_error_field_parse(input: ParseStream<'_>) -> Result<(String, String, String)> { + let interface = input.parse::()?.to_string(); + input.parse::()?; + let type_ = input.parse::()?.to_string(); + input.parse::()?; + let rust_type = input.parse::()?.to_string(); + Ok((interface, type_, rust_type)) +} diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index d83f37f3528a..0f664fdc7a9d 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -1,6 +1,5 @@ use crate::rust::{to_rust_ident, RustGenerator, TypeMode}; use crate::types::{TypeInfo, Types}; -use anyhow::{anyhow, Result}; use heck::*; use std::collections::BTreeMap; use std::fmt::Write as _; diff --git a/tests/all/component_model/bindgen/results.rs b/tests/all/component_model/bindgen/results.rs index 0aa533f63218..b9eba701310a 100644 --- a/tests/all/component_model/bindgen/results.rs +++ b/tests/all/component_model/bindgen/results.rs @@ -17,7 +17,9 @@ mod empty_error { default export interface { empty-error: func(a: float64) -> result } - }" + }", + // This doesn't actually do anything, just showing the macro parses it correctly: + trappable_error_type: { imports::e: TrappableE } }); #[test] From 71cfe822e17d23e32c0eb7f45e73487175fb91bc Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Thu, 8 Dec 2022 16:41:27 -0800 Subject: [PATCH 05/10] runtime result tests works for an empty and a string error type --- tests/all/component_model/bindgen/results.rs | 134 +++++++++++++++++-- 1 file changed, 125 insertions(+), 9 deletions(-) diff --git a/tests/all/component_model/bindgen/results.rs b/tests/all/component_model/bindgen/results.rs index b9eba701310a..b53f08d17ae0 100644 --- a/tests/all/component_model/bindgen/results.rs +++ b/tests/all/component_model/bindgen/results.rs @@ -1,4 +1,4 @@ -use super::engine; +use super::{super::REALLOC_AND_FREE, engine}; use anyhow::{anyhow, Error}; use wasmtime::{ component::{Component, Linker}, @@ -18,8 +18,6 @@ mod empty_error { empty-error: func(a: float64) -> result } }", - // This doesn't actually do anything, just showing the macro parses it correctly: - trappable_error_type: { imports::e: TrappableE } }); #[test] @@ -34,25 +32,28 @@ mod empty_error { )) (core module $libc (memory (export "memory") 1) - (func (export "realloc") (param i32 i32 i32 i32) (result i32) - unreachable) ) (core instance $libc (instantiate $libc)) (core module $m - (import "" "core_empty_error" (func (param f64) (result i32))) - (export "core_empty_error" (func 0)) + (import "" "core_empty_error" (func $f (param f64 i32))) + (import "libc" "memory" (memory 0)) + (func (export "core_empty_error_export") (param f64) (result i32) + (call $f (local.get 0) (i32.const 8)) + (i32.const 8) + ) ) (core func $core_empty_error (canon lower (func $i "empty-error") (memory $libc "memory")) ) (core instance $i (instantiate $m (with "" (instance (export "core_empty_error" (func $core_empty_error)))) + (with "libc" (instance $libc)) )) (func $f_empty_error (export "empty-error") (param "a" float64) (result (result float64)) - (canon lift (core func $i "empty_error") (memory $libc "memory")) + (canon lift (core func $i "core_empty_error_export") (memory $libc "memory")) ) ) "#, @@ -93,7 +94,122 @@ mod empty_error { .err() .expect("() error returned"); - results.empty_error(&mut store, 2.0).err().expect("trap"); + let e = results.empty_error(&mut store, 2.0).err().expect("trap"); + assert_eq!( + format!("{}", e.source().expect("trap message is stored in source")), + "empty_error: trap" + ); + + Ok(()) + } +} + +mod string_error { + use super::*; + wasmtime::component::bindgen!({ + inline: " + world result-playground { + import imports: interface { + string-error: func(a: float64) -> result + } + + default export interface { + string-error: func(a: float64) -> result + } + }", + }); + + #[test] + fn run() -> Result<(), Error> { + let engine = engine(); + let component = Component::new( + &engine, + format!( + r#" + (component + (import "imports" (instance $i + (export "string-error" (func (param "a" float64) (result (result float64 (error string))))) + )) + (core module $libc + (memory (export "memory") 1) + {REALLOC_AND_FREE} + ) + (core instance $libc (instantiate $libc)) + (core module $m + (import "" "core_string_error" (func $f (param f64 i32))) + (import "libc" "memory" (memory 0)) + (import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32))) + (func (export "core_string_error_export") (param f64) (result i32) + (local $retptr i32) + (local.set $retptr + (call $realloc + (i32.const 0) + (i32.const 0) + (i32.const 4) + (i32.const 16))) + (call $f (local.get 0) (local.get $retptr)) + (local.get $retptr) + ) + ) + (core func $core_string_error + (canon lower (func $i "string-error") (memory $libc "memory") (realloc (func $libc "realloc"))) + ) + (core instance $i (instantiate $m + (with "" (instance (export "core_string_error" (func $core_string_error)))) + (with "libc" (instance $libc)) + )) + (func $f_string_error + (export "string-error") + (param "a" float64) + (result (result float64 (error string))) + (canon lift (core func $i "core_string_error_export") (memory $libc "memory")) + ) + ) + "# + ), + )?; + + #[derive(Default)] + struct MyImports {} + + impl imports::Imports for MyImports { + fn string_error(&mut self, a: f64) -> Result, Error> { + if a == 0.0 { + Ok(Ok(a)) + } else if a == 1.0 { + Ok(Err("string_error: error".to_owned())) + } else { + Err(anyhow!("string_error: trap")) + } + } + } + + let mut linker = Linker::new(&engine); + imports::add_to_linker(&mut linker, |f: &mut MyImports| f)?; + + let mut store = Store::new(&engine, MyImports::default()); + let (results, _) = ResultPlayground::instantiate(&mut store, &component, &linker)?; + + assert_eq!( + results + .string_error(&mut store, 0.0) + .expect("no trap") + .expect("no error returned"), + 0.0 + ); + + let e = results + .string_error(&mut store, 1.0) + .expect("no trap") + .err() + .expect("error returned"); + assert_eq!(e, "string_error: error"); + + let e = results.string_error(&mut store, 2.0).err().expect("trap"); + assert_eq!( + format!("{}", e.source().expect("trap message is stored in source")), + "string_error: trap" + ); Ok(()) } From 1a076e7f401c4309b4cbccfca7f8cbb701a20976 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Mon, 12 Dec 2022 12:14:33 -0800 Subject: [PATCH 06/10] debugging: macro is broken because interfaces dont have names??? --- crates/wit-bindgen/src/lib.rs | 26 +++++ tests/all/component_model/bindgen/results.rs | 114 +++++++++++++++++++ 2 files changed, 140 insertions(+) diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index 0f664fdc7a9d..1c6ad39f6ead 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -324,6 +324,27 @@ impl Wasmtime { &'a self, iface: &'a Interface, ) -> impl Iterator + 'a { + println!("TRAPPABLE ERROR TYPES {:?}", self.opts.trappable_error_type); + println!("{:?}", iface.name); + + println!( + "{:?}", + self.opts + .trappable_error_type + .iter() + .filter(|(interface_name, _, _)| iface.name == *interface_name) + .collect::>() + ); + println!( + "{:?}", + self.opts + .trappable_error_type + .iter() + .filter(|(interface_name, _, _)| iface.name == *interface_name) + .map(|(_, tn, _)| (tn, iface.type_lookup.get(tn))) + .collect::>() + ); + self.opts .trappable_error_type .iter() @@ -1125,6 +1146,11 @@ impl<'a> InterfaceGenerator<'a> { ) } let abi_type = self.param_name(*wit_type); + + println!( + "TRAPPABLE TYPE {}::{wit_typename}({abi_type}): {trappable_type}", + self.iface.name + ); uwriteln!( self.src, " diff --git a/tests/all/component_model/bindgen/results.rs b/tests/all/component_model/bindgen/results.rs index b53f08d17ae0..7ad11402b822 100644 --- a/tests/all/component_model/bindgen/results.rs +++ b/tests/all/component_model/bindgen/results.rs @@ -214,3 +214,117 @@ mod string_error { Ok(()) } } + +mod enum_error { + use super::*; + wasmtime::component::bindgen!({ + inline: " + world result-playground { + import imports: interface { + enum e1 { a, b, c } + enum-error: func(a: float64) -> result + } + + default export interface { + enum e1 { a, b, c } + enum-error: func(a: float64) -> result + } + }", + trappable_error_type: { imports::e1: TrappableE1 } + }); + + #[test] + fn run() -> Result<(), Error> { + let engine = engine(); + let component = Component::new( + &engine, + format!( + r#" + (component + (import "imports" (instance $i + (export "enum-error" (func (param "a" float64) (result (result float64 (error (enum "a" "b" "c")))))) + )) + (core module $libc + (memory (export "memory") 1) + {REALLOC_AND_FREE} + ) + (core instance $libc (instantiate $libc)) + (core module $m + (import "" "core_enum_error" (func $f (param f64 i32))) + (import "libc" "memory" (memory 0)) + (import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32))) + (func (export "core_enum_error_export") (param f64) (result i32) + (local $retptr i32) + (local.set $retptr + (call $realloc + (i32.const 0) + (i32.const 0) + (i32.const 4) + (i32.const 16))) + (call $f (local.get 0) (local.get $retptr)) + (local.get $retptr) + ) + ) + (core func $core_enum_error + (canon lower (func $i "enum-error") (memory $libc "memory") (realloc (func $libc "realloc"))) + ) + (core instance $i (instantiate $m + (with "" (instance (export "core_enum_error" (func $core_enum_error)))) + (with "libc" (instance $libc)) + )) + (func $f_enum_error + (export "enum-error") + (param "a" float64) + (result (result float64 (error (enum "a" "b" "c")))) + (canon lift (core func $i "core_enum_error_export") (memory $libc "memory")) + ) + ) + "# + ), + )?; + + #[derive(Default)] + struct MyImports {} + + impl imports::Imports for MyImports { + fn enum_error(&mut self, a: f64) -> Result, Error> { + if a == 0.0 { + Ok(Ok(a)) + } else if a == 1.0 { + Ok(Err(imports::E1::A)) + } else { + Err(anyhow!("enum_error: trap")) + } + } + } + + let mut linker = Linker::new(&engine); + imports::add_to_linker(&mut linker, |f: &mut MyImports| f)?; + + let mut store = Store::new(&engine, MyImports::default()); + let (results, _) = ResultPlayground::instantiate(&mut store, &component, &linker)?; + + assert_eq!( + results + .enum_error(&mut store, 0.0) + .expect("no trap") + .expect("no error returned"), + 0.0 + ); + + let e = results + .enum_error(&mut store, 1.0) + .expect("no trap") + .err() + .expect("error returned"); + assert_eq!(e, enum_error::E1::A); + + let e = results.enum_error(&mut store, 2.0).err().expect("trap"); + assert_eq!( + format!("{}", e.source().expect("trap message is stored in source")), + "enum_error: trap" + ); + + Ok(()) + } +} From 1c4caf14161fd260c2206ba8170aa9a47a97098a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 13 Dec 2022 14:18:18 -0800 Subject: [PATCH 07/10] thats how you name interfaces --- crates/wit-bindgen/src/lib.rs | 21 -------------------- tests/all/component_model/bindgen/results.rs | 18 ++++++++--------- 2 files changed, 9 insertions(+), 30 deletions(-) diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index 1c6ad39f6ead..554c355db886 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -324,27 +324,6 @@ impl Wasmtime { &'a self, iface: &'a Interface, ) -> impl Iterator + 'a { - println!("TRAPPABLE ERROR TYPES {:?}", self.opts.trappable_error_type); - println!("{:?}", iface.name); - - println!( - "{:?}", - self.opts - .trappable_error_type - .iter() - .filter(|(interface_name, _, _)| iface.name == *interface_name) - .collect::>() - ); - println!( - "{:?}", - self.opts - .trappable_error_type - .iter() - .filter(|(interface_name, _, _)| iface.name == *interface_name) - .map(|(_, tn, _)| (tn, iface.type_lookup.get(tn))) - .collect::>() - ); - self.opts .trappable_error_type .iter() diff --git a/tests/all/component_model/bindgen/results.rs b/tests/all/component_model/bindgen/results.rs index 7ad11402b822..10f9bd2ce259 100644 --- a/tests/all/component_model/bindgen/results.rs +++ b/tests/all/component_model/bindgen/results.rs @@ -219,12 +219,12 @@ mod enum_error { use super::*; wasmtime::component::bindgen!({ inline: " + interface imports { + enum e1 { a, b, c } + enum-error: func(a: float64) -> result + } world result-playground { - import imports: interface { - enum e1 { a, b, c } - enum-error: func(a: float64) -> result - } - + import imports: imports default export interface { enum e1 { a, b, c } enum-error: func(a: float64) -> result @@ -287,13 +287,13 @@ mod enum_error { struct MyImports {} impl imports::Imports for MyImports { - fn enum_error(&mut self, a: f64) -> Result, Error> { + fn enum_error(&mut self, a: f64) -> Result { if a == 0.0 { - Ok(Ok(a)) + Ok(a) } else if a == 1.0 { - Ok(Err(imports::E1::A)) + Err(imports::E1::A)? } else { - Err(anyhow!("enum_error: trap")) + Err(imports::TrappableE1::trap(anyhow!("enum_error: trap"))) } } } From 4ab764be66d680ad972938a6f92a72a2af88531e Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 13 Dec 2022 14:51:53 -0800 Subject: [PATCH 08/10] record error and variant error work --- tests/all/component_model/bindgen/results.rs | 250 +++++++++++++++++++ 1 file changed, 250 insertions(+) diff --git a/tests/all/component_model/bindgen/results.rs b/tests/all/component_model/bindgen/results.rs index 10f9bd2ce259..155a8e60226a 100644 --- a/tests/all/component_model/bindgen/results.rs +++ b/tests/all/component_model/bindgen/results.rs @@ -328,3 +328,253 @@ mod enum_error { Ok(()) } } + +mod record_error { + use super::*; + wasmtime::component::bindgen!({ + inline: " + interface imports { + record e2 { line: u32, col: u32 } + record-error: func(a: float64) -> result + } + world result-playground { + import imports: imports + default export interface { + record e2 { line: u32, col: u32 } + record-error: func(a: float64) -> result + } + }", + trappable_error_type: { imports::e2: TrappableE2 } + }); + + #[test] + fn run() -> Result<(), Error> { + let engine = engine(); + let component = Component::new( + &engine, + format!( + r#" + (component + (import "imports" (instance $i + (export "record-error" (func (param "a" float64) (result (result float64 (error (record (field "line" u32) (field "col" u32))))))) + )) + (core module $libc + (memory (export "memory") 1) + {REALLOC_AND_FREE} + ) + (core instance $libc (instantiate $libc)) + (core module $m + (import "" "core_record_error" (func $f (param f64 i32))) + (import "libc" "memory" (memory 0)) + (import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32))) + (func (export "core_record_error_export") (param f64) (result i32) + (local $retptr i32) + (local.set $retptr + (call $realloc + (i32.const 0) + (i32.const 0) + (i32.const 4) + (i32.const 16))) + (call $f (local.get 0) (local.get $retptr)) + (local.get $retptr) + ) + ) + (core func $core_record_error + (canon lower (func $i "record-error") (memory $libc "memory") (realloc (func $libc "realloc"))) + ) + (core instance $i (instantiate $m + (with "" (instance (export "core_record_error" (func $core_record_error)))) + (with "libc" (instance $libc)) + )) + (func $f_record_error + (export "record-error") + (param "a" float64) + (result (result float64 (error (record (field "line" u32) (field "col" u32))))) + (canon lift (core func $i "core_record_error_export") (memory $libc "memory")) + ) + ) + "# + ), + )?; + + #[derive(Default)] + struct MyImports {} + + impl imports::Imports for MyImports { + fn record_error(&mut self, a: f64) -> Result { + if a == 0.0 { + Ok(a) + } else if a == 1.0 { + Err(imports::E2 { + line: 420, + col: 1312, + })? + } else { + Err(imports::TrappableE2::trap(anyhow!("record_error: trap"))) + } + } + } + + let mut linker = Linker::new(&engine); + imports::add_to_linker(&mut linker, |f: &mut MyImports| f)?; + + let mut store = Store::new(&engine, MyImports::default()); + let (results, _) = ResultPlayground::instantiate(&mut store, &component, &linker)?; + + assert_eq!( + results + .record_error(&mut store, 0.0) + .expect("no trap") + .expect("no error returned"), + 0.0 + ); + + let e = results + .record_error(&mut store, 1.0) + .expect("no trap") + .err() + .expect("error returned"); + assert!(matches!( + e, + record_error::E2 { + line: 420, + col: 1312 + } + )); + + let e = results.record_error(&mut store, 2.0).err().expect("trap"); + assert_eq!( + format!("{}", e.source().expect("trap message is stored in source")), + "record_error: trap" + ); + + Ok(()) + } +} + +mod variant_error { + use super::*; + wasmtime::component::bindgen!({ + inline: " + interface imports { + enum e1 { a, b, c } + record e2 { line: u32, col: u32 } + variant e3 { E1(e1), E2(e2) } + variant-error: func(a: float64) -> result + } + world result-playground { + import imports: imports + default export interface { + enum e1 { a, b, c } + record e2 { line: u32, col: u32 } + variant e3 { E1(e1), E2(e2) } + variant-error: func(a: float64) -> result + } + }", + trappable_error_type: { imports::e3: TrappableE3 } + }); + + #[test] + fn run() -> Result<(), Error> { + let engine = engine(); + let component = Component::new( + &engine, + format!( + r#" + (component + (import "imports" (instance $i + (export "variant-error" (func (param "a" float64) (result (result float64 (error (variant (case "E1" (enum "a" "b" "c")) (case "E2" (record (field "line" u32) (field "col" u32))))))))) + )) + (core module $libc + (memory (export "memory") 1) + {REALLOC_AND_FREE} + ) + (core instance $libc (instantiate $libc)) + (core module $m + (import "" "core_variant_error" (func $f (param f64 i32))) + (import "libc" "memory" (memory 0)) + (import "libc" "realloc" (func $realloc (param i32 i32 i32 i32) (result i32))) + (func (export "core_variant_error_export") (param f64) (result i32) + (local $retptr i32) + (local.set $retptr + (call $realloc + (i32.const 0) + (i32.const 0) + (i32.const 4) + (i32.const 16))) + (call $f (local.get 0) (local.get $retptr)) + (local.get $retptr) + ) + ) + (core func $core_variant_error + (canon lower (func $i "variant-error") (memory $libc "memory") (realloc (func $libc "realloc"))) + ) + (core instance $i (instantiate $m + (with "" (instance (export "core_variant_error" (func $core_variant_error)))) + (with "libc" (instance $libc)) + )) + (func $f_variant_error + (export "variant-error") + (param "a" float64) + (result (result float64 (error (variant (case "E1" (enum "a" "b" "c")) (case "E2"(record (field "line" u32) (field "col" u32))))))) + (canon lift (core func $i "core_variant_error_export") (memory $libc "memory")) + ) + ) + "# + ), + )?; + + #[derive(Default)] + struct MyImports {} + + impl imports::Imports for MyImports { + fn variant_error(&mut self, a: f64) -> Result { + if a == 0.0 { + Ok(a) + } else if a == 1.0 { + Err(imports::E3::E2(imports::E2 { + line: 420, + col: 1312, + }))? + } else { + Err(imports::TrappableE3::trap(anyhow!("variant_error: trap"))) + } + } + } + + let mut linker = Linker::new(&engine); + imports::add_to_linker(&mut linker, |f: &mut MyImports| f)?; + + let mut store = Store::new(&engine, MyImports::default()); + let (results, _) = ResultPlayground::instantiate(&mut store, &component, &linker)?; + + assert_eq!( + results + .variant_error(&mut store, 0.0) + .expect("no trap") + .expect("no error returned"), + 0.0 + ); + + let e = results + .variant_error(&mut store, 1.0) + .expect("no trap") + .err() + .expect("error returned"); + assert!(matches!( + e, + variant_error::E3::E2(variant_error::E2 { + line: 420, + col: 1312 + }) + )); + + let e = results.variant_error(&mut store, 2.0).err().expect("trap"); + assert_eq!( + format!("{}", e.source().expect("trap message is stored in source")), + "variant_error: trap" + ); + + Ok(()) + } +} From 363651f323c838be21e064533939f19dab528334 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Tue, 13 Dec 2022 15:11:00 -0800 Subject: [PATCH 09/10] show a concrete trap type, remove debug --- crates/wit-bindgen/src/lib.rs | 4 --- tests/all/component_model/bindgen/results.rs | 28 ++++++++++++++++++-- 2 files changed, 26 insertions(+), 6 deletions(-) diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index 554c355db886..b17373d5b95b 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -1126,10 +1126,6 @@ impl<'a> InterfaceGenerator<'a> { } let abi_type = self.param_name(*wit_type); - println!( - "TRAPPABLE TYPE {}::{wit_typename}({abi_type}): {trappable_type}", - self.iface.name - ); uwriteln!( self.src, " diff --git a/tests/all/component_model/bindgen/results.rs b/tests/all/component_model/bindgen/results.rs index 155a8e60226a..84c906d8e86a 100644 --- a/tests/all/component_model/bindgen/results.rs +++ b/tests/all/component_model/bindgen/results.rs @@ -283,6 +283,28 @@ mod enum_error { ), )?; + // You can create concrete trap types which make it all the way out to the + // host caller, via downcast_ref below. + #[derive(Debug)] + struct MyTrap; + + impl std::fmt::Display for MyTrap { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{:?}", self) + } + } + impl std::error::Error for MyTrap {} + + // It is possible to define From impls that target these generated trappable + // types. This allows you to integrate libraries with other error types, or + // use your own more descriptive error types, and use ? to convert them at + // their throw site. + impl From for imports::TrappableE1 { + fn from(t: MyTrap) -> imports::TrappableE1 { + imports::TrappableE1::trap(anyhow!(t)) + } + } + #[derive(Default)] struct MyImports {} @@ -293,7 +315,7 @@ mod enum_error { } else if a == 1.0 { Err(imports::E1::A)? } else { - Err(imports::TrappableE1::trap(anyhow!("enum_error: trap"))) + Err(MyTrap)? } } } @@ -322,8 +344,10 @@ mod enum_error { let e = results.enum_error(&mut store, 2.0).err().expect("trap"); assert_eq!( format!("{}", e.source().expect("trap message is stored in source")), - "enum_error: trap" + "MyTrap" ); + e.downcast_ref::() + .expect("downcast trap to concrete MyTrap type"); Ok(()) } From f848fd9a531ec2ec379f4e1e5b49791025470a4a Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 14 Dec 2022 10:08:17 -0800 Subject: [PATCH 10/10] delete clap annotations from wit-bindgen crate these are not used - clap isnt even an optional dep here - but were a holdover from the old home --- crates/wit-bindgen/src/lib.rs | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/crates/wit-bindgen/src/lib.rs b/crates/wit-bindgen/src/lib.rs index b17373d5b95b..393cc3b6fabf 100644 --- a/crates/wit-bindgen/src/lib.rs +++ b/crates/wit-bindgen/src/lib.rs @@ -40,23 +40,18 @@ struct Exports { } #[derive(Default, Debug, Clone)] -#[cfg_attr(feature = "clap", derive(clap::Args))] pub struct Opts { /// Whether or not `rustfmt` is executed to format generated code. - #[cfg_attr(feature = "clap", arg(long))] pub rustfmt: bool, /// Whether or not to emit `tracing` macro calls on function entry/exit. - #[cfg_attr(feature = "clap", arg(long))] pub tracing: bool, /// Whether or not to use async rust functions and traits. - #[cfg_attr(feature = "clap", arg(long = "async"))] pub async_: bool, /// For a given wit interface and type name, generate a "trappable error type" /// of the following Rust type name - #[cfg_attr(feature = "clap", arg(long = "trappable_error_type"), clap(value_name="INTERFACE:TYPE=RUSTTYPE", value_parser = parse_trappable_error))] pub trappable_error_type: Vec<(String, String, String)>, } @@ -68,18 +63,6 @@ impl Opts { } } -#[cfg(feature = "clap")] -// Argument looks like `INTERFACE:TYPE=RUSTTYPE` -fn parse_trappable_error(s: &str) -> Result<(String, String, String)> { - let (interface, after_colon) = s - .split_once(':') - .ok_or_else(|| anyhow!("expected `:` separator"))?; - let (ty, rustty) = after_colon - .split_once('=') - .ok_or_else(|| anyhow!("expected `=` separator"))?; - Ok((interface, ty, rustty)) -} - impl Wasmtime { fn generate(&mut self, world: &World) -> String { for (name, import) in world.imports.iter() {