Handles (#22)
* test coverage: make sure aliases to builtins get tested * trivial support for handles * add tests for handles
This commit is contained in:
@@ -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"),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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<u32> for #ident {
|
||||
fn from(e: u32) -> #ident {
|
||||
#ident(e)
|
||||
}
|
||||
}
|
||||
impl From<i32> 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;)
|
||||
|
||||
@@ -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<f32, types::Errno> {
|
||||
fn double_int_return_float(
|
||||
&mut self,
|
||||
an_int: u32,
|
||||
) -> Result<types::AliasToFloat, types::Errno> {
|
||||
Ok((an_int as f32) * 2.0)
|
||||
}
|
||||
}
|
||||
@@ -75,7 +78,7 @@ impl DoubleIntExercise {
|
||||
self.return_loc.ptr as i32,
|
||||
);
|
||||
|
||||
let return_val: GuestRef<f32> = guest_memory
|
||||
let return_val: GuestRef<types::AliasToFloat> = guest_memory
|
||||
.ptr(self.return_loc.ptr)
|
||||
.expect("return loc ptr")
|
||||
.as_ref()
|
||||
|
||||
@@ -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))
|
||||
)
|
||||
|
||||
76
tests/handles.rs
Normal file
76
tests/handles.rs
Normal file
@@ -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<types::Fd, types::Errno> {
|
||||
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<Self> {
|
||||
(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()
|
||||
}
|
||||
}
|
||||
12
tests/handles.witx
Normal file
12
tests/handles.witx
Normal file
@@ -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))
|
||||
)
|
||||
Reference in New Issue
Block a user