diff --git a/crates/generate/src/funcs.rs b/crates/generate/src/funcs.rs index 13eff6baa1..e788032e66 100644 --- a/crates/generate/src/funcs.rs +++ b/crates/generate/src/funcs.rs @@ -308,6 +308,11 @@ fn marshal_arg( } } witx::Type::Union(_u) => read_conversion, + witx::Type::Handle(_h) => { + let name = names.func_param(¶m.name); + let handle_type = names.type_ref(tref, anon_lifetime()); + quote!( let #name = #handle_type::from(#name); ) + } _ => unimplemented!("argument type marshalling"), } } diff --git a/crates/generate/src/types.rs b/crates/generate/src/types.rs index bd05467d38..05154ded3e 100644 --- a/crates/generate/src/types.rs +++ b/crates/generate/src/types.rs @@ -21,7 +21,7 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea } } witx::Type::Union(u) => define_union(names, &namedtype.name, &u), - witx::Type::Handle(_h) => unimplemented!("handle types"), + witx::Type::Handle(h) => define_handle(names, &namedtype.name, &h), witx::Type::Builtin(b) => define_builtin(names, &namedtype.name, *b), witx::Type::Pointer(p) => define_witx_pointer( names, @@ -398,10 +398,73 @@ fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenS } } +fn define_handle(names: &Names, name: &witx::Id, h: &witx::HandleDatatype) -> TokenStream { + let ident = names.type_(name); + let size = h.mem_size_align().size as u32; + let align = h.mem_size_align().align as u32; + quote! { + #[derive(Copy, Clone, Debug, ::std::hash::Hash, Eq, PartialEq)] + pub struct #ident(u32); + + impl From<#ident> for u32 { + fn from(e: #ident) -> u32 { + e.0 + } + } + + impl From<#ident> for i32 { + fn from(e: #ident) -> i32 { + e.0 as i32 + } + } + + impl From for #ident { + fn from(e: u32) -> #ident { + #ident(e) + } + } + impl From for #ident { + fn from(e: i32) -> #ident { + #ident(e as u32) + } + } + + impl ::std::fmt::Display for #ident { + fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result { + write!(f, "{}({})", stringify!(#ident), self.0) + } + } + impl wiggle_runtime::GuestType for #ident { + fn size() -> u32 { + #size + } + fn align() -> u32 { + #align + } + fn name() -> String { + stringify!(#ident).to_owned() + } + fn validate(ptr: &wiggle_runtime::GuestPtr<#ident>) -> Result<(), wiggle_runtime::GuestError> { + Ok(()) + } + } + impl<'a> wiggle_runtime::GuestTypeClone<'a> for #ident { + fn read_from_guest(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<#ident, wiggle_runtime::GuestError> { + let r = location.as_ref()?; + Ok(*r) + } + fn write_to_guest(&self, location: &wiggle_runtime::GuestPtrMut<'a, Self>) { + unsafe { (location.as_raw() as *mut #ident).write(*self) }; + } + } + impl<'a> wiggle_runtime::GuestTypeCopy<'a> for #ident {} + } +} + fn define_builtin(names: &Names, name: &witx::Id, builtin: witx::BuiltinType) -> TokenStream { let ident = names.type_(name); let built = names.builtin_type(builtin, quote!('a)); - if let witx::BuiltinType::String = builtin { + if builtin.needs_lifetime() { quote!(pub type #ident<'a> = #built;) } else { quote!(pub type #ident = #built;) diff --git a/tests/atoms.rs b/tests/atoms.rs index 216613766f..e9be5479b6 100644 --- a/tests/atoms.rs +++ b/tests/atoms.rs @@ -14,7 +14,10 @@ impl atoms::Atoms for WasiCtx { println!("INT FLOAT ARGS: {} {}", an_int, an_float); Ok(()) } - fn double_int_return_float(&mut self, an_int: u32) -> Result { + fn double_int_return_float( + &mut self, + an_int: u32, + ) -> Result { Ok((an_int as f32) * 2.0) } } @@ -75,7 +78,7 @@ impl DoubleIntExercise { self.return_loc.ptr as i32, ); - let return_val: GuestRef = guest_memory + let return_val: GuestRef = guest_memory .ptr(self.return_loc.ptr) .expect("return loc ptr") .as_ref() diff --git a/tests/atoms.witx b/tests/atoms.witx index ef496d7600..932d7c9ffd 100644 --- a/tests/atoms.witx +++ b/tests/atoms.witx @@ -1,5 +1,7 @@ (use "errno.witx") +(typename $alias_to_float f32) + (module $atoms (@interface func (export "int_float_args") (param $an_int u32) @@ -8,5 +10,5 @@ (@interface func (export "double_int_return_float") (param $an_int u32) (result $error $errno) - (result $doubled_it f32)) + (result $doubled_it $alias_to_float)) ) diff --git a/tests/handles.rs b/tests/handles.rs new file mode 100644 index 0000000000..ed86a04519 --- /dev/null +++ b/tests/handles.rs @@ -0,0 +1,76 @@ +use proptest::prelude::*; +use wiggle_runtime::{GuestError, GuestType}; +use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx}; + +const FD_VAL: u32 = 123; + +wiggle_generate::from_witx!({ + witx: ["tests/handles.witx"], + ctx: WasiCtx, +}); + +impl_errno!(types::Errno); + +impl handle_examples::HandleExamples for WasiCtx { + fn fd_create(&mut self) -> Result { + Ok(types::Fd::from(FD_VAL)) + } + fn fd_consume(&mut self, fd: types::Fd) -> Result<(), types::Errno> { + println!("FD_CONSUME {}", fd); + if fd == types::Fd::from(FD_VAL) { + Ok(()) + } else { + Err(types::Errno::InvalidArg) + } + } +} + +#[derive(Debug)] +struct HandleExercise { + pub return_loc: MemArea, +} + +impl HandleExercise { + pub fn test(&self) { + let mut ctx = WasiCtx::new(); + let mut host_memory = HostMemory::new(); + let mut guest_memory = host_memory.guest_memory(); + + let e = handle_examples::fd_create(&mut ctx, &mut guest_memory, self.return_loc.ptr as i32); + + assert_eq!(e, types::Errno::Ok.into(), "fd_create error"); + + let h_got: u32 = *guest_memory + .ptr(self.return_loc.ptr) + .expect("return ptr") + .as_ref() + .expect("return ref_mut"); + + assert_eq!(h_got, 123, "fd_create return val"); + + let e = handle_examples::fd_consume(&mut ctx, &mut guest_memory, h_got as i32); + + assert_eq!(e, types::Errno::Ok.into(), "fd_consume error"); + + let e = handle_examples::fd_consume(&mut ctx, &mut guest_memory, h_got as i32 + 1); + + assert_eq!( + e, + types::Errno::InvalidArg.into(), + "fd_consume invalid error" + ); + } + + pub fn strat() -> BoxedStrategy { + (HostMemory::mem_area_strat(types::Fd::size())) + .prop_map(|return_loc| HandleExercise { return_loc }) + .boxed() + } +} + +proptest! { + #[test] + fn handle_exercise(e in HandleExercise::strat()) { + e.test() + } +} diff --git a/tests/handles.witx b/tests/handles.witx new file mode 100644 index 0000000000..69c1b0546e --- /dev/null +++ b/tests/handles.witx @@ -0,0 +1,12 @@ +(use "errno.witx") + +(typename $fd (handle)) + +(module $handle_examples + (@interface func (export "fd_create") + (result $error $errno) + (result $fd $fd)) + (@interface func (export "fd_consume") + (param $fd $fd) + (result $error $errno)) +)