use crate::{GuestError, GuestMemory, GuestPtr};
use std::cell::UnsafeCell;
use std::mem;
use std::sync::atomic::{
AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicU8, AtomicU16, AtomicU32, AtomicU64, Ordering,
};
pub trait GuestErrorType {
fn success() -> Self;
}
pub trait GuestType: Sized {
fn guest_size() -> u32;
fn guest_align() -> usize;
fn read(mem: &GuestMemory, ptr: GuestPtr<Self>) -> Result<Self, GuestError>;
fn write(mem: &mut GuestMemory, ptr: GuestPtr<Self>, val: Self) -> Result<(), GuestError>;
}
pub unsafe trait GuestTypeTransparent: GuestType {}
macro_rules! integer_primitives {
($([$ty:ident, $ty_atomic:ident],)*) => ($(
impl GuestType for $ty {
#[inline]
fn guest_size() -> u32 { mem::size_of::<Self>() as u32 }
#[inline]
fn guest_align() -> usize { mem::align_of::<Self>() }
#[inline]
fn read(mem: &GuestMemory, ptr: GuestPtr<Self>) -> Result<Self, GuestError> {
let offset = ptr.offset();
let host_ptr = mem.validate_size_align::<Self>(offset, 1)?;
let host_ptr: &$ty_atomic = unsafe {
let host_ptr: &UnsafeCell<Self> = &host_ptr[0];
&*((host_ptr as *const UnsafeCell<Self>).cast::<$ty_atomic>())
};
let val = host_ptr.load(Ordering::Relaxed);
Ok($ty::from_le(val))
}
#[inline]
fn write(mem: &mut GuestMemory, ptr: GuestPtr<Self>, val: Self) -> Result<(), GuestError> {
let val = val.to_le();
let offset = ptr.offset();
let host_ptr = mem.validate_size_align::<Self>(offset, 1)?;
let host_ptr = &host_ptr[0];
let atomic_value_ref: &$ty_atomic =
unsafe { &*(host_ptr.get().cast::<$ty_atomic>()) };
atomic_value_ref.store(val, Ordering::Relaxed);
Ok(())
}
}
unsafe impl GuestTypeTransparent for $ty {}
)*)
}
macro_rules! float_primitives {
($([$ty:ident, $ty_unsigned:ident, $ty_atomic:ident],)*) => ($(
impl GuestType for $ty {
#[inline]
fn guest_size() -> u32 { mem::size_of::<Self>() as u32 }
#[inline]
fn guest_align() -> usize { mem::align_of::<Self>() }
#[inline]
fn read(mem: &GuestMemory, ptr: GuestPtr<Self>) -> Result<Self, GuestError> {
<$ty_unsigned as GuestType>::read(mem, ptr.cast()).map($ty::from_bits)
}
#[inline]
fn write(mem:&mut GuestMemory, ptr: GuestPtr<Self>, val: Self) -> Result<(), GuestError> {
<$ty_unsigned as GuestType>::write(mem, ptr.cast(), val.to_bits())
}
}
unsafe impl GuestTypeTransparent for $ty {}
)*)
}
integer_primitives! {
[i8, AtomicI8], [i16, AtomicI16], [i32, AtomicI32], [i64, AtomicI64],
[u8, AtomicU8], [u16, AtomicU16], [u32, AtomicU32], [u64, AtomicU64],
}
float_primitives! {
[f32, u32, AtomicU32], [f64, u64, AtomicU64],
}
impl<T> GuestType for GuestPtr<T> {
#[inline]
fn guest_size() -> u32 {
u32::guest_size()
}
#[inline]
fn guest_align() -> usize {
u32::guest_align()
}
fn read(mem: &GuestMemory, ptr: GuestPtr<Self>) -> Result<Self, GuestError> {
let offset = u32::read(mem, ptr.cast())?;
Ok(GuestPtr::new(offset))
}
fn write(mem: &mut GuestMemory, ptr: GuestPtr<Self>, val: Self) -> Result<(), GuestError> {
u32::write(mem, ptr.cast(), val.offset())
}
}
impl<T> GuestType for GuestPtr<[T]>
where
T: GuestType,
{
#[inline]
fn guest_size() -> u32 {
u32::guest_size() * 2
}
#[inline]
fn guest_align() -> usize {
u32::guest_align()
}
fn read(mem: &GuestMemory, ptr: GuestPtr<Self>) -> Result<Self, GuestError> {
let ptr = ptr.cast::<u32>();
let offset = u32::read(mem, ptr)?;
let len = u32::read(mem, ptr.add(1)?)?;
Ok(GuestPtr::new(offset).as_array(len))
}
fn write(mem: &mut GuestMemory, ptr: GuestPtr<Self>, val: Self) -> Result<(), GuestError> {
let (offset, len) = val.offset();
let ptr = ptr.cast::<u32>();
u32::write(mem, ptr, offset)?;
u32::write(mem, ptr.add(1)?, len)?;
Ok(())
}
}