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

@@ -1,26 +1,25 @@
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
// 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.
fn size() -> u32;
fn align() -> u32;
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 {
fn read_from_guest(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError>;
fn write_to_guest(&self, location: &GuestPtrMut<'a, Self>);
}
// Following trait system in Rust, Copy implies Clone
pub trait GuestTypeCopy<'a>: GuestTypeClone<'a> + Copy {}
/// Represents any guest type which can transparently be represented
/// as a host type.
pub trait GuestTypeTransparent<'a>: GuestType<'a> + Copy {}
macro_rules! builtin_type {
( $( $t:ident ), * ) => {
$(
impl GuestType for $t {
impl<'a> GuestType<'a> for $t {
fn size() -> u32 {
::std::mem::size_of::<$t>() as u32
}
@@ -33,16 +32,14 @@ macro_rules! builtin_type {
fn validate(_ptr: &GuestPtr<$t>) -> Result<(), GuestError> {
Ok(())
}
}
impl<'a> GuestTypeClone<'a> for $t {
fn read_from_guest(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
fn read(location: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
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) };
}
}
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:
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 {
type Context;
fn success() -> Self;

View File

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

View File

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

View File

@@ -43,7 +43,7 @@ impl<'a> GuestMemory<'a> {
&& 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 {
start: at,
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)?;
Ok(GuestPtrMut {
mem: ptr.mem,

View File

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