Draft out IntDatatype in wiggle-generate (#15)

* Draft out IntDatatype in wiggle-generate

This commit drafts out basic layout for `IntDatatype` structure in
`wiggle`. As it currently stands, an `Int` type is represented as
a one-element tuple struct much like `FlagDatatype`, however, with
this difference that we do not perform any checks on the input
underlying representation since any value for the prescribed type
is legal.

* Finish drafting IntDatatype support in wiggle

This commit adds necessary marshal stubs to properly pass `IntDatatype`
in and out of interface functions. It also adds a basic proptest.
This commit is contained in:
Jakub Konka
2020-02-21 22:53:10 +01:00
committed by GitHub
parent 6ab3ff71d2
commit f48474b247
5 changed files with 175 additions and 2 deletions

View File

@@ -154,6 +154,7 @@ fn marshal_arg(
match &*tref.type_() {
witx::Type::Enum(_e) => try_into_conversion,
witx::Type::Flags(_f) => try_into_conversion,
witx::Type::Int(_i) => try_into_conversion,
witx::Type::Builtin(b) => match b {
witx::BuiltinType::U8 | witx::BuiltinType::U16 | witx::BuiltinType::Char8 => {
try_into_conversion
@@ -359,7 +360,7 @@ where
| witx::BuiltinType::Char8 => write_val_to_ptr,
witx::BuiltinType::String => unimplemented!("string types"),
},
witx::Type::Enum(_) | witx::Type::Flags(_) => write_val_to_ptr,
witx::Type::Enum(_) | witx::Type::Flags(_) | witx::Type::Int(_) => write_val_to_ptr,
_ => unimplemented!("marshal result"),
}
}

View File

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

View File

@@ -10,7 +10,7 @@ pub fn define_datatype(names: &Names, namedtype: &witx::NamedType) -> TokenStrea
witx::TypeRef::Name(alias_to) => define_alias(names, &namedtype.name, &alias_to),
witx::TypeRef::Value(v) => match &**v {
witx::Type::Enum(e) => define_enum(names, &namedtype.name, &e),
witx::Type::Int(_) => unimplemented!("int types"),
witx::Type::Int(i) => define_int(names, &namedtype.name, &i),
witx::Type::Flags(f) => define_flags(names, &namedtype.name, &f),
witx::Type::Struct(s) => {
if struct_is_copy(s) {
@@ -46,6 +46,92 @@ fn define_alias(names: &Names, name: &witx::Id, to: &witx::NamedType) -> TokenSt
}
}
fn define_int(names: &Names, name: &witx::Id, i: &witx::IntDatatype) -> TokenStream {
let ident = names.type_(&name);
let repr = int_repr_tokens(i.repr);
let abi_repr = atom_token(match i.repr {
witx::IntRepr::U8 | witx::IntRepr::U16 | witx::IntRepr::U32 => witx::AtomType::I32,
witx::IntRepr::U64 => witx::AtomType::I64,
});
let consts = i
.consts
.iter()
.map(|r#const| {
let const_ident = names.int_member(&r#const.name);
let value = r#const.value;
quote!(pub const #const_ident: #ident = #ident(#value))
})
.collect::<Vec<_>>();
quote! {
#[repr(transparent)]
#[derive(Copy, Clone, Debug, ::std::hash::Hash, Eq, PartialEq)]
pub struct #ident(#repr);
impl #ident {
#(#consts;)*
}
impl ::std::convert::TryFrom<#repr> for #ident {
type Error = wiggle_runtime::GuestError;
fn try_from(value: #repr) -> Result<Self, wiggle_runtime::GuestError> {
Ok(#ident(value))
}
}
impl ::std::convert::TryFrom<#abi_repr> for #ident {
type Error = wiggle_runtime::GuestError;
fn try_from(value: #abi_repr) -> Result<#ident, wiggle_runtime::GuestError> {
#ident::try_from(value as #repr)
}
}
impl From<#ident> for #repr {
fn from(e: #ident) -> #repr {
e.0
}
}
impl From<#ident> for #abi_repr {
fn from(e: #ident) -> #abi_repr {
#repr::from(e) as #abi_repr
}
}
impl wiggle_runtime::GuestType for #ident {
fn size() -> u32 {
::std::mem::size_of::<#repr>() as u32
}
fn align() -> u32 {
::std::mem::align_of::<#repr>() as u32
}
fn name() -> String {
stringify!(#ident).to_owned()
}
fn validate<'a>(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<(), wiggle_runtime::GuestError> {
use ::std::convert::TryFrom;
let raw: #repr = unsafe { (location.as_raw() as *const #repr).read() };
let _ = #ident::try_from(raw)?;
Ok(())
}
}
impl wiggle_runtime::GuestTypeCopy for #ident {}
impl<'a> wiggle_runtime::GuestTypeClone<'a> for #ident {
fn read_from_guest(location: &wiggle_runtime::GuestPtr<#ident>) -> Result<#ident, wiggle_runtime::GuestError> {
Ok(*location.as_ref()?)
}
fn write_to_guest(&self, location: &wiggle_runtime::GuestPtrMut<#ident>) {
let val: #repr = #repr::from(*self);
unsafe { (location.as_raw() as *mut #repr).write(val) };
}
}
}
}
fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDatatype) -> TokenStream {
let ident = names.type_(&name);
let repr = int_repr_tokens(f.repr);