some progress on marshalling args
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
use proc_macro2::{Ident, TokenStream};
|
||||
use proc_macro2::TokenStream;
|
||||
use quote::quote;
|
||||
|
||||
use crate::names::Names;
|
||||
@@ -66,29 +66,20 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream {
|
||||
let marshal_args = func
|
||||
.params
|
||||
.iter()
|
||||
.map(|param| match param.tref.type_().passed_by() {
|
||||
witx::TypePassedBy::Value(_atom) => {
|
||||
// FIXME atom -> param.tref can be either an `as` conversion, or `try_from`
|
||||
let name = names.func_param(¶m.name);
|
||||
let interface_type = names.type_ref(¶m.tref);
|
||||
quote!( let #name = #name as #interface_type; )
|
||||
}
|
||||
_ => unimplemented!(),
|
||||
});
|
||||
.map(|p| marshal_arg(names, p, func.results.get(0).map(|r| &r.tref)));
|
||||
let trait_args = func
|
||||
.params
|
||||
.iter()
|
||||
.map(|param| names.func_param(¶m.name));
|
||||
|
||||
let trait_rets = func
|
||||
.results
|
||||
.iter()
|
||||
.skip(1)
|
||||
.map(|result| names.func_param(&result.name))
|
||||
.collect::<Vec<Ident>>();
|
||||
let (trait_rets, trait_bindings) = if trait_rets.is_empty() {
|
||||
let (trait_rets, trait_bindings) = if func.results.len() < 2 {
|
||||
(quote!({}), quote!(_))
|
||||
} else {
|
||||
let trait_rets = func
|
||||
.results
|
||||
.iter()
|
||||
.skip(1)
|
||||
.map(|result| names.func_param(&result.name));
|
||||
let tuple = quote!((#(#trait_rets),*));
|
||||
(tuple.clone(), tuple)
|
||||
};
|
||||
@@ -110,3 +101,67 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream {
|
||||
#abi_ret::from(success)
|
||||
})
|
||||
}
|
||||
|
||||
fn marshal_arg(
|
||||
names: &Names,
|
||||
param: &witx::InterfaceFuncParam,
|
||||
error_type: Option<&witx::TypeRef>,
|
||||
) -> TokenStream {
|
||||
let tref = ¶m.tref;
|
||||
let interface_typename = names.type_ref(&tref);
|
||||
let name = names.func_param(¶m.name);
|
||||
|
||||
let value_error_handling = if let Some(tref) = error_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::GuestError::from_memory_error(e, ctx);
|
||||
return #abi_ret::from(err);
|
||||
}
|
||||
} else {
|
||||
quote! {
|
||||
panic!("memory error: {:?}", e)
|
||||
}
|
||||
};
|
||||
|
||||
let try_into_conversion = quote! {
|
||||
use ::std::convert::TryInto;
|
||||
let #name: #interface_typename = match #name.try_into() {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
#value_error_handling
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
match &*tref.type_() {
|
||||
witx::Type::Enum(_e) => try_into_conversion,
|
||||
witx::Type::Builtin(b) => match b {
|
||||
witx::BuiltinType::U8 | witx::BuiltinType::U16 | witx::BuiltinType::Char8 => {
|
||||
try_into_conversion
|
||||
}
|
||||
witx::BuiltinType::S8 | witx::BuiltinType::S16 => quote! {
|
||||
let #name: #interface_typename = match (#name as i32).try_into() {
|
||||
Ok(a) => a,
|
||||
Err(e) => {
|
||||
#value_error_handling
|
||||
}
|
||||
}
|
||||
},
|
||||
witx::BuiltinType::U32
|
||||
| witx::BuiltinType::S32
|
||||
| witx::BuiltinType::U64
|
||||
| witx::BuiltinType::S64
|
||||
| witx::BuiltinType::USize
|
||||
| witx::BuiltinType::F32
|
||||
| witx::BuiltinType::F64 => quote! {
|
||||
let #name = #name as #interface_typename;
|
||||
},
|
||||
witx::BuiltinType::String => unimplemented!("string types unimplemented"),
|
||||
},
|
||||
_ => unimplemented!("only enums and builtins so far"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,13 +37,11 @@ fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenS
|
||||
let variant_names = e.variants.iter().map(|v| names.enum_variant(&v.name));
|
||||
let tryfrom_repr_cases = e.variants.iter().enumerate().map(|(n, v)| {
|
||||
let variant_name = names.enum_variant(&v.name);
|
||||
let n = n as u32;
|
||||
quote!(#n => Ok(#ident::#variant_name))
|
||||
});
|
||||
let to_repr_cases = e.variants.iter().enumerate().map(|(n, v)| {
|
||||
let variant_name = names.enum_variant(&v.name);
|
||||
let n = n as u32;
|
||||
quote!(#ident::#variant_name => #n)
|
||||
quote!(#ident::#variant_name => #n as #repr)
|
||||
});
|
||||
|
||||
quote! {
|
||||
@@ -56,14 +54,14 @@ fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenS
|
||||
impl ::std::convert::TryFrom<#repr> for #ident {
|
||||
type Error = ::memory::GuestValueError;
|
||||
fn try_from(value: #repr) -> Result<#ident, ::memory::GuestValueError> {
|
||||
match value {
|
||||
match value as usize {
|
||||
#(#tryfrom_repr_cases),*,
|
||||
_ => Err(::memory::GuestValueError::InvalidEnum(stringify!(#ident))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ::std::convert::TryFrom<#signed_repr> for #ident {
|
||||
impl ::std::convert::TryFrom<#signed_repr> for #ident { // XXX this one should always be from i32/i64 (abi size)
|
||||
type Error = ::memory::GuestValueError;
|
||||
fn try_from(value: #signed_repr) -> Result<#ident, ::memory::GuestValueError> {
|
||||
#ident::try_from(value as #repr)
|
||||
@@ -78,7 +76,7 @@ fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenS
|
||||
}
|
||||
}
|
||||
|
||||
impl From<#ident> for #signed_repr {
|
||||
impl From<#ident> for #signed_repr { // XXX this should be to i32 or i64 (abi size)
|
||||
fn from(e: #ident) -> #signed_repr {
|
||||
#repr::from(e) as #signed_repr
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user