Unify GuestType and GuestTypeClone, rename GuestTypeCopy to GuestTypeTransparent

This commit refactors trait system for guest types. Namely, as
discussed offline on zulip, `GuestType` now includes `GuestTypeClone`,
whereas `GuestTypeCopy` has been renamed to `GuestTypeTransparent`.
This commit is contained in:
Jakub Konka
2020-02-27 14:25:39 +01:00
committed by Jakub Konka
parent ed1d5180ef
commit ec75f874ee
8 changed files with 152 additions and 147 deletions

View File

@@ -105,7 +105,7 @@ fn define_int(names: &Names, name: &witx::Id, i: &witx::IntDatatype) -> TokenStr
} }
} }
impl wiggle_runtime::GuestType for #ident { impl<'a> wiggle_runtime::GuestType<'a> for #ident {
fn size() -> u32 { fn size() -> u32 {
::std::mem::size_of::<#repr>() as u32 ::std::mem::size_of::<#repr>() as u32
} }
@@ -118,24 +118,24 @@ fn define_int(names: &Names, name: &witx::Id, i: &witx::IntDatatype) -> TokenStr
stringify!(#ident).to_owned() stringify!(#ident).to_owned()
} }
fn validate<'a>(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<(), wiggle_runtime::GuestError> { fn validate(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<(), wiggle_runtime::GuestError> {
use ::std::convert::TryFrom; use ::std::convert::TryFrom;
let raw: #repr = unsafe { (location.as_raw() as *const #repr).read() }; let raw: #repr = unsafe { (location.as_raw() as *const #repr).read() };
let _ = #ident::try_from(raw)?; let _ = #ident::try_from(raw)?;
Ok(()) Ok(())
} }
}
impl<'a> wiggle_runtime::GuestTypeCopy<'a> for #ident {} fn read(location: &wiggle_runtime::GuestPtr<#ident>) -> Result<#ident, wiggle_runtime::GuestError> {
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()?) Ok(*location.as_ref()?)
} }
fn write_to_guest(&self, location: &wiggle_runtime::GuestPtrMut<#ident>) {
fn write(&self, location: &wiggle_runtime::GuestPtrMut<#ident>) {
let val: #repr = #repr::from(*self); let val: #repr = #repr::from(*self);
unsafe { (location.as_raw() as *mut #repr).write(val) }; unsafe { (location.as_raw() as *mut #repr).write(val) };
} }
} }
impl<'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident {}
} }
} }
@@ -258,7 +258,7 @@ fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDatatype) -> Toke
} }
} }
impl wiggle_runtime::GuestType for #ident { impl<'a> wiggle_runtime::GuestType<'a> for #ident {
fn size() -> u32 { fn size() -> u32 {
::std::mem::size_of::<#repr>() as u32 ::std::mem::size_of::<#repr>() as u32
} }
@@ -271,24 +271,24 @@ fn define_flags(names: &Names, name: &witx::Id, f: &witx::FlagsDatatype) -> Toke
stringify!(#ident).to_owned() stringify!(#ident).to_owned()
} }
fn validate<'a>(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<(), wiggle_runtime::GuestError> { fn validate(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<(), wiggle_runtime::GuestError> {
use ::std::convert::TryFrom; use ::std::convert::TryFrom;
let raw: #repr = unsafe { (location.as_raw() as *const #repr).read() }; let raw: #repr = unsafe { (location.as_raw() as *const #repr).read() };
let _ = #ident::try_from(raw)?; let _ = #ident::try_from(raw)?;
Ok(()) Ok(())
} }
}
impl<'a> wiggle_runtime::GuestTypeCopy<'a> for #ident {} fn read(location: &wiggle_runtime::GuestPtr<#ident>) -> Result<#ident, wiggle_runtime::GuestError> {
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()?) Ok(*location.as_ref()?)
} }
fn write_to_guest(&self, location: &wiggle_runtime::GuestPtrMut<#ident>) {
fn write(&self, location: &wiggle_runtime::GuestPtrMut<#ident>) {
let val: #repr = #repr::from(*self); let val: #repr = #repr::from(*self);
unsafe { (location.as_raw() as *mut #repr).write(val) }; unsafe { (location.as_raw() as *mut #repr).write(val) };
} }
} }
impl<'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident {}
} }
} }
@@ -364,37 +364,39 @@ fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenS
} }
} }
impl wiggle_runtime::GuestType for #ident { impl<'a> wiggle_runtime::GuestType<'a> for #ident {
fn size() -> u32 { fn size() -> u32 {
::std::mem::size_of::<#repr>() as u32 ::std::mem::size_of::<#repr>() as u32
} }
fn align() -> u32 { fn align() -> u32 {
::std::mem::align_of::<#repr>() as u32 ::std::mem::align_of::<#repr>() as u32
} }
fn name() -> String { fn name() -> String {
stringify!(#ident).to_owned() stringify!(#ident).to_owned()
} }
fn validate<'a>(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<(), wiggle_runtime::GuestError> {
fn validate(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<(), wiggle_runtime::GuestError> {
use ::std::convert::TryFrom; use ::std::convert::TryFrom;
let raw: #repr = unsafe { (location.as_raw() as *const #repr).read() }; let raw: #repr = unsafe { (location.as_raw() as *const #repr).read() };
let _ = #ident::try_from(raw)?; let _ = #ident::try_from(raw)?;
Ok(()) Ok(())
} }
}
impl<'a> wiggle_runtime::GuestTypeCopy<'a> for #ident {} fn read(location: &wiggle_runtime::GuestPtr<#ident>) -> Result<#ident, wiggle_runtime::GuestError> {
impl<'a> wiggle_runtime::GuestTypeClone<'a> for #ident {
fn read_from_guest(location: &wiggle_runtime::GuestPtr<#ident>) -> Result<#ident, wiggle_runtime::GuestError> {
// Perform validation as part of as_ref: // Perform validation as part of as_ref:
let r = location.as_ref()?; let r = location.as_ref()?;
Ok(*r) Ok(*r)
} }
fn write_to_guest(&self, location: &wiggle_runtime::GuestPtrMut<#ident>) {
fn write(&self, location: &wiggle_runtime::GuestPtrMut<#ident>) {
let val: #repr = #repr::from(*self); let val: #repr = #repr::from(*self);
unsafe { (location.as_raw() as *mut #repr).write(val) }; unsafe { (location.as_raw() as *mut #repr).write(val) };
} }
} }
impl<'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident {}
} }
} }
@@ -434,30 +436,35 @@ fn define_handle(names: &Names, name: &witx::Id, h: &witx::HandleDatatype) -> To
write!(f, "{}({})", stringify!(#ident), self.0) write!(f, "{}({})", stringify!(#ident), self.0)
} }
} }
impl wiggle_runtime::GuestType for #ident {
impl<'a> wiggle_runtime::GuestType<'a> for #ident {
fn size() -> u32 { fn size() -> u32 {
#size #size
} }
fn align() -> u32 { fn align() -> u32 {
#align #align
} }
fn name() -> String { fn name() -> String {
stringify!(#ident).to_owned() stringify!(#ident).to_owned()
} }
fn validate(ptr: &wiggle_runtime::GuestPtr<#ident>) -> Result<(), wiggle_runtime::GuestError> { fn validate(ptr: &wiggle_runtime::GuestPtr<#ident>) -> Result<(), wiggle_runtime::GuestError> {
Ok(()) Ok(())
} }
}
impl<'a> wiggle_runtime::GuestTypeClone<'a> for #ident { fn read(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<#ident, wiggle_runtime::GuestError> {
fn read_from_guest(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<#ident, wiggle_runtime::GuestError> {
let r = location.as_ref()?; let r = location.as_ref()?;
Ok(*r) Ok(*r)
} }
fn write_to_guest(&self, location: &wiggle_runtime::GuestPtrMut<'a, Self>) {
fn write(&self, location: &wiggle_runtime::GuestPtrMut<'a, Self>) {
unsafe { (location.as_raw() as *mut #ident).write(*self) }; unsafe { (location.as_raw() as *mut #ident).write(*self) };
} }
} }
impl<'a> wiggle_runtime::GuestTypeCopy<'a> for #ident {}
impl<'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident {}
} }
} }
@@ -509,31 +516,35 @@ fn define_copy_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype)
#(#member_decls),* #(#member_decls),*
} }
impl wiggle_runtime::GuestType for #ident { impl<'a> wiggle_runtime::GuestType<'a> for #ident {
fn size() -> u32 { fn size() -> u32 {
#size #size
} }
fn align() -> u32 { fn align() -> u32 {
#align #align
} }
fn name() -> String { fn name() -> String {
stringify!(#ident).to_owned() stringify!(#ident).to_owned()
} }
fn validate(ptr: &wiggle_runtime::GuestPtr<#ident>) -> Result<(), wiggle_runtime::GuestError> { fn validate(ptr: &wiggle_runtime::GuestPtr<#ident>) -> Result<(), wiggle_runtime::GuestError> {
#(#member_valids)* #(#member_valids)*
Ok(()) Ok(())
} }
}
impl<'a> wiggle_runtime::GuestTypeClone<'a> for #ident { fn read(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<#ident, wiggle_runtime::GuestError> {
fn read_from_guest(location: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<#ident, wiggle_runtime::GuestError> {
let r = location.as_ref()?; let r = location.as_ref()?;
Ok(*r) Ok(*r)
} }
fn write_to_guest(&self, location: &wiggle_runtime::GuestPtrMut<'a, Self>) {
fn write(&self, location: &wiggle_runtime::GuestPtrMut<'a, Self>) {
unsafe { (location.as_raw() as *mut #ident).write(*self) }; unsafe { (location.as_raw() as *mut #ident).write(*self) };
} }
} }
impl<'a> wiggle_runtime::GuestTypeCopy<'a> for #ident {}
impl<'a> wiggle_runtime::GuestTypeTransparent<'a> for #ident {}
} }
} }
@@ -604,26 +615,26 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) -
witx::TypeRef::Name(nt) => { witx::TypeRef::Name(nt) => {
let type_ = names.type_(&nt.name); let type_ = names.type_(&nt.name);
quote! { quote! {
let #name = #type_::read_from_guest(&location.cast(#offset)?)?; let #name = <#type_ as wiggle_runtime::GuestType>::read(&location.cast(#offset)?)?;
} }
} }
witx::TypeRef::Value(ty) => match &**ty { witx::TypeRef::Value(ty) => match &**ty {
witx::Type::Builtin(builtin) => { witx::Type::Builtin(builtin) => {
let type_ = names.builtin_type(*builtin, anon_lifetime()); let type_ = names.builtin_type(*builtin, anon_lifetime());
quote! { quote! {
let #name = #type_::read_from_guest(&location.cast(#offset)?)?; let #name = <#type_ as wiggle_runtime::GuestType>::read(&location.cast(#offset)?)?;
} }
} }
witx::Type::Pointer(pointee) => { witx::Type::Pointer(pointee) => {
let pointee_type = names.type_ref(&pointee, anon_lifetime()); let pointee_type = names.type_ref(&pointee, anon_lifetime());
quote! { quote! {
let #name = wiggle_runtime::GuestPtrMut::<#pointee_type>::read_from_guest(&location.cast(#offset)?)?; let #name = <wiggle_runtime::GuestPtrMut::<#pointee_type> as wiggle_runtime::GuestType>::read(&location.cast(#offset)?)?;
} }
} }
witx::Type::ConstPointer(pointee) => { witx::Type::ConstPointer(pointee) => {
let pointee_type = names.type_ref(&pointee, anon_lifetime()); let pointee_type = names.type_ref(&pointee, anon_lifetime());
quote! { quote! {
let #name = wiggle_runtime::GuestPtr::<#pointee_type>::read_from_guest(&location.cast(#offset)?)?; let #name = <wiggle_runtime::GuestPtr::<#pointee_type> as wiggle_runtime::GuestType>::read(&location.cast(#offset)?)?;
} }
} }
_ => unimplemented!("other anonymous struct members"), _ => unimplemented!("other anonymous struct members"),
@@ -635,7 +646,7 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) -
let name = names.struct_member(&ml.member.name); let name = names.struct_member(&ml.member.name);
let offset = ml.offset as u32; let offset = ml.offset as u32;
quote! { quote! {
self.#name.write_to_guest(&location.cast(#offset).expect("cast to inner member")); self.#name.write(&location.cast(#offset).expect("cast to inner member"));
} }
}); });
@@ -645,27 +656,30 @@ fn define_ptr_struct(names: &Names, name: &witx::Id, s: &witx::StructDatatype) -
#(#member_decls),* #(#member_decls),*
} }
impl<'a> wiggle_runtime::GuestType for #ident<'a> { impl<'a> wiggle_runtime::GuestType<'a> for #ident<'a> {
fn size() -> u32 { fn size() -> u32 {
#size #size
} }
fn align() -> u32 { fn align() -> u32 {
#align #align
} }
fn name() -> String { fn name() -> String {
stringify!(#ident).to_owned() stringify!(#ident).to_owned()
} }
fn validate(ptr: &wiggle_runtime::GuestPtr<#ident>) -> Result<(), wiggle_runtime::GuestError> {
fn validate(ptr: &wiggle_runtime::GuestPtr<'a, #ident<'a>>) -> Result<(), wiggle_runtime::GuestError> {
#(#member_valids)* #(#member_valids)*
Ok(()) Ok(())
} }
}
impl<'a> wiggle_runtime::GuestTypeClone<'a> for #ident<'a> { fn read(location: &wiggle_runtime::GuestPtr<'a, #ident<'a>>) -> Result<#ident<'a>, wiggle_runtime::GuestError> {
fn read_from_guest(location: &wiggle_runtime::GuestPtr<'a, #ident<'a>>) -> Result<#ident<'a>, wiggle_runtime::GuestError> {
#(#member_reads)* #(#member_reads)*
Ok(#ident { #(#member_names),* }) Ok(#ident { #(#member_names),* })
} }
fn write_to_guest(&self, location: &wiggle_runtime::GuestPtrMut<'a, Self>) {
fn write(&self, location: &wiggle_runtime::GuestPtrMut<'a, Self>) {
#(#member_writes)* #(#member_writes)*
} }
} }
@@ -694,11 +708,12 @@ fn union_validate(
let err = with_err(v.name.as_str()); let err = with_err(v.name.as_str());
let variantname = names.enum_variant(&v.name); let variantname = names.enum_variant(&v.name);
if let Some(tref) = &v.tref { if let Some(tref) = &v.tref {
let varianttype = names.type_ref(tref, anon_lifetime()); let lifetime = anon_lifetime();
let varianttype = names.type_ref(tref, lifetime.clone());
quote! { quote! {
#tagname::#variantname => { #tagname::#variantname => {
let variant_ptr = ptr.cast::<#varianttype>(#contents_offset).map_err(#err)?; let variant_ptr = ptr.cast::<#varianttype>(#contents_offset).map_err(#err)?;
wiggle_runtime::GuestType::validate(&variant_ptr).map_err(#err)?; <#varianttype as wiggle_runtime::GuestType>::validate(&variant_ptr).map_err(#err)?;
} }
} }
} else { } else {
@@ -743,7 +758,7 @@ fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDatatype) -> Toke
quote! { quote! {
#tagname::#variantname => { #tagname::#variantname => {
let variant_ptr = location.cast::<#varianttype>(#contents_offset).expect("union variant ptr validated"); let variant_ptr = location.cast::<#varianttype>(#contents_offset).expect("union variant ptr validated");
let variant_val = wiggle_runtime::GuestTypeClone::read_from_guest(&variant_ptr)?; let variant_val = <#varianttype as wiggle_runtime::GuestType>::read(&variant_ptr)?;
Ok(#ident::#variantname(variant_val)) Ok(#ident::#variantname(variant_val))
} }
} }
@@ -765,7 +780,7 @@ fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDatatype) -> Toke
#ident::#variantname(contents) => { #ident::#variantname(contents) => {
#write_tag #write_tag
let variant_ptr = location.cast::<#varianttype>(#contents_offset).expect("union variant ptr validated"); let variant_ptr = location.cast::<#varianttype>(#contents_offset).expect("union variant ptr validated");
contents.write_to_guest(&variant_ptr); <#varianttype as wiggle_runtime::GuestType>::write(&contents, &variant_ptr);
} }
} }
} else { } else {
@@ -785,31 +800,35 @@ fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDatatype) -> Toke
pub enum #ident { pub enum #ident {
#(#variants),* #(#variants),*
} }
impl wiggle_runtime::GuestType for #ident {
impl<'a> wiggle_runtime::GuestType<'a> for #ident {
fn size() -> u32 { fn size() -> u32 {
#size #size
} }
fn align() -> u32 { fn align() -> u32 {
#align #align
} }
fn name() -> String { fn name() -> String {
stringify!(#ident).to_owned() stringify!(#ident).to_owned()
} }
fn validate(ptr: &wiggle_runtime::GuestPtr<#ident>) -> Result<(), wiggle_runtime::GuestError> {
fn validate(ptr: &wiggle_runtime::GuestPtr<'a, #ident>) -> Result<(), wiggle_runtime::GuestError> {
#validate #validate
} }
}
impl<#lifetime> wiggle_runtime::GuestTypeClone<#lifetime> for #ident { fn read(location: &wiggle_runtime::GuestPtr<'a, #ident>)
fn read_from_guest(location: &wiggle_runtime::GuestPtr<'a, #ident>)
-> Result<Self, wiggle_runtime::GuestError> { -> Result<Self, wiggle_runtime::GuestError> {
wiggle_runtime::GuestType::validate(location)?; <#ident as wiggle_runtime::GuestType>::validate(location)?;
let tag = *location.cast::<#tagname>(0).expect("validated tag ptr").as_ref().expect("validated tag ref"); let tag = *location.cast::<#tagname>(0).expect("validated tag ptr").as_ref().expect("validated tag ref");
match tag { match tag {
#(#read_variant)* #(#read_variant)*
} }
} }
fn write_to_guest(&self, location: &wiggle_runtime::GuestPtrMut<'a, #ident>) {
fn write(&self, location: &wiggle_runtime::GuestPtrMut<'a, #ident>) {
match self { match self {
#(#write_variant)* #(#write_variant)*
} }
@@ -823,31 +842,34 @@ fn define_union(names: &Names, name: &witx::Id, u: &witx::UnionDatatype) -> Toke
#(#variants),* #(#variants),*
} }
impl<#lifetime> wiggle_runtime::GuestType for #ident<#lifetime> { impl<#lifetime> wiggle_runtime::GuestType<#lifetime> for #ident<#lifetime> {
fn size() -> u32 { fn size() -> u32 {
#size #size
} }
fn align() -> u32 { fn align() -> u32 {
#align #align
} }
fn name() -> String { fn name() -> String {
stringify!(#ident).to_owned() stringify!(#ident).to_owned()
} }
fn validate(ptr: &wiggle_runtime::GuestPtr<#ident>) -> Result<(), wiggle_runtime::GuestError> {
fn validate(ptr: &wiggle_runtime::GuestPtr<#lifetime, #ident<#lifetime>>) -> Result<(), wiggle_runtime::GuestError> {
#validate #validate
} }
}
impl<#lifetime> wiggle_runtime::GuestTypeClone<#lifetime> for #ident<#lifetime> { fn read(location: &wiggle_runtime::GuestPtr<#lifetime, #ident<#lifetime>>)
fn read_from_guest(location: &wiggle_runtime::GuestPtr<'a, #ident>)
-> Result<Self, wiggle_runtime::GuestError> { -> Result<Self, wiggle_runtime::GuestError> {
wiggle_runtime::GuestType::validate(location)?; <#ident as wiggle_runtime::GuestType>::validate(location)?;
let tag = *location.cast::<#tagname>(0).expect("validated tag ptr").as_ref().expect("validated tag ref"); let tag = *location.cast::<#tagname>(0).expect("validated tag ptr").as_ref().expect("validated tag ref");
match tag { match tag {
#(#read_variant)* #(#read_variant)*
} }
} }
fn write_to_guest(&self, location: &wiggle_runtime::GuestPtrMut<'a, #ident>) {
fn write(&self, location: &wiggle_runtime::GuestPtrMut<#lifetime, #ident<#lifetime>>) {
match self { match self {
#(#write_variant)* #(#write_variant)*
} }

View File

@@ -1,26 +1,25 @@
use crate::{GuestError, GuestPtr, GuestPtrMut}; use crate::{GuestError, GuestPtr, GuestPtrMut};
pub trait GuestType: Sized { pub trait GuestType<'a>: Sized + Clone {
// These are morally the same as Rust ::std::mem::size_of / align_of, but they return // These are morally the same as Rust ::std::mem::size_of / align_of, but they return
// a u32 because the wasm memory space is 32 bits. They have a different names so they // a u32 because the wasm memory space is 32 bits. They have a different names so they
// don't collide with the std::mem methods. // don't collide with the std::mem methods.
fn size() -> u32; fn size() -> u32;
fn align() -> u32; fn align() -> u32;
fn name() -> String; fn name() -> String;
fn validate<'a>(location: &GuestPtr<'a, Self>) -> Result<(), GuestError>; fn validate(location: &GuestPtr<'a, Self>) -> Result<(), GuestError>;
fn read(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError>;
fn write(&self, location: &GuestPtrMut<'a, Self>);
} }
pub trait GuestTypeClone<'a>: GuestType + Clone { /// Represents any guest type which can transparently be represented
fn read_from_guest(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError>; /// as a host type.
fn write_to_guest(&self, location: &GuestPtrMut<'a, Self>); pub trait GuestTypeTransparent<'a>: GuestType<'a> + Copy {}
}
// Following trait system in Rust, Copy implies Clone
pub trait GuestTypeCopy<'a>: GuestTypeClone<'a> + Copy {}
macro_rules! builtin_type { macro_rules! builtin_type {
( $( $t:ident ), * ) => { ( $( $t:ident ), * ) => {
$( $(
impl GuestType for $t { impl<'a> GuestType<'a> for $t {
fn size() -> u32 { fn size() -> u32 {
::std::mem::size_of::<$t>() as u32 ::std::mem::size_of::<$t>() as u32
} }
@@ -33,16 +32,14 @@ macro_rules! builtin_type {
fn validate(_ptr: &GuestPtr<$t>) -> Result<(), GuestError> { fn validate(_ptr: &GuestPtr<$t>) -> Result<(), GuestError> {
Ok(()) Ok(())
} }
} fn read(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
impl<'a> GuestTypeClone<'a> for $t {
fn read_from_guest(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
Ok(*location.as_ref()?) Ok(*location.as_ref()?)
} }
fn write_to_guest(&self, location: &GuestPtrMut<'a, Self>) { fn write(&self, location: &GuestPtrMut<'a, Self>) {
unsafe { (location.as_raw() as *mut $t).write(*self) }; unsafe { (location.as_raw() as *mut $t).write(*self) };
} }
} }
impl<'a> GuestTypeCopy<'a> for $t {} impl<'a> GuestTypeTransparent<'a> for $t {}
)* )*
}; };
} }
@@ -50,9 +47,6 @@ macro_rules! builtin_type {
// These definitions correspond to all the witx BuiltinType variants that are Copy: // These definitions correspond to all the witx BuiltinType variants that are Copy:
builtin_type!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, usize); builtin_type!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, usize);
// FIXME implement GuestType for char. needs to validate that its a code point. what is the sizeof a char?
// FIXME implement GuestType for String. how does validate work for array types?
pub trait GuestErrorType { pub trait GuestErrorType {
type Context; type Context;
fn success() -> Self; fn success() -> Self;

View File

@@ -5,7 +5,7 @@ mod memory;
mod region; mod region;
pub use error::GuestError; pub use error::GuestError;
pub use guest_type::{GuestErrorType, GuestType, GuestTypeClone, GuestTypeCopy}; pub use guest_type::{GuestErrorType, GuestType, GuestTypeTransparent};
pub use memory::{ pub use memory::{
GuestArray, GuestMemory, GuestPtr, GuestPtrMut, GuestRef, GuestRefMut, GuestString, GuestArray, GuestMemory, GuestPtr, GuestPtrMut, GuestRef, GuestRefMut, GuestString,
GuestStringRef, GuestStringRef,

View File

@@ -1,11 +1,11 @@
use super::ptr::{GuestPtr, GuestRef}; use super::ptr::{GuestPtr, GuestRef};
use crate::{GuestError, GuestType, GuestTypeCopy}; use crate::{GuestError, GuestType, GuestTypeTransparent};
use std::{fmt, ops::Deref}; use std::{fmt, ops::Deref};
#[derive(Clone)] #[derive(Clone)]
pub struct GuestArray<'a, T> pub struct GuestArray<'a, T>
where where
T: GuestType, T: GuestType<'a>,
{ {
pub(super) ptr: GuestPtr<'a, T>, pub(super) ptr: GuestPtr<'a, T>,
pub(super) num_elems: u32, pub(super) num_elems: u32,
@@ -13,7 +13,7 @@ where
impl<'a, T> fmt::Debug for GuestArray<'a, T> impl<'a, T> fmt::Debug for GuestArray<'a, T>
where where
T: GuestType + fmt::Debug, T: GuestType<'a> + fmt::Debug,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
@@ -26,7 +26,7 @@ where
impl<'a, T> GuestArray<'a, T> impl<'a, T> GuestArray<'a, T>
where where
T: GuestType, T: GuestType<'a>,
{ {
pub fn iter(&self) -> GuestArrayIter<'a, T> { pub fn iter(&self) -> GuestArrayIter<'a, T> {
let next = GuestPtr { let next = GuestPtr {
@@ -44,7 +44,7 @@ where
pub struct GuestArrayIter<'a, T> pub struct GuestArrayIter<'a, T>
where where
T: GuestType, T: GuestType<'a>,
{ {
next: GuestPtr<'a, T>, next: GuestPtr<'a, T>,
num_elems: u32, num_elems: u32,
@@ -53,7 +53,7 @@ where
impl<'a, T> Iterator for GuestArrayIter<'a, T> impl<'a, T> Iterator for GuestArrayIter<'a, T>
where where
T: GuestType, T: GuestType<'a>,
{ {
type Item = Result<GuestPtr<'a, T>, GuestError>; type Item = Result<GuestPtr<'a, T>, GuestError>;
@@ -79,7 +79,7 @@ where
impl<'a, T> GuestArray<'a, T> impl<'a, T> GuestArray<'a, T>
where where
T: GuestTypeCopy<'a>, T: GuestTypeTransparent<'a>,
{ {
pub fn as_ref(&self) -> Result<GuestArrayRef<'a, T>, GuestError> { pub fn as_ref(&self) -> Result<GuestArrayRef<'a, T>, GuestError> {
let mut next = self.ptr.elem(0)?; let mut next = self.ptr.elem(0)?;
@@ -109,7 +109,7 @@ where
pub struct GuestArrayRef<'a, T> pub struct GuestArrayRef<'a, T>
where where
T: GuestTypeCopy<'a>, T: GuestTypeTransparent<'a>,
{ {
ref_: GuestRef<'a, T>, ref_: GuestRef<'a, T>,
num_elems: u32, num_elems: u32,
@@ -117,7 +117,7 @@ where
impl<'a, T> fmt::Debug for GuestArrayRef<'a, T> impl<'a, T> fmt::Debug for GuestArrayRef<'a, T>
where where
T: GuestTypeCopy<'a> + fmt::Debug, T: GuestTypeTransparent<'a> + fmt::Debug,
{ {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!( write!(
@@ -130,7 +130,7 @@ where
impl<'a, T> Deref for GuestArrayRef<'a, T> impl<'a, T> Deref for GuestArrayRef<'a, T>
where where
T: GuestTypeCopy<'a>, T: GuestTypeTransparent<'a>,
{ {
type Target = [T]; type Target = [T];
@@ -148,7 +148,7 @@ where
mod test { mod test {
use crate::{ use crate::{
memory::ptr::{GuestPtr, GuestPtrMut}, memory::ptr::{GuestPtr, GuestPtrMut},
GuestError, GuestMemory, GuestTypeClone, Region, GuestError, GuestMemory, GuestType, Region,
}; };
#[repr(align(4096))] #[repr(align(4096))]
@@ -249,7 +249,7 @@ mod test {
let contents = arr let contents = arr
.iter() .iter()
.map(|ptr_ptr| { .map(|ptr_ptr| {
*GuestTypeClone::read_from_guest(&ptr_ptr.expect("valid ptr to ptr")) *GuestType::read(&ptr_ptr.expect("valid ptr to ptr"))
.expect("valid ptr to some value") .expect("valid ptr to some value")
.as_ref() .as_ref()
.expect("deref ptr to some value") .expect("deref ptr to some value")

View File

@@ -43,7 +43,7 @@ impl<'a> GuestMemory<'a> {
&& r.start <= (self.len - r.len) && r.start <= (self.len - r.len)
} }
pub fn ptr<T: GuestType>(&'a self, at: u32) -> Result<GuestPtr<'a, T>, GuestError> { pub fn ptr<T: GuestType<'a>>(&'a self, at: u32) -> Result<GuestPtr<'a, T>, GuestError> {
let region = Region { let region = Region {
start: at, start: at,
len: T::size(), len: T::size(),
@@ -61,7 +61,7 @@ impl<'a> GuestMemory<'a> {
}) })
} }
pub fn ptr_mut<T: GuestType>(&'a self, at: u32) -> Result<GuestPtrMut<'a, T>, GuestError> { pub fn ptr_mut<T: GuestType<'a>>(&'a self, at: u32) -> Result<GuestPtrMut<'a, T>, GuestError> {
let ptr = self.ptr(at)?; let ptr = self.ptr(at)?;
Ok(GuestPtrMut { Ok(GuestPtrMut {
mem: ptr.mem, mem: ptr.mem,

View File

@@ -1,5 +1,5 @@
use super::{array::GuestArray, GuestMemory}; use super::{array::GuestArray, GuestMemory};
use crate::{borrow::BorrowHandle, GuestError, GuestType, GuestTypeClone, GuestTypeCopy, Region}; use crate::{borrow::BorrowHandle, GuestError, GuestType, GuestTypeTransparent, Region};
use std::{ use std::{
fmt, fmt,
marker::PhantomData, marker::PhantomData,
@@ -26,7 +26,7 @@ where
} }
} }
impl<'a, T: GuestType> GuestPtr<'a, T> { impl<'a, T: GuestType<'a>> GuestPtr<'a, T> {
pub fn as_raw(&self) -> *const u8 { pub fn as_raw(&self) -> *const u8 {
(self.mem.ptr as usize + self.region.start as usize) as *const u8 (self.mem.ptr as usize + self.region.start as usize) as *const u8
} }
@@ -36,7 +36,10 @@ impl<'a, T: GuestType> GuestPtr<'a, T> {
.ptr(self.region.start + (elements * self.region.len as i32) as u32) .ptr(self.region.start + (elements * self.region.len as i32) as u32)
} }
pub fn cast<CastTo: GuestType>(&self, offset: u32) -> Result<GuestPtr<'a, CastTo>, GuestError> { pub fn cast<CastTo: GuestType<'a>>(
&self,
offset: u32,
) -> Result<GuestPtr<'a, CastTo>, GuestError> {
self.mem.ptr(self.region.start + offset) self.mem.ptr(self.region.start + offset)
} }
@@ -57,7 +60,7 @@ impl<'a, T: GuestType> GuestPtr<'a, T> {
impl<'a, T> GuestPtr<'a, T> impl<'a, T> GuestPtr<'a, T>
where where
T: GuestTypeCopy<'a>, T: GuestTypeTransparent<'a>,
{ {
pub fn as_ref(&self) -> Result<GuestRef<'a, T>, GuestError> { pub fn as_ref(&self) -> Result<GuestRef<'a, T>, GuestError> {
T::validate(&self)?; T::validate(&self)?;
@@ -78,16 +81,16 @@ where
impl<'a, T> GuestPtr<'a, T> impl<'a, T> GuestPtr<'a, T>
where where
T: GuestTypeClone<'a>, T: GuestType<'a>,
{ {
pub fn read(&self) -> Result<T, GuestError> { pub fn read(&self) -> Result<T, GuestError> {
T::read_from_guest(self) T::read(self)
} }
} }
impl<'a, T> GuestType for GuestPtr<'a, T> impl<'a, T> GuestType<'a> for GuestPtr<'a, T>
where where
T: GuestType, T: GuestType<'a>,
{ {
fn size() -> u32 { fn size() -> u32 {
4 4
@@ -101,21 +104,16 @@ where
format!("GuestPtr<{}>", T::name()) format!("GuestPtr<{}>", T::name())
} }
fn validate<'b>(location: &GuestPtr<'b, GuestPtr<'b, T>>) -> Result<(), GuestError> { fn validate(location: &GuestPtr<'a, GuestPtr<'a, T>>) -> Result<(), GuestError> {
// location is guaranteed to be in GuestMemory and aligned to 4 // location is guaranteed to be in GuestMemory and aligned to 4
let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) }; let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) };
// GuestMemory can validate that the raw pointer contents are legal for T: // GuestMemory can validate that the raw pointer contents are legal for T:
let _guest_ptr: GuestPtr<T> = location.mem.ptr(raw_ptr)?; let _guest_ptr: GuestPtr<T> = location.mem.ptr(raw_ptr)?;
Ok(()) Ok(())
} }
}
// Operations for reading and writing Ptrs to memory: // Operations for reading and writing Ptrs to memory:
impl<'a, T> GuestTypeClone<'a> for GuestPtr<'a, T> fn read(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
where
T: GuestType + Clone,
{
fn read_from_guest(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
// location is guaranteed to be in GuestMemory and aligned to 4 // location is guaranteed to be in GuestMemory and aligned to 4
let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) }; let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) };
// GuestMemory can validate that the raw pointer contents are legal for T: // GuestMemory can validate that the raw pointer contents are legal for T:
@@ -123,7 +121,7 @@ where
Ok(guest_ptr) Ok(guest_ptr)
} }
fn write_to_guest(&self, location: &GuestPtrMut<'a, Self>) { fn write(&self, location: &GuestPtrMut<'a, Self>) {
// location is guaranteed to be in GuestMemory and aligned to 4 // location is guaranteed to be in GuestMemory and aligned to 4
unsafe { unsafe {
let raw_ptr: *mut u32 = location.as_raw() as *mut u32; let raw_ptr: *mut u32 = location.as_raw() as *mut u32;
@@ -154,7 +152,7 @@ where
impl<'a, T> GuestPtrMut<'a, T> impl<'a, T> GuestPtrMut<'a, T>
where where
T: GuestType, T: GuestType<'a>,
{ {
pub fn as_immut(&self) -> GuestPtr<'a, T> { pub fn as_immut(&self) -> GuestPtr<'a, T> {
GuestPtr { GuestPtr {
@@ -173,7 +171,7 @@ where
.ptr_mut(self.region.start + (elements * self.region.len as i32) as u32) .ptr_mut(self.region.start + (elements * self.region.len as i32) as u32)
} }
pub fn cast<CastTo: GuestType>( pub fn cast<CastTo: GuestType<'a>>(
&self, &self,
offset: u32, offset: u32,
) -> Result<GuestPtrMut<'a, CastTo>, GuestError> { ) -> Result<GuestPtrMut<'a, CastTo>, GuestError> {
@@ -183,7 +181,7 @@ where
impl<'a, T> GuestPtrMut<'a, T> impl<'a, T> GuestPtrMut<'a, T>
where where
T: GuestTypeCopy<'a>, T: GuestTypeTransparent<'a>,
{ {
pub fn as_ref(&self) -> Result<GuestRef<'a, T>, GuestError> { pub fn as_ref(&self) -> Result<GuestRef<'a, T>, GuestError> {
self.as_immut().as_ref() self.as_immut().as_ref()
@@ -208,20 +206,20 @@ where
impl<'a, T> GuestPtrMut<'a, T> impl<'a, T> GuestPtrMut<'a, T>
where where
T: GuestTypeClone<'a>, T: GuestType<'a>,
{ {
pub fn read(&self) -> Result<T, GuestError> { pub fn read(&self) -> Result<T, GuestError> {
T::read_from_guest(&self.as_immut()) T::read(&self.as_immut())
} }
pub fn write(&self, ptr: &T) { pub fn write(&self, ptr: &T) {
T::write_to_guest(ptr, &self); T::write(ptr, &self);
} }
} }
impl<'a, T> GuestType for GuestPtrMut<'a, T> impl<'a, T> GuestType<'a> for GuestPtrMut<'a, T>
where where
T: GuestType, T: GuestType<'a>,
{ {
fn size() -> u32 { fn size() -> u32 {
4 4
@@ -235,21 +233,16 @@ where
format!("GuestPtrMut<{}>", T::name()) format!("GuestPtrMut<{}>", T::name())
} }
fn validate<'b>(location: &GuestPtr<'b, GuestPtrMut<'b, T>>) -> Result<(), GuestError> { fn validate(location: &GuestPtr<'a, GuestPtrMut<'a, T>>) -> Result<(), GuestError> {
// location is guaranteed to be in GuestMemory and aligned to 4 // location is guaranteed to be in GuestMemory and aligned to 4
let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) }; let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) };
// GuestMemory can validate that the raw pointer contents are legal for T: // GuestMemory can validate that the raw pointer contents are legal for T:
let _guest_ptr: GuestPtr<T> = location.mem.ptr(raw_ptr)?; let _guest_ptr: GuestPtr<T> = location.mem.ptr(raw_ptr)?;
Ok(()) Ok(())
} }
}
// Reading and writing GuestPtrMuts to memory: // Reading and writing GuestPtrMuts to memory:
impl<'a, T> GuestTypeClone<'a> for GuestPtrMut<'a, T> fn read(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
where
T: GuestType + Clone,
{
fn read_from_guest(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
// location is guaranteed to be in GuestMemory and aligned to 4 // location is guaranteed to be in GuestMemory and aligned to 4
let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) }; let raw_ptr: u32 = unsafe { *(location.as_raw() as *const u32) };
// GuestMemory can validate that the raw pointer contents are legal for T: // GuestMemory can validate that the raw pointer contents are legal for T:
@@ -257,7 +250,7 @@ where
Ok(guest_ptr_mut) Ok(guest_ptr_mut)
} }
fn write_to_guest(&self, location: &GuestPtrMut<'a, Self>) { fn write(&self, location: &GuestPtrMut<'a, Self>) {
// location is guaranteed to be in GuestMemory and aligned to 4 // location is guaranteed to be in GuestMemory and aligned to 4
unsafe { unsafe {
let raw_ptr: *mut u32 = location.as_raw() as *mut u32; let raw_ptr: *mut u32 = location.as_raw() as *mut u32;
@@ -298,7 +291,7 @@ impl<'a, T> GuestRef<'a, T> {
impl<'a, T> Deref for GuestRef<'a, T> impl<'a, T> Deref for GuestRef<'a, T>
where where
T: GuestTypeCopy<'a>, T: GuestTypeTransparent<'a>,
{ {
type Target = T; type Target = T;
@@ -357,7 +350,7 @@ impl<'a, T> GuestRefMut<'a, T> {
impl<'a, T> ::std::ops::Deref for GuestRefMut<'a, T> impl<'a, T> ::std::ops::Deref for GuestRefMut<'a, T>
where where
T: GuestTypeCopy<'a>, T: GuestTypeTransparent<'a>,
{ {
type Target = T; type Target = T;
@@ -372,7 +365,7 @@ where
impl<'a, T> DerefMut for GuestRefMut<'a, T> impl<'a, T> DerefMut for GuestRefMut<'a, T>
where where
T: GuestTypeCopy<'a>, T: GuestTypeTransparent<'a>,
{ {
fn deref_mut(&mut self) -> &mut Self::Target { fn deref_mut(&mut self) -> &mut Self::Target {
unsafe { unsafe {

View File

@@ -1,5 +1,5 @@
use proptest::prelude::*; use proptest::prelude::*;
use wiggle_runtime::{GuestArray, GuestError, GuestPtr, GuestPtrMut}; use wiggle_runtime::{GuestArray, GuestError, GuestPtr, GuestPtrMut, GuestType};
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx}; use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
wiggle_generate::from_witx!({ wiggle_generate::from_witx!({
@@ -14,7 +14,7 @@ impl arrays::Arrays for WasiCtx {
&mut self, &mut self,
excuses: &types::ConstExcuseArray, excuses: &types::ConstExcuseArray,
) -> Result<types::Excuse, types::Errno> { ) -> Result<types::Excuse, types::Errno> {
let last = wiggle_runtime::GuestTypeClone::read_from_guest( let last = GuestType::read(
&excuses &excuses
.iter() .iter()
.last() .last()
@@ -27,8 +27,7 @@ impl arrays::Arrays for WasiCtx {
fn populate_excuses(&mut self, excuses: &types::ExcuseArray) -> Result<(), types::Errno> { fn populate_excuses(&mut self, excuses: &types::ExcuseArray) -> Result<(), types::Errno> {
for excuse in excuses.iter() { for excuse in excuses.iter() {
let ptr_to_ptr = let ptr_to_ptr = GuestType::read(&excuse.expect("valid ptr to ptr"))
wiggle_runtime::GuestTypeClone::read_from_guest(&excuse.expect("valid ptr to ptr"))
.expect("valid ptr to some Excuse value"); .expect("valid ptr to some Excuse value");
let mut ptr = ptr_to_ptr let mut ptr = ptr_to_ptr
.as_ref_mut() .as_ref_mut()
@@ -226,8 +225,7 @@ impl PopulateExcusesExcercise {
.array(self.elements.len() as u32) .array(self.elements.len() as u32)
.expect("as array"); .expect("as array");
for el in arr.iter() { for el in arr.iter() {
let ptr_to_ptr = let ptr_to_ptr = GuestType::read(&el.expect("valid ptr to ptr"))
wiggle_runtime::GuestTypeClone::read_from_guest(&el.expect("valid ptr to ptr"))
.expect("valid ptr to some Excuse value"); .expect("valid ptr to some Excuse value");
assert_eq!( assert_eq!(
*ptr_to_ptr *ptr_to_ptr

View File

@@ -1,5 +1,5 @@
use proptest::prelude::*; use proptest::prelude::*;
use wiggle_runtime::{GuestError, GuestPtr, GuestPtrMut, GuestRefMut}; use wiggle_runtime::{GuestError, GuestPtr, GuestPtrMut, GuestRefMut, GuestType};
use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx}; use wiggle_test::{impl_errno, HostMemory, MemArea, WasiCtx};
wiggle_generate::from_witx!({ wiggle_generate::from_witx!({
@@ -38,9 +38,7 @@ impl pointers::Pointers for WasiCtx {
println!("wrote to input2_ref {:?}", input3); println!("wrote to input2_ref {:?}", input3);
// Read ptr value from mutable ptr: // Read ptr value from mutable ptr:
let input4_ptr: GuestPtr<types::Excuse> = wiggle_runtime::GuestTypeClone::read_from_guest( let input4_ptr: GuestPtr<types::Excuse> = GuestType::read(&input4_ptr_ptr.as_immut())
&input4_ptr_ptr.as_immut(),
)
.map_err(|e| { .map_err(|e| {
eprintln!("input4_ptr_ptr error: {}", e); eprintln!("input4_ptr_ptr error: {}", e);
types::Errno::InvalidArg types::Errno::InvalidArg