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::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"),
|
_ => 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::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::Builtin(b) => define_builtin(names, &namedtype.name, *b),
|
||||||
witx::Type::Pointer(p) => define_witx_pointer(
|
witx::Type::Pointer(p) => define_witx_pointer(
|
||||||
names,
|
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 {
|
fn define_builtin(names: &Names, name: &witx::Id, builtin: witx::BuiltinType) -> TokenStream {
|
||||||
let ident = names.type_(name);
|
let ident = names.type_(name);
|
||||||
let built = names.builtin_type(builtin, quote!('a));
|
let built = names.builtin_type(builtin, quote!('a));
|
||||||
if let witx::BuiltinType::String = builtin {
|
if builtin.needs_lifetime() {
|
||||||
quote!(pub type #ident<'a> = #built;)
|
quote!(pub type #ident<'a> = #built;)
|
||||||
} else {
|
} else {
|
||||||
quote!(pub type #ident = #built;)
|
quote!(pub type #ident = #built;)
|
||||||
|
|||||||
@@ -14,7 +14,10 @@ impl atoms::Atoms for WasiCtx {
|
|||||||
println!("INT FLOAT ARGS: {} {}", an_int, an_float);
|
println!("INT FLOAT ARGS: {} {}", an_int, an_float);
|
||||||
Ok(())
|
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)
|
Ok((an_int as f32) * 2.0)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,7 +78,7 @@ impl DoubleIntExercise {
|
|||||||
self.return_loc.ptr as i32,
|
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)
|
.ptr(self.return_loc.ptr)
|
||||||
.expect("return loc ptr")
|
.expect("return loc ptr")
|
||||||
.as_ref()
|
.as_ref()
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
(use "errno.witx")
|
(use "errno.witx")
|
||||||
|
|
||||||
|
(typename $alias_to_float f32)
|
||||||
|
|
||||||
(module $atoms
|
(module $atoms
|
||||||
(@interface func (export "int_float_args")
|
(@interface func (export "int_float_args")
|
||||||
(param $an_int u32)
|
(param $an_int u32)
|
||||||
@@ -8,5 +10,5 @@
|
|||||||
(@interface func (export "double_int_return_float")
|
(@interface func (export "double_int_return_float")
|
||||||
(param $an_int u32)
|
(param $an_int u32)
|
||||||
(result $error $errno)
|
(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