From aa5c5f70188dcfc7137fc54bfc255b03079deab8 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 22 Jan 2020 16:38:25 -0800 Subject: [PATCH] flesh out the guest type traits a bit further --- crates/generate/src/names.rs | 1 + crates/generate/src/types.rs | 56 ++++++++++++-- crates/memory/src/guest_type.rs | 129 +++++++++++++++----------------- crates/memory/src/lib.rs | 2 +- crates/memory/src/memory.rs | 15 +++- 5 files changed, 126 insertions(+), 77 deletions(-) diff --git a/crates/generate/src/names.rs b/crates/generate/src/names.rs index ed59e44e3c..a674f13cfe 100644 --- a/crates/generate/src/names.rs +++ b/crates/generate/src/names.rs @@ -41,6 +41,7 @@ impl Names { } } + #[allow(unused)] pub fn type_ref(&self, tref: &TypeRef) -> TokenStream { match tref { TypeRef::Name(nt) => { diff --git a/crates/generate/src/types.rs b/crates/generate/src/types.rs index 22cc025c9b..4b107f4f90 100644 --- a/crates/generate/src/types.rs +++ b/crates/generate/src/types.rs @@ -36,15 +36,61 @@ fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenS output.extend(quote!(#[repr(#repr)])); output.extend(quote!(#[derive(Copy, Clone, Debug, std::hash::Hash, Eq, PartialEq)])); - let mut inner = TokenStream::new(); - for variant in &e.variants { + let mut variants = TokenStream::new(); + let mut to_repr_cases = TokenStream::new(); + let mut tryfrom_repr_cases = TokenStream::new(); + for (n, variant) in e.variants.iter().enumerate() { + let n = n as u32; let variant_name = names.enum_variant(&variant.name); - inner.extend(quote!(#variant_name,)); + variants.extend(quote!(#variant_name,)); + tryfrom_repr_cases.extend(quote!(#n => Ok(#ident::#variant_name),)); + to_repr_cases.extend(quote!(#ident::#variant_name => #n,)); } + tryfrom_repr_cases + .extend(quote!(_ => Err(::memory::GuestValueError::InvalidEnum(stringify!(#ident))))); + output.extend(quote!(pub enum #ident { - #inner - })); + #variants + } + + impl ::std::convert::TryFrom<#repr> for #ident { + type Error = ::memory::GuestValueError; + fn try_from(value: #repr) -> Result<#ident, ::memory::GuestValueError> { + match value { + #tryfrom_repr_cases + } + } + } + + impl From<#ident> for #repr { + fn from(e: #ident) -> #repr { + match e { + #to_repr_cases + } + } + } + + impl ::memory::GuestType for #ident { + fn size() -> u32 { + ::std::mem::size_of::<#repr>() as u32 + } + fn name() -> &'static str { + stringify!(#ident) + } + } + + impl ::memory::GuestTypeCopy for #ident { + fn read_val(src: ::memory::GuestPtr<#ident>) -> Result<#ident, ::memory::GuestValueError> { + // Get the pointer to memory, cast it to *const #repr, read_unaligned, then use the tryinto + unimplemented!() + } + fn write_val(val: #ident, dest: ::memory::GuestPtrMut<#ident>) { + // use the into<#repr>, get pointer to memory, write_unaligned + unimplemented!() + } + } + )); output } diff --git a/crates/memory/src/guest_type.rs b/crates/memory/src/guest_type.rs index c34aa0fce4..820e3b28f2 100644 --- a/crates/memory/src/guest_type.rs +++ b/crates/memory/src/guest_type.rs @@ -1,75 +1,68 @@ -pub trait GuestType { - fn len() -> u32; +use crate::{GuestPtr, GuestPtrMut}; +use thiserror::Error; + +pub trait GuestType: Sized { + fn size() -> u32; + fn name() -> &'static str; } -impl GuestType for u8 { - fn len() -> u32 { - 1 +#[derive(Debug, Error)] +pub enum GuestValueError { + #[error("Invalid enum {0}")] + InvalidEnum(&'static str), +} + +pub trait GuestTypeCopy: GuestType + Copy { + fn read_val(src: GuestPtr) -> Result; + fn write_val(val: Self, dest: GuestPtrMut); +} + +pub trait GuestTypeClone: GuestType + Clone { + fn read_ref(src: GuestPtr, dest: &mut Self) -> Result<(), GuestValueError>; + fn write_ref(val: &Self, dest: GuestPtrMut); +} + +impl GuestTypeClone for T +where + T: GuestTypeCopy, +{ + fn read_ref(src: GuestPtr, dest: &mut T) -> Result<(), GuestValueError> { + let val = GuestTypeCopy::read_val(src)?; + *dest = val; + Ok(()) + } + fn write_ref(val: &T, dest: GuestPtrMut) { + GuestTypeCopy::write_val(*val, dest) } } -impl GuestType for i8 { - fn len() -> u32 { - 1 - } +macro_rules! builtin_copy { + ( $( $t:ident ), * ) => { + $( + impl GuestType for $t { + fn size() -> u32 { + ::std::mem::size_of::<$t>() as u32 + } + fn name() -> &'static str { + ::std::stringify!($t) + } + } + + impl GuestTypeCopy for $t { + fn read_val(src: GuestPtr<$t>) -> Result<$t, GuestValueError> { + Ok(unsafe { + ::std::ptr::read_unaligned(src.ptr() as *const $t) + }) + } + fn write_val(val: $t, dest: GuestPtrMut<$t>) { + unsafe { + ::std::ptr::write_unaligned(dest.ptr_mut() as *mut $t, val) + } + } + } + )* + }; } -impl GuestType for u16 { - fn len() -> u32 { - 2 - } -} - -impl GuestType for i16 { - fn len() -> u32 { - 2 - } -} - -impl GuestType for u32 { - fn len() -> u32 { - 4 - } -} - -impl GuestType for i32 { - fn len() -> u32 { - 4 - } -} - -impl GuestType for f32 { - fn len() -> u32 { - 4 - } -} - -impl GuestType for u64 { - fn len() -> u32 { - 8 - } -} - -impl GuestType for i64 { - fn len() -> u32 { - 8 - } -} - -impl GuestType for f64 { - fn len() -> u32 { - 8 - } -} - -impl GuestType for char { - fn len() -> u32 { - 1 - } -} - -impl GuestType for usize { - fn len() -> u32 { - 4 - } -} +// These definitions correspond to all the witx BuiltinType variants that are Copy: +builtin_copy!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, usize, char); diff --git a/crates/memory/src/lib.rs b/crates/memory/src/lib.rs index b8ade8806c..6b8edeb287 100644 --- a/crates/memory/src/lib.rs +++ b/crates/memory/src/lib.rs @@ -3,6 +3,6 @@ mod guest_type; mod memory; mod region; -pub use guest_type::GuestType; +pub use guest_type::{GuestType, GuestTypeClone, GuestTypeCopy, GuestValueError}; pub use memory::{GuestMemory, GuestPtr, GuestPtrMut}; pub use region::Region; diff --git a/crates/memory/src/memory.rs b/crates/memory/src/memory.rs index 7cffb52606..efb027550e 100644 --- a/crates/memory/src/memory.rs +++ b/crates/memory/src/memory.rs @@ -33,7 +33,7 @@ impl<'a> GuestMemory<'a> { pub fn ptr(&'a self, at: u32) -> Result, MemoryError> { let r = Region { start: at, - len: T::len(), + len: T::size(), }; let mut borrows = self.borrows.borrow_mut(); if !self.contains(r) { @@ -53,7 +53,7 @@ impl<'a> GuestMemory<'a> { pub fn ptr_mut(&'a self, at: u32) -> Result, MemoryError> { let r = Region { start: at, - len: T::len(), + len: T::size(), }; let mut borrows = self.borrows.borrow_mut(); if !self.contains(r) { @@ -77,10 +77,19 @@ pub struct GuestPtr<'a, T> { type_: PhantomData, } -impl<'a, T> GuestPtr<'a, T> { +impl<'a, T: GuestType> GuestPtr<'a, T> { pub fn ptr(&self) -> *const u8 { (self.mem.ptr as usize + self.region.start as usize) as *const u8 } + + pub unsafe fn downcast(self) -> GuestPtr<'a, Q> { + debug_assert!(T::size() == Q::size(), "downcast to type of same size"); + GuestPtr { + mem: self.mem, + region: self.region, + type_: PhantomData, + } + } } impl<'a, T> Drop for GuestPtr<'a, T> {