* Introduce WasiCtxBuilderError error type `WasiCtxBuilderError` is the `wasi-common` client-facing error type which is exclusively thrown when building a new `WasiCtx` instance. As such, building such an instance should not require the client to understand different WASI errno values as was assumed until now. This commit is a first step at streamlining error handling in `wasi-common` and makes way for the `wiggle` crate. When adding the `WasiCtxBuilderError`, I've had to do two things of notable importance: 1. I've removed a couple of `ok_or` calls in `WasiCtxBuilder::build` and replaced them with `unwrap`s, following the same pattern in different builder methods above. This is fine since we _always_ operate on non-empty `Option`s in `WasiCtxBuilder` thus `unwrap`ing will never fail. On the other hand, this might be a good opportunity to rethink the structure of our builder, and how we good remove the said `Option`s especially since we always populate them with empty containers to begin with. I understand this is to make chaining of builder methods easier which take and return `&mut self` and the same applies to `WasiCtxBuilder::build(&mut self)` method, but perhaps it would more cleanly signal the intentions if we simply moved `WasiCtxBuilder` instance around. Food for thought! 2. Methods specific to determining rights of passed around `std::fs::File` objects when populating `WasiCtx` `FdEntry` entities now return `io::Error` directly so that we can reuse them in `WasiCtxBuilder` methods (returning `WasiCtxBuilderError` error type), and in syscalls (returning WASI errno). * Return WasiError directly in syscalls Also, removes `error::Error` type altogether. Now, `io::Error` and related are automatically converted to their corresponding WASI errno value encapsulated as `WasiError`. While here, it made sense to me to move `WasiError` to `wasi` module which will align itself well with the upcoming changes introduced by `wiggle`. To different standard `Result` from WASI specific, I've created a helper alias `WasiResult` also residing in `wasi` module. * Update wig * Add from ffi::NulError and pass context to NotADirectory * Add dummy commit to test CI
131 lines
3.9 KiB
Rust
131 lines
3.9 KiB
Rust
use crate::utils;
|
|
use proc_macro2::TokenStream;
|
|
use quote::{format_ident, quote};
|
|
|
|
pub fn define(args: TokenStream) -> TokenStream {
|
|
let (path, phase) = utils::witx_path_from_args(args);
|
|
let doc = match witx::load(&[&path]) {
|
|
Ok(doc) => doc,
|
|
Err(e) => {
|
|
panic!("error opening file {}: {}", path, e);
|
|
}
|
|
};
|
|
|
|
let mut ret = TokenStream::new();
|
|
|
|
let old = match phase.as_str() {
|
|
"snapshot" => false,
|
|
"old/snapshot_0" => true,
|
|
s => panic!("unsupported phase: {}", s),
|
|
};
|
|
|
|
for module in doc.modules() {
|
|
for func in module.funcs() {
|
|
ret.extend(generate_wrappers(&func, old));
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
fn generate_wrappers(func: &witx::InterfaceFunc, old: bool) -> TokenStream {
|
|
let name = format_ident!("{}", func.name.as_str());
|
|
let mut arg_declarations = Vec::new();
|
|
let mut arg_names = Vec::new();
|
|
|
|
for param in func.params.iter() {
|
|
let name = utils::param_name(param);
|
|
|
|
if let witx::TypePassedBy::PointerLengthPair = param.tref.type_().passed_by() {
|
|
let ptr = format_ident!("{}_ptr", name);
|
|
let len = format_ident!("{}_len", name);
|
|
arg_declarations.push(quote! { #ptr: super::wasi32::uintptr_t });
|
|
arg_declarations.push(quote! { #len: super::wasi32::size_t });
|
|
arg_names.push(ptr);
|
|
arg_names.push(len);
|
|
continue;
|
|
}
|
|
|
|
match ¶m.tref {
|
|
witx::TypeRef::Name(n) => {
|
|
if n.name.as_str() == "size" {
|
|
arg_declarations.push(quote! { #name: super::wasi32::size_t });
|
|
} else {
|
|
let ty_name = format_ident!("__wasi_{}_t", n.name.as_str());
|
|
arg_declarations.push(quote! { #name: super::wasi::#ty_name });
|
|
}
|
|
}
|
|
witx::TypeRef::Value(v) => match &**v {
|
|
witx::Type::ConstPointer(_) | witx::Type::Pointer(_) => {
|
|
arg_declarations.push(quote! { #name: super::wasi32::uintptr_t });
|
|
}
|
|
_ => panic!("unexpected value type"),
|
|
},
|
|
}
|
|
arg_names.push(name);
|
|
}
|
|
|
|
let mut ret = quote!(());
|
|
|
|
for (i, result) in func.results.iter().enumerate() {
|
|
if i == 0 {
|
|
match &result.tref {
|
|
witx::TypeRef::Name(n) => {
|
|
let ty_name = format_ident!("__wasi_{}_t", n.name.as_str());
|
|
ret = quote! { super::wasi::#ty_name };
|
|
}
|
|
witx::TypeRef::Value(_) => panic!("unexpected value type"),
|
|
}
|
|
continue;
|
|
}
|
|
let name = utils::param_name(result);
|
|
arg_declarations.push(quote! { #name: super::wasi32::uintptr_t });
|
|
arg_names.push(name);
|
|
}
|
|
|
|
let call = quote! {
|
|
super::hostcalls_impl::#name(wasi_ctx, memory, #(#arg_names,)*)
|
|
};
|
|
let body = if func.results.len() == 0 {
|
|
call
|
|
} else {
|
|
quote! {
|
|
let ret = #call
|
|
.err()
|
|
.unwrap_or(super::wasi::WasiError::ESUCCESS);
|
|
log::trace!(" | errno={}", ret);
|
|
ret.as_raw_errno()
|
|
}
|
|
};
|
|
|
|
let c_abi_name = if old {
|
|
format_ident!("old_wasi_common_{}", name)
|
|
} else {
|
|
format_ident!("wasi_common_{}", name)
|
|
};
|
|
|
|
quote! {
|
|
pub unsafe fn #name(
|
|
wasi_ctx: &mut super::WasiCtx,
|
|
memory: &mut [u8],
|
|
#(#arg_declarations,)*
|
|
) -> #ret {
|
|
#body
|
|
}
|
|
|
|
#[no_mangle]
|
|
pub unsafe fn #c_abi_name(
|
|
wasi_ctx: *mut super::WasiCtx,
|
|
memory: *mut u8,
|
|
memory_len: usize,
|
|
#(#arg_declarations,)*
|
|
) -> #ret {
|
|
#name(
|
|
&mut *wasi_ctx,
|
|
std::slice::from_raw_parts_mut(memory, memory_len),
|
|
#(#arg_names,)*
|
|
)
|
|
}
|
|
}
|
|
}
|