flesh out the guest type traits a bit further

This commit is contained in:
Pat Hickey
2020-01-22 16:38:25 -08:00
parent b8feffe6e1
commit aa5c5f7018
5 changed files with 126 additions and 77 deletions

View File

@@ -41,6 +41,7 @@ impl Names {
} }
} }
#[allow(unused)]
pub fn type_ref(&self, tref: &TypeRef) -> TokenStream { pub fn type_ref(&self, tref: &TypeRef) -> TokenStream {
match tref { match tref {
TypeRef::Name(nt) => { TypeRef::Name(nt) => {

View File

@@ -36,15 +36,61 @@ fn define_enum(names: &Names, name: &witx::Id, e: &witx::EnumDatatype) -> TokenS
output.extend(quote!(#[repr(#repr)])); output.extend(quote!(#[repr(#repr)]));
output.extend(quote!(#[derive(Copy, Clone, Debug, std::hash::Hash, Eq, PartialEq)])); output.extend(quote!(#[derive(Copy, Clone, Debug, std::hash::Hash, Eq, PartialEq)]));
let mut inner = TokenStream::new(); let mut variants = TokenStream::new();
for variant in &e.variants { 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); 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 { 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 output
} }

View File

@@ -1,75 +1,68 @@
pub trait GuestType { use crate::{GuestPtr, GuestPtrMut};
fn len() -> u32; use thiserror::Error;
pub trait GuestType: Sized {
fn size() -> u32;
fn name() -> &'static str;
} }
impl GuestType for u8 { #[derive(Debug, Error)]
fn len() -> u32 { pub enum GuestValueError {
1 #[error("Invalid enum {0}")]
InvalidEnum(&'static str),
}
pub trait GuestTypeCopy: GuestType + Copy {
fn read_val(src: GuestPtr<Self>) -> Result<Self, GuestValueError>;
fn write_val(val: Self, dest: GuestPtrMut<Self>);
}
pub trait GuestTypeClone: GuestType + Clone {
fn read_ref(src: GuestPtr<Self>, dest: &mut Self) -> Result<(), GuestValueError>;
fn write_ref(val: &Self, dest: GuestPtrMut<Self>);
}
impl<T> GuestTypeClone for T
where
T: GuestTypeCopy,
{
fn read_ref(src: GuestPtr<T>, dest: &mut T) -> Result<(), GuestValueError> {
let val = GuestTypeCopy::read_val(src)?;
*dest = val;
Ok(())
}
fn write_ref(val: &T, dest: GuestPtrMut<T>) {
GuestTypeCopy::write_val(*val, dest)
} }
} }
impl GuestType for i8 { macro_rules! builtin_copy {
fn len() -> u32 { ( $( $t:ident ), * ) => {
1 $(
impl GuestType for $t {
fn size() -> u32 {
::std::mem::size_of::<$t>() as u32
}
fn name() -> &'static str {
::std::stringify!($t)
} }
} }
impl GuestType for u16 { impl GuestTypeCopy for $t {
fn len() -> u32 { fn read_val(src: GuestPtr<$t>) -> Result<$t, GuestValueError> {
2 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 i16 { // These definitions correspond to all the witx BuiltinType variants that are Copy:
fn len() -> u32 { builtin_copy!(u8, i8, u16, i16, u32, i32, u64, i64, f32, f64, usize, char);
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
}
}

View File

@@ -3,6 +3,6 @@ mod guest_type;
mod memory; mod memory;
mod region; mod region;
pub use guest_type::GuestType; pub use guest_type::{GuestType, GuestTypeClone, GuestTypeCopy, GuestValueError};
pub use memory::{GuestMemory, GuestPtr, GuestPtrMut}; pub use memory::{GuestMemory, GuestPtr, GuestPtrMut};
pub use region::Region; pub use region::Region;

View File

@@ -33,7 +33,7 @@ impl<'a> GuestMemory<'a> {
pub fn ptr<T: GuestType>(&'a self, at: u32) -> Result<GuestPtr<'a, T>, MemoryError> { pub fn ptr<T: GuestType>(&'a self, at: u32) -> Result<GuestPtr<'a, T>, MemoryError> {
let r = Region { let r = Region {
start: at, start: at,
len: T::len(), len: T::size(),
}; };
let mut borrows = self.borrows.borrow_mut(); let mut borrows = self.borrows.borrow_mut();
if !self.contains(r) { if !self.contains(r) {
@@ -53,7 +53,7 @@ impl<'a> GuestMemory<'a> {
pub fn ptr_mut<T: GuestType>(&'a self, at: u32) -> Result<GuestPtrMut<'a, T>, MemoryError> { pub fn ptr_mut<T: GuestType>(&'a self, at: u32) -> Result<GuestPtrMut<'a, T>, MemoryError> {
let r = Region { let r = Region {
start: at, start: at,
len: T::len(), len: T::size(),
}; };
let mut borrows = self.borrows.borrow_mut(); let mut borrows = self.borrows.borrow_mut();
if !self.contains(r) { if !self.contains(r) {
@@ -77,10 +77,19 @@ pub struct GuestPtr<'a, T> {
type_: PhantomData<T>, type_: PhantomData<T>,
} }
impl<'a, T> GuestPtr<'a, T> { impl<'a, T: GuestType> GuestPtr<'a, T> {
pub fn ptr(&self) -> *const u8 { pub fn ptr(&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
} }
pub unsafe fn downcast<Q: GuestType>(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> { impl<'a, T> Drop for GuestPtr<'a, T> {