better error trait design
This commit is contained in:
@@ -1,57 +0,0 @@
|
|||||||
use crate::names::Names;
|
|
||||||
use heck::SnakeCase;
|
|
||||||
use proc_macro2::TokenStream;
|
|
||||||
use quote::{format_ident, quote};
|
|
||||||
use std::collections::HashSet;
|
|
||||||
use witx::{Document, TypeRef};
|
|
||||||
|
|
||||||
/// The context struct needs to implement a trait for converting memory and value errors into the
|
|
||||||
/// witx doc's error types.
|
|
||||||
///
|
|
||||||
// XXX im rethinking this. maybe each error type should impl
|
|
||||||
// pub trait WitxErrorType {
|
|
||||||
// type Context;
|
|
||||||
// fn is_success(&self) -> bool;
|
|
||||||
// fn from_memory_error(memory_error: MemoryError, ctx: &mut Context) -> Self;
|
|
||||||
// fn from_value_error(value_error: GuestValueError, ctx: &mut Context) -> Self;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// where Context is mapped to their wasi ctx.
|
|
||||||
// It seems less "magic" to leave that impl up to the user, and the error message may be simpler?
|
|
||||||
//
|
|
||||||
pub fn define_error_trait(names: &Names, doc: &Document) -> TokenStream {
|
|
||||||
// All non-anonymous first return types are used to pass errors.
|
|
||||||
let error_typenames = doc
|
|
||||||
.modules()
|
|
||||||
.flat_map(|m| {
|
|
||||||
m.funcs()
|
|
||||||
.filter_map(|f| {
|
|
||||||
f.results.get(0).and_then(|r| match &r.tref {
|
|
||||||
TypeRef::Name(nt) => Some(nt.name.clone()),
|
|
||||||
_ => None,
|
|
||||||
})
|
|
||||||
})
|
|
||||||
.collect::<HashSet<witx::Id>>()
|
|
||||||
})
|
|
||||||
.collect::<HashSet<witx::Id>>();
|
|
||||||
|
|
||||||
let methods = error_typenames.iter().map(|typename| {
|
|
||||||
let tname = names.type_(typename);
|
|
||||||
let methodfragment = typename.as_str().to_snake_case();
|
|
||||||
let success = format_ident!("success_to_{}", methodfragment);
|
|
||||||
let memory_error = format_ident!("memory_error_to_{}", methodfragment);
|
|
||||||
let value_error = format_ident!("value_error_to_{}", methodfragment);
|
|
||||||
|
|
||||||
quote! {
|
|
||||||
fn #success(&mut self) -> #tname;
|
|
||||||
fn #memory_error(&mut self, err: ::memory::MemoryError) -> #tname;
|
|
||||||
fn #value_error(&mut self, err: ::memory::GuestValueError) -> #tname;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
quote!(
|
|
||||||
pub trait WitxErrorConversion {
|
|
||||||
#(#methods)*
|
|
||||||
}
|
|
||||||
)
|
|
||||||
}
|
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
mod errors;
|
|
||||||
mod funcs;
|
mod funcs;
|
||||||
mod names;
|
mod names;
|
||||||
mod parse;
|
mod parse;
|
||||||
@@ -10,7 +9,6 @@ use proc_macro::TokenStream;
|
|||||||
use proc_macro2::TokenStream as TokenStream2;
|
use proc_macro2::TokenStream as TokenStream2;
|
||||||
use quote::quote;
|
use quote::quote;
|
||||||
|
|
||||||
use errors::define_error_trait;
|
|
||||||
use funcs::define_func;
|
use funcs::define_func;
|
||||||
use names::Names;
|
use names::Names;
|
||||||
use types::define_datatype;
|
use types::define_datatype;
|
||||||
@@ -39,12 +37,9 @@ pub fn from_witx(args: TokenStream) -> TokenStream {
|
|||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
let error_trait = define_error_trait(&names, &doc);
|
|
||||||
|
|
||||||
TokenStream::from(quote!(
|
TokenStream::from(quote!(
|
||||||
mod types {
|
mod types {
|
||||||
#(#types)*
|
#(#types)*
|
||||||
#error_trait
|
|
||||||
}
|
}
|
||||||
#(#modules)*
|
#(#modules)*
|
||||||
))
|
))
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
use crate::{GuestPtr, GuestPtrMut};
|
use crate::{GuestPtr, GuestPtrMut, MemoryError};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
pub trait GuestType: Sized {
|
pub trait GuestType: Sized {
|
||||||
@@ -66,3 +66,10 @@ macro_rules! builtin_copy {
|
|||||||
|
|
||||||
// These definitions correspond to all the witx BuiltinType variants that are Copy:
|
// These definitions correspond to all the witx BuiltinType variants that are Copy:
|
||||||
builtin_copy!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, usize, char);
|
builtin_copy!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, usize, char);
|
||||||
|
|
||||||
|
pub trait GuestError {
|
||||||
|
type Context;
|
||||||
|
fn is_success(&self) -> bool;
|
||||||
|
fn from_memory_error(memory_error: MemoryError, ctx: &mut Self::Context) -> Self;
|
||||||
|
fn from_value_error(value_error: GuestValueError, ctx: &mut Self::Context) -> Self;
|
||||||
|
}
|
||||||
|
|||||||
@@ -3,6 +3,6 @@ mod guest_type;
|
|||||||
mod memory;
|
mod memory;
|
||||||
mod region;
|
mod region;
|
||||||
|
|
||||||
pub use guest_type::{GuestType, GuestTypeClone, GuestTypeCopy, GuestValueError};
|
pub use guest_type::{GuestError, GuestType, GuestTypeClone, GuestTypeCopy, GuestValueError};
|
||||||
pub use memory::{GuestMemory, GuestPtr, GuestPtrMut, MemoryError};
|
pub use memory::{GuestMemory, GuestPtr, GuestPtrMut, MemoryError};
|
||||||
pub use region::Region;
|
pub use region::Region;
|
||||||
|
|||||||
30
src/lib.rs
30
src/lib.rs
@@ -1,18 +1,30 @@
|
|||||||
pub mod test {
|
pub mod test {
|
||||||
|
// FIXME: parameterize macro on what ctx type is used here
|
||||||
generate::from_witx!("test.witx");
|
generate::from_witx!("test.witx");
|
||||||
|
|
||||||
pub struct WasiCtx {} // FIXME: parameterize macro on what ctx type is used here
|
pub struct WasiCtx {
|
||||||
|
mem_errors: Vec<::memory::MemoryError>,
|
||||||
impl types::WitxErrorConversion for WasiCtx {
|
value_errors: Vec<::memory::GuestValueError>,
|
||||||
fn success_to_errno(&mut self) -> types::Errno {
|
|
||||||
types::Errno::Ok
|
|
||||||
}
|
}
|
||||||
fn memory_error_to_errno(&mut self, e: ::memory::MemoryError) -> types::Errno {
|
|
||||||
eprintln!("memory error: {:?}", e);
|
// Errno is used as a first return value in the functions above, therefore
|
||||||
|
// it must implement GuestError with type Context = WasiCtx.
|
||||||
|
// The context type should let you do logging or debugging or whatever you need
|
||||||
|
// with these errors. We just push them to vecs.
|
||||||
|
impl ::memory::GuestError for types::Errno {
|
||||||
|
type Context = WasiCtx;
|
||||||
|
fn is_success(&self) -> bool {
|
||||||
|
match self {
|
||||||
|
types::Errno::Ok => true,
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fn from_memory_error(e: ::memory::MemoryError, ctx: &mut WasiCtx) -> types::Errno {
|
||||||
|
ctx.mem_errors.push(e);
|
||||||
types::Errno::InvalidArg
|
types::Errno::InvalidArg
|
||||||
}
|
}
|
||||||
fn value_error_to_errno(&mut self, e: ::memory::GuestValueError) -> types::Errno {
|
fn from_value_error(e: ::memory::GuestValueError, ctx: &mut WasiCtx) -> types::Errno {
|
||||||
eprintln!("guest value error: {:?}", e);
|
ctx.value_errors.push(e);
|
||||||
types::Errno::InvalidArg
|
types::Errno::InvalidArg
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user