return values written to pointers!
This commit is contained in:
@@ -8,39 +8,34 @@ use crate::names::Names;
|
|||||||
//
|
//
|
||||||
pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream {
|
pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream {
|
||||||
let ident = names.func(&func.name);
|
let ident = names.func(&func.name);
|
||||||
|
let coretype = func.core_type();
|
||||||
|
|
||||||
let arg_signature = |param: &witx::InterfaceFuncParam| -> TokenStream {
|
let params = coretype.args.iter().map(|arg| match arg.signifies {
|
||||||
let name = names.func_param(¶m.name);
|
witx::CoreParamSignifies::Value(atom) => {
|
||||||
match param.tref.type_().passed_by() {
|
let atom = names.atom_type(atom);
|
||||||
witx::TypePassedBy::Value(atom) => {
|
let name = names.func_param(&arg.param.name);
|
||||||
let atom = names.atom_type(atom);
|
quote!(#name : #atom)
|
||||||
quote!(#name: #atom)
|
|
||||||
}
|
|
||||||
witx::TypePassedBy::Pointer => {
|
|
||||||
let atom = names.atom_type(witx::AtomType::I32);
|
|
||||||
quote!(#name: #atom)
|
|
||||||
}
|
|
||||||
witx::TypePassedBy::PointerLengthPair => {
|
|
||||||
let atom = names.atom_type(witx::AtomType::I32);
|
|
||||||
let len_name = names.func_len_param(¶m.name);
|
|
||||||
quote!(#name: #atom, #len_name: #atom)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
witx::CoreParamSignifies::PointerTo => {
|
||||||
|
let atom = names.atom_type(witx::AtomType::I32);
|
||||||
|
let name = names.func_ptr_binding(&arg.param.name);
|
||||||
|
quote!(#name: #atom)
|
||||||
|
}
|
||||||
|
witx::CoreParamSignifies::LengthOf => {
|
||||||
|
let atom = names.atom_type(witx::AtomType::I32);
|
||||||
|
let name = names.func_len_binding(&arg.param.name);
|
||||||
|
quote!(#name: #atom)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
let params = func
|
|
||||||
.params
|
|
||||||
.iter()
|
|
||||||
.chain(func.results.iter().skip(1))
|
|
||||||
.map(arg_signature);
|
|
||||||
let abi_args = quote!(
|
let abi_args = quote!(
|
||||||
ctx: &mut WasiCtx, memory: ::memory::GuestMemory,
|
ctx: &mut WasiCtx, memory: ::memory::GuestMemory,
|
||||||
#(#params),*
|
#(#params),*
|
||||||
);
|
);
|
||||||
let abi_ret = if let Some(first_result) = func.results.get(0) {
|
let abi_ret = if let Some(ret) = &coretype.ret {
|
||||||
match first_result.tref.type_().passed_by() {
|
match ret.signifies {
|
||||||
witx::TypePassedBy::Value(atom) => names.atom_type(atom),
|
witx::CoreParamSignifies::Value(atom) => names.atom_type(atom),
|
||||||
_ => unreachable!("first result should always be passed by value"),
|
_ => unreachable!("ret should always be passed by value"),
|
||||||
}
|
}
|
||||||
} else if func.noreturn {
|
} else if func.noreturn {
|
||||||
// Ideally we would return `quote!(!)` here, but, we'd have to change
|
// Ideally we would return `quote!(!)` here, but, we'd have to change
|
||||||
@@ -52,21 +47,34 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream {
|
|||||||
quote!(())
|
quote!(())
|
||||||
};
|
};
|
||||||
|
|
||||||
let err_type = func
|
let err_type = coretype.ret.map(|ret| ret.param.tref);
|
||||||
.results
|
let err_val = err_type
|
||||||
.get(0)
|
.clone()
|
||||||
.map(|res| names.type_ref(&res.tref))
|
|
||||||
.unwrap_or_else(|| abi_ret.clone());
|
|
||||||
let err_val = func
|
|
||||||
.results
|
|
||||||
.get(0)
|
|
||||||
.map(|_res| quote!(#abi_ret::from(e)))
|
.map(|_res| quote!(#abi_ret::from(e)))
|
||||||
.unwrap_or_else(|| quote!(()));
|
.unwrap_or_else(|| quote!(()));
|
||||||
|
|
||||||
|
let error_handling: TokenStream = {
|
||||||
|
if let Some(tref) = &err_type {
|
||||||
|
let abi_ret = match tref.type_().passed_by() {
|
||||||
|
witx::TypePassedBy::Value(atom) => names.atom_type(atom),
|
||||||
|
_ => unreachable!("err should always be passed by value"),
|
||||||
|
};
|
||||||
|
let err_typename = names.type_ref(&tref);
|
||||||
|
quote! {
|
||||||
|
let err: #err_typename = ::memory::GuestErrorType::from_error(e, ctx);
|
||||||
|
return #abi_ret::from(err);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote! {
|
||||||
|
panic!("error: {:?}", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
let marshal_args = func
|
let marshal_args = func
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| marshal_arg(names, p, func.results.get(0).map(|r| &r.tref)));
|
.map(|p| marshal_arg(names, p, error_handling.clone()));
|
||||||
let trait_args = func
|
let trait_args = func
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
@@ -84,88 +92,93 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream {
|
|||||||
(tuple.clone(), tuple)
|
(tuple.clone(), tuple)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Return value pointers need to be validated before the api call, then
|
||||||
|
// assigned to afterwards. marshal_result returns these two statements as a pair.
|
||||||
let marshal_rets = func
|
let marshal_rets = func
|
||||||
.results
|
.results
|
||||||
.iter()
|
.iter()
|
||||||
.skip(1)
|
.skip(1)
|
||||||
.map(|_result| quote! { unimplemented!("convert result..."); });
|
.map(|result| marshal_result(names, result, error_handling.clone()));
|
||||||
|
let marshal_rets_pre = marshal_rets.clone().map(|(pre, _post)| pre);
|
||||||
|
let marshal_rets_post = marshal_rets.map(|(_pre, post)| post);
|
||||||
|
|
||||||
|
let success = if let Some(err_type) = err_type {
|
||||||
|
let err_typename = names.type_ref(&err_type);
|
||||||
|
quote! {
|
||||||
|
let success:#err_typename = ::memory::GuestErrorType::success();
|
||||||
|
#abi_ret::from(success)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
quote!()
|
||||||
|
};
|
||||||
|
|
||||||
quote!(pub fn #ident(#abi_args) -> #abi_ret {
|
quote!(pub fn #ident(#abi_args) -> #abi_ret {
|
||||||
#(#marshal_args)*
|
#(#marshal_args)*
|
||||||
|
#(#marshal_rets_pre)*
|
||||||
let #trait_bindings = match ctx.#ident(#(#trait_args),*) {
|
let #trait_bindings = match ctx.#ident(#(#trait_args),*) {
|
||||||
Ok(#trait_bindings) => #trait_rets,
|
Ok(#trait_bindings) => #trait_rets,
|
||||||
Err(e) => { return #err_val; },
|
Err(e) => { return #err_val; },
|
||||||
};
|
};
|
||||||
#(#marshal_rets)*
|
#(#marshal_rets_post)*
|
||||||
let success:#err_type = ::memory::GuestErrorType::success();
|
#success
|
||||||
#abi_ret::from(success)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn marshal_arg(
|
fn marshal_arg(
|
||||||
names: &Names,
|
names: &Names,
|
||||||
param: &witx::InterfaceFuncParam,
|
param: &witx::InterfaceFuncParam,
|
||||||
error_type: Option<&witx::TypeRef>,
|
error_handling: TokenStream,
|
||||||
) -> TokenStream {
|
) -> TokenStream {
|
||||||
let tref = ¶m.tref;
|
let tref = ¶m.tref;
|
||||||
let interface_typename = names.type_ref(&tref);
|
let interface_typename = names.type_ref(&tref);
|
||||||
let name = names.func_param(¶m.name);
|
|
||||||
|
|
||||||
let error_handling: TokenStream = {
|
let try_into_conversion = {
|
||||||
if let Some(tref) = error_type {
|
let name = names.func_param(¶m.name);
|
||||||
let abi_ret = match tref.type_().passed_by() {
|
quote! {
|
||||||
witx::TypePassedBy::Value(atom) => names.atom_type(atom),
|
use ::std::convert::TryInto;
|
||||||
_ => unreachable!("err should always be passed by value"),
|
let #name: #interface_typename = match #name.try_into() {
|
||||||
|
Ok(a) => a,
|
||||||
|
Err(e) => {
|
||||||
|
#error_handling
|
||||||
|
}
|
||||||
};
|
};
|
||||||
let err_typename = names.type_ref(&tref);
|
|
||||||
quote! {
|
|
||||||
let err: #err_typename = ::memory::GuestErrorType::from_error(e, ctx);
|
|
||||||
return #abi_ret::from(err);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
quote! {
|
|
||||||
panic!("error: {:?}", e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let try_into_conversion = quote! {
|
|
||||||
use ::std::convert::TryInto;
|
|
||||||
let #name: #interface_typename = match #name.try_into() {
|
|
||||||
Ok(a) => a,
|
|
||||||
Err(e) => {
|
|
||||||
#error_handling
|
|
||||||
}
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
match &*tref.type_() {
|
match &*tref.type_() {
|
||||||
witx::Type::Enum(_e) => try_into_conversion,
|
witx::Type::Enum(_e) => try_into_conversion,
|
||||||
witx::Type::Builtin(b) => match b {
|
witx::Type::Builtin(b) => match b {
|
||||||
witx::BuiltinType::U8 | witx::BuiltinType::U16 | witx::BuiltinType::Char8 => {
|
witx::BuiltinType::U8 | witx::BuiltinType::U16 | witx::BuiltinType::Char8 => {
|
||||||
try_into_conversion
|
try_into_conversion
|
||||||
}
|
}
|
||||||
witx::BuiltinType::S8 | witx::BuiltinType::S16 => quote! {
|
witx::BuiltinType::S8 | witx::BuiltinType::S16 => {
|
||||||
let #name: #interface_typename = match (#name as i32).try_into() {
|
let name = names.func_param(¶m.name);
|
||||||
Ok(a) => a,
|
quote! {
|
||||||
Err(e) => {
|
let #name: #interface_typename = match (#name as i32).try_into() {
|
||||||
#error_handling
|
Ok(a) => a,
|
||||||
|
Err(e) => {
|
||||||
|
#error_handling
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
witx::BuiltinType::U32
|
witx::BuiltinType::U32
|
||||||
| witx::BuiltinType::S32
|
| witx::BuiltinType::S32
|
||||||
| witx::BuiltinType::U64
|
| witx::BuiltinType::U64
|
||||||
| witx::BuiltinType::S64
|
| witx::BuiltinType::S64
|
||||||
| witx::BuiltinType::USize
|
| witx::BuiltinType::USize
|
||||||
| witx::BuiltinType::F32
|
| witx::BuiltinType::F32
|
||||||
| witx::BuiltinType::F64 => quote! {
|
| witx::BuiltinType::F64 => {
|
||||||
let #name = #name as #interface_typename;
|
let name = names.func_param(¶m.name);
|
||||||
},
|
quote! {
|
||||||
|
let #name = #name as #interface_typename;
|
||||||
|
}
|
||||||
|
}
|
||||||
witx::BuiltinType::String => unimplemented!("string types unimplemented"),
|
witx::BuiltinType::String => unimplemented!("string types unimplemented"),
|
||||||
},
|
},
|
||||||
witx::Type::Pointer(pointee) => {
|
witx::Type::Pointer(pointee) => {
|
||||||
let pointee_type = names.type_ref(pointee);
|
let pointee_type = names.type_ref(pointee);
|
||||||
|
let name = names.func_param(¶m.name);
|
||||||
quote! {
|
quote! {
|
||||||
let #name = match memory.ptr_mut::<#pointee_type>(#name as u32) {
|
let #name = match memory.ptr_mut::<#pointee_type>(#name as u32) {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
@@ -177,6 +190,7 @@ fn marshal_arg(
|
|||||||
}
|
}
|
||||||
witx::Type::ConstPointer(pointee) => {
|
witx::Type::ConstPointer(pointee) => {
|
||||||
let pointee_type = names.type_ref(pointee);
|
let pointee_type = names.type_ref(pointee);
|
||||||
|
let name = names.func_param(¶m.name);
|
||||||
quote! {
|
quote! {
|
||||||
let #name = match memory.ptr::<#pointee_type>(#name as u32) {
|
let #name = match memory.ptr::<#pointee_type>(#name as u32) {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
@@ -189,3 +203,52 @@ fn marshal_arg(
|
|||||||
_ => unimplemented!("argument type marshalling"),
|
_ => unimplemented!("argument type marshalling"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn marshal_result(
|
||||||
|
names: &Names,
|
||||||
|
result: &witx::InterfaceFuncParam,
|
||||||
|
error_handling: TokenStream,
|
||||||
|
) -> (TokenStream, TokenStream) {
|
||||||
|
let tref = &result.tref;
|
||||||
|
|
||||||
|
let write_val_to_ptr = {
|
||||||
|
let pointee_type = names.type_ref(tref);
|
||||||
|
// core type is given func_ptr_binding name.
|
||||||
|
let ptr_name = names.func_ptr_binding(&result.name);
|
||||||
|
let pre = quote! {
|
||||||
|
let #ptr_name = match memory.ptr_mut::<#pointee_type>(#ptr_name as u32) {
|
||||||
|
Ok(p) => p,
|
||||||
|
Err(e) => {
|
||||||
|
#error_handling
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
// trait binding returns func_param name.
|
||||||
|
let val_name = names.func_param(&result.name);
|
||||||
|
let post = quote! {
|
||||||
|
use ::memory::GuestTypeCopy;
|
||||||
|
#pointee_type::write_val(#val_name, &#ptr_name);
|
||||||
|
};
|
||||||
|
(pre, post)
|
||||||
|
};
|
||||||
|
|
||||||
|
match &*tref.type_() {
|
||||||
|
witx::Type::Builtin(b) => match b {
|
||||||
|
witx::BuiltinType::U8
|
||||||
|
| witx::BuiltinType::S8
|
||||||
|
| witx::BuiltinType::U16
|
||||||
|
| witx::BuiltinType::S16
|
||||||
|
| witx::BuiltinType::U32
|
||||||
|
| witx::BuiltinType::S32
|
||||||
|
| witx::BuiltinType::U64
|
||||||
|
| witx::BuiltinType::S64
|
||||||
|
| witx::BuiltinType::F32
|
||||||
|
| witx::BuiltinType::F64
|
||||||
|
| witx::BuiltinType::USize
|
||||||
|
| witx::BuiltinType::Char8 => write_val_to_ptr,
|
||||||
|
witx::BuiltinType::String => unimplemented!("string types"),
|
||||||
|
},
|
||||||
|
witx::Type::Enum(_e) => write_val_to_ptr,
|
||||||
|
_ => unimplemented!("marshal result"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -88,8 +88,13 @@ impl Names {
|
|||||||
format_ident!("{}", id.as_str().to_snake_case())
|
format_ident!("{}", id.as_str().to_snake_case())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// For when you need a {name}_len parameter for passing an array:
|
/// For when you need a {name}_ptr binding for passing a value by reference:
|
||||||
pub fn func_len_param(&self, id: &Id) -> Ident {
|
pub fn func_ptr_binding(&self, id: &Id) -> Ident {
|
||||||
|
format_ident!("{}_ptr", id.as_str().to_snake_case())
|
||||||
|
}
|
||||||
|
|
||||||
|
/// For when you need a {name}_len binding for passing an array:
|
||||||
|
pub fn func_len_binding(&self, id: &Id) -> Ident {
|
||||||
format_ident!("{}_len", id.as_str().to_snake_case())
|
format_ident!("{}_len", id.as_str().to_snake_case())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -62,8 +62,12 @@ pub mod test {
|
|||||||
);
|
);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
fn bat(&mut self, an_int: u32) -> Result<f32, types::Errno> {
|
||||||
|
println!("bat: {}", an_int);
|
||||||
|
Ok((an_int as f32) * 2.0)
|
||||||
|
}
|
||||||
|
}
|
||||||
// Errno is used as a first return value in the functions above, therefore
|
// Errno is used as a first return value in the functions above, therefore
|
||||||
// it must implement GuestErrorType with type Context = WasiCtx.
|
// it must implement GuestErrorType with type Context = WasiCtx.
|
||||||
// The context type should let you do logging or debugging or whatever you need
|
// The context type should let you do logging or debugging or whatever you need
|
||||||
|
|||||||
@@ -25,4 +25,8 @@
|
|||||||
(param $a_lamer_excuse (@witx const_pointer $excuse))
|
(param $a_lamer_excuse (@witx const_pointer $excuse))
|
||||||
(param $two_layers_of_excuses (@witx pointer (@witx const_pointer $excuse)))
|
(param $two_layers_of_excuses (@witx pointer (@witx const_pointer $excuse)))
|
||||||
(result $error $errno))
|
(result $error $errno))
|
||||||
|
(@interface func (export "bat")
|
||||||
|
(param $an_int u32)
|
||||||
|
(result $error $errno)
|
||||||
|
(result $doubled_it f32))
|
||||||
)
|
)
|
||||||
|
|||||||
Reference in New Issue
Block a user