use crate::{region::Region, GuestError, GuestPtr};
use std::mem;
pub trait GuestErrorType {
fn success() -> Self;
}
pub trait GuestType<'a>: Sized {
fn guest_size() -> u32;
fn guest_align() -> usize;
fn read(ptr: &GuestPtr<'a, Self>) -> Result<Self, GuestError>;
fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError>;
}
pub unsafe trait GuestTypeTransparent<'a>: GuestType<'a> {
fn validate(ptr: *mut Self) -> Result<(), GuestError>;
}
macro_rules! primitives {
($($i:ident)*) => ($(
impl<'a> GuestType<'a> for $i {
fn guest_size() -> u32 { mem::size_of::<Self>() as u32 }
fn guest_align() -> usize { mem::align_of::<Self>() }
#[inline]
fn read(ptr: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
let offset = ptr.offset();
let size = Self::guest_size();
let host_ptr = ptr.mem().validate_size_align(
offset,
Self::guest_align(),
size,
)?;
let region = Region {
start: offset,
len: size,
};
if ptr.mem().is_borrowed(region) {
return Err(GuestError::PtrBorrowed(region));
}
Ok(unsafe { *host_ptr.cast::<Self>() })
}
#[inline]
fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError> {
let offset = ptr.offset();
let size = Self::guest_size();
let host_ptr = ptr.mem().validate_size_align(
offset,
Self::guest_align(),
size,
)?;
let region = Region {
start: offset,
len: size,
};
if ptr.mem().is_borrowed(region) {
return Err(GuestError::PtrBorrowed(region));
}
unsafe {
*host_ptr.cast::<Self>() = val;
}
Ok(())
}
}
unsafe impl<'a> GuestTypeTransparent<'a> for $i {
#[inline]
fn validate(_ptr: *mut $i) -> Result<(), GuestError> {
Ok(())
}
}
)*)
}
primitives! {
i8 i16 i32 i64 i128
u8 u16 u32 u64 u128
f32 f64
}
impl<'a, T> GuestType<'a> for GuestPtr<'a, T> {
fn guest_size() -> u32 {
u32::guest_size()
}
fn guest_align() -> usize {
u32::guest_align()
}
fn read(ptr: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
let offset = ptr.cast::<u32>().read()?;
Ok(GuestPtr::new(ptr.mem(), offset))
}
fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError> {
ptr.cast::<u32>().write(val.offset())
}
}
impl<'a, T> GuestType<'a> for GuestPtr<'a, [T]>
where
T: GuestType<'a>,
{
fn guest_size() -> u32 {
u32::guest_size() * 2
}
fn guest_align() -> usize {
u32::guest_align()
}
fn read(ptr: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
let offset = ptr.cast::<u32>().read()?;
let len = ptr.cast::<u32>().add(1)?.read()?;
Ok(GuestPtr::new(ptr.mem(), offset).as_array(len))
}
fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError> {
let (offs, len) = val.offset();
let len_ptr = ptr.cast::<u32>().add(1)?;
ptr.cast::<u32>().write(offs)?;
len_ptr.write(len)
}
}