structs implementing Copy are scaffolded out.

todo: need an unsafe method for casting pointers in order to validate
contents via recursive descent
This commit is contained in:
Pat Hickey
2020-01-28 15:45:52 -08:00
parent 373560b88a
commit 62e00434b0
6 changed files with 113 additions and 6 deletions

View File

@@ -2,6 +2,7 @@ use proc_macro2::TokenStream;
use quote::quote; use quote::quote;
use crate::names::Names; use crate::names::Names;
use crate::types::struct_is_copy;
// FIXME need to template what argument is required to an import function - some context // FIXME need to template what argument is required to an import function - some context
// struct (e.g. WasiCtx) should be provided at the invocation of the `gen` proc macro. // struct (e.g. WasiCtx) should be provided at the invocation of the `gen` proc macro.
@@ -75,10 +76,14 @@ pub fn define_func(names: &Names, func: &witx::InterfaceFunc) -> TokenStream {
.params .params
.iter() .iter()
.map(|p| marshal_arg(names, p, error_handling.clone())); .map(|p| marshal_arg(names, p, error_handling.clone()));
let trait_args = func let trait_args = func.params.iter().map(|param| {
.params let name = names.func_param(&param.name);
.iter() match param.tref.type_().passed_by() {
.map(|param| names.func_param(&param.name)); witx::TypePassedBy::Value { .. } => quote!(#name),
witx::TypePassedBy::Pointer { .. } => quote!(&#name),
witx::TypePassedBy::PointerLengthPair { .. } => unimplemented!(),
}
});
let (trait_rets, trait_bindings) = if func.results.len() < 2 { let (trait_rets, trait_bindings) = if func.results.len() < 2 {
(quote!({}), quote!(_)) (quote!({}), quote!(_))
@@ -200,6 +205,24 @@ fn marshal_arg(
}; };
} }
} }
witx::Type::Struct(s) if struct_is_copy(&s) => {
let pointee_type = names.type_ref(tref);
let arg_name = names.func_ptr_binding(&param.name);
let name = names.func_param(&param.name);
quote! {
let #name = match memory.ptr::<#pointee_type>(#arg_name as u32) {
Ok(p) => match p.as_ref() {
Ok(r) => r,
Err(e) => {
#error_handling
}
},
Err(e) => {
#error_handling
}
};
}
}
_ => unimplemented!("argument type marshalling"), _ => unimplemented!("argument type marshalling"),
} }
} }

View File

@@ -10,7 +10,12 @@ pub fn define_module_trait(names: &Names, m: &Module) -> TokenStream {
let funcname = names.func(&f.name); let funcname = names.func(&f.name);
let args = f.params.iter().map(|arg| { let args = f.params.iter().map(|arg| {
let arg_name = names.func_param(&arg.name); let arg_name = names.func_param(&arg.name);
let arg_type = names.type_ref(&arg.tref); let arg_typename = names.type_ref(&arg.tref);
let arg_type = match arg.tref.type_().passed_by() {
witx::TypePassedBy::Value { .. } => quote!(#arg_typename),
witx::TypePassedBy::Pointer { .. } => quote!(&#arg_typename),
witx::TypePassedBy::PointerLengthPair { .. } => unimplemented!(),
};
quote!(#arg_name: #arg_type) quote!(#arg_name: #arg_type)
}); });
let rets = f let rets = f

View File

@@ -72,6 +72,10 @@ impl Names {
} }
} }
pub fn struct_member(&self, id: &Id) -> Ident {
format_ident!("{}", id.as_str().to_snake_case())
}
pub fn module(&self, id: &Id) -> Ident { pub fn module(&self, id: &Id) -> Ident {
format_ident!("{}", id.as_str().to_snake_case()) format_ident!("{}", id.as_str().to_snake_case())
} }

View File

@@ -2,6 +2,7 @@ use crate::names::Names;
use proc_macro2::TokenStream; use proc_macro2::TokenStream;
use quote::quote; use quote::quote;
use witx::Layout;
pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStream { pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStream {
match &namedtype.tref { match &namedtype.tref {
@@ -10,7 +11,13 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea
witx::Type::Enum(e) => define_enum(names, &namedtype.name, &e), witx::Type::Enum(e) => define_enum(names, &namedtype.name, &e),
witx::Type::Int(_) => unimplemented!("int types"), witx::Type::Int(_) => unimplemented!("int types"),
witx::Type::Flags(_) => unimplemented!("flag types"), witx::Type::Flags(_) => unimplemented!("flag types"),
witx::Type::Struct(_) => unimplemented!("struct types"), witx::Type::Struct(s) => {
if struct_is_copy(s) {
define_copy_struct(names, &namedtype.name, &s)
} else {
unimplemented!("non-Copy struct")
}
}
witx::Type::Union(_) => unimplemented!("union types"), witx::Type::Union(_) => unimplemented!("union types"),
witx::Type::Handle(_h) => unimplemented!("handle types"), witx::Type::Handle(_h) => unimplemented!("handle types"),
witx::Type::Builtin(b) => define_builtin(names, &namedtype.name, *b), witx::Type::Builtin(b) => define_builtin(names, &namedtype.name, *b),
@@ -126,6 +133,59 @@ fn define_builtin(names: &Names, name: &witx::Id, builtin: witx::BuiltinType) ->
quote!(pub type #ident = #built;) quote!(pub type #ident = #built;)
} }
pub fn struct_is_copy(s: &witx::StructDatatype) -> bool {
s.members.iter().all(|m| match &*m.tref.type_() {
witx::Type::Struct(s) => struct_is_copy(&s),
witx::Type::Builtin(b) => match &*b {
witx::BuiltinType::String => false,
_ => true,
},
witx::Type::ConstPointer { .. }
| witx::Type::Pointer { .. }
| witx::Type::Array { .. }
| witx::Type::Union { .. } => false,
witx::Type::Enum { .. }
| witx::Type::Int { .. }
| witx::Type::Flags { .. }
| witx::Type::Handle { .. } => true,
})
}
fn define_copy_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) -> TokenStream {
let ident = names.type_(name);
let member_decls = s.members.iter().map(|m| {
let name = names.struct_member(&m.name);
let type_ = names.type_ref(&m.tref);
quote!(pub #name: #type_)
});
let size = s.mem_size_align().size as u32;
let align = s.mem_size_align().align as u32;
quote! {
#[repr(C)]
#[derive(Copy, Clone, Debug, ::std::hash::Hash, Eq, PartialEq)]
pub struct #ident {
#(#member_decls),*
}
impl ::memory::GuestType for #ident {
fn size() -> u32 {
#size
}
fn align() -> u32 {
#align
}
fn name() -> String {
stringify!(#ident).to_owned()
}
fn validate(_ptr: &::memory::GuestPtr<#ident>) -> Result<(), ::memory::GuestError> {
Ok(()) // FIXME
}
}
impl ::memory::GuestTypeCopy for #ident {}
}
}
fn int_repr_tokens(int_repr: witx::IntRepr) -> TokenStream { fn int_repr_tokens(int_repr: witx::IntRepr) -> TokenStream {
match int_repr { match int_repr {
witx::IntRepr::U8 => quote!(u8), witx::IntRepr::U8 => quote!(u8),

View File

@@ -62,6 +62,11 @@ pub mod test {
println!("bat: {}", an_int); println!("bat: {}", an_int);
Ok((an_int as f32) * 2.0) Ok((an_int as f32) * 2.0)
} }
fn sum_of_pair(&mut self, an_pair: &types::PairInts) -> Result<i64, types::Errno> {
println!("sum of pair: {:?}", an_pair);
Ok(an_pair.first as i64 + an_pair.second as i64)
}
} }
// 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.

View File

@@ -14,6 +14,11 @@
$traffic $traffic
$sleeping)) $sleeping))
(typename $pair_ints
(struct
(field $first s32)
(field $second s32)))
(module $foo (module $foo
(@interface func (export "bar") (@interface func (export "bar")
(param $an_int u32) (param $an_int u32)
@@ -29,4 +34,9 @@
(param $an_int u32) (param $an_int u32)
(result $error $errno) (result $error $errno)
(result $doubled_it f32)) (result $doubled_it f32))
(@interface func (export "sum_of_pair")
(param $an_pair $pair_ints)
(result $error $errno)
(result $doubled s64))
) )