Start drafting out flags datatype generation (#11)

* Adds support for flags datatype

This commit adds support for `FlagsDatatype`. In WASI, flags are
represented as bitfields/bitflags, therefore, it is important
for the type to have bitwise operations implemented, and some
way of checking whether the current set of flags contains some
other set (i.e., they intersect). Thus, this commit automatically
derives `BitAnd`, etc. for the derived flags datatype. It also
automatically provides an `ALL_FLAGS` value which corresponds to
a bitwise-or of all flag values present and is provided for
convenience.

* Simplify read_from_guest
This commit is contained in:
Jakub Konka
2020-02-21 09:58:43 +01:00
committed by GitHub
parent 898af8e2fb
commit 3ef24a04fe
6 changed files with 261 additions and 4 deletions

View File

@@ -1,4 +1,5 @@
use proptest::prelude::*;
use std::convert::TryFrom;
use wiggle_runtime::{
GuestArray, GuestError, GuestErrorType, GuestMemory, GuestPtr, GuestPtrMut, GuestRef,
GuestRefMut,
@@ -121,6 +122,18 @@ impl foo::Foo for WasiCtx {
}
Ok(())
}
fn configure_car(
&mut self,
old_config: types::CarConfig,
other_config_ptr: GuestPtr<types::CarConfig>,
) -> Result<types::CarConfig, types::Errno> {
let other_config = *other_config_ptr.as_ref().map_err(|e| {
eprintln!("old_config_ptr error: {}", e);
types::Errno::InvalidArg
})?;
Ok(old_config ^ other_config)
}
}
// Errno is used as a first return value in the functions above, therefore
// it must implement GuestErrorType with type Context = WasiCtx.
@@ -774,3 +787,82 @@ proptest! {
e.test()
}
}
fn car_config_strat() -> impl Strategy<Value = types::CarConfig> {
(1u8..=types::CarConfig::ALL_FLAGS.into())
.prop_map(|v| {
types::CarConfig::try_from(v).expect("invalid value for types::CarConfig flag")
})
.boxed()
}
#[derive(Debug)]
struct ConfigureCarExercise {
old_config: types::CarConfig,
other_config: types::CarConfig,
other_config_by_ptr: MemArea,
return_ptr_loc: MemArea,
}
impl ConfigureCarExercise {
pub fn strat() -> BoxedStrategy<Self> {
(
car_config_strat(),
car_config_strat(),
HostMemory::mem_area_strat(4),
HostMemory::mem_area_strat(4),
)
.prop_map(
|(old_config, other_config, other_config_by_ptr, return_ptr_loc)| Self {
old_config,
other_config,
other_config_by_ptr,
return_ptr_loc,
},
)
.prop_filter("non-overlapping ptrs", |e| {
non_overlapping_set(&[&e.other_config_by_ptr, &e.return_ptr_loc])
})
.boxed()
}
pub fn test(&self) {
let mut ctx = WasiCtx::new();
let mut host_memory = HostMemory::new();
let mut guest_memory = GuestMemory::new(host_memory.as_mut_ptr(), host_memory.len() as u32);
// Populate input ptr
*guest_memory
.ptr_mut(self.other_config_by_ptr.ptr)
.expect("ptr mut to CarConfig")
.as_ref_mut()
.expect("deref ptr mut to CarConfig") = self.other_config;
let res = foo::configure_car(
&mut ctx,
&mut guest_memory,
self.old_config.into(),
self.other_config_by_ptr.ptr as i32,
self.return_ptr_loc.ptr as i32,
);
assert_eq!(res, types::Errno::Ok.into(), "configure car errno");
let res_config = *guest_memory
.ptr::<types::CarConfig>(self.return_ptr_loc.ptr)
.expect("ptr to returned CarConfig")
.as_ref()
.expect("deref to CarConfig value");
assert_eq!(
self.old_config ^ self.other_config,
res_config,
"returned CarConfig should be an XOR of inputs"
);
}
}
proptest! {
#[test]
fn configure_car(e in ConfigureCarExercise::strat()) {
e.test()
}
}

View File

@@ -12,6 +12,12 @@
$traffic
$sleeping))
(typename $car_config
(flags u8
$automatic
$awd
$suv))
(typename $pair_ints
(struct
(field $first s32)
@@ -60,4 +66,10 @@
(param $excuses $excuse_array)
(result $error $errno)
)
(@interface func (export "configure_car")
(param $old_config $car_config)
(param $old_config_by_ptr (@witx const_pointer $car_config))
(result $error $errno)
(result $new_config $car_config)
)
)