use crate::{GuestError, GuestPtr};
use std::mem;
use std::sync::atomic::{
AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicU16, AtomicU32, AtomicU64, AtomicU8, Ordering,
};
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> {}
macro_rules! integer_primitives {
($([$ty:ident, $ty_atomic:ident],)*) => ($(
impl<'a> GuestType<'a> 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(ptr: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
let offset = ptr.offset();
let (host_ptr, region) = super::validate_size_align::<Self>(ptr.mem(), offset, 1)?;
let host_ptr = &host_ptr[0];
if ptr.mem().is_mut_borrowed(region) {
return Err(GuestError::PtrBorrowed(region));
}
let atomic_value_ref: &$ty_atomic =
unsafe { &*(host_ptr.get().cast::<$ty_atomic>()) };
let val = atomic_value_ref.load(Ordering::Relaxed);
Ok($ty::from_le(val))
}
#[inline]
fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError> {
let val = val.to_le();
let offset = ptr.offset();
let (host_ptr, region) = super::validate_size_align::<Self>(ptr.mem(), offset, 1)?;
let host_ptr = &host_ptr[0];
if ptr.mem().is_shared_borrowed(region) || ptr.mem().is_mut_borrowed(region) {
return Err(GuestError::PtrBorrowed(region));
}
let atomic_value_ref: &$ty_atomic =
unsafe { &*(host_ptr.get().cast::<$ty_atomic>()) };
atomic_value_ref.store(val, Ordering::Relaxed);
Ok(())
}
}
unsafe impl<'a> GuestTypeTransparent<'a> for $ty {}
)*)
}
macro_rules! float_primitives {
($([$ty:ident, $ty_unsigned:ident, $ty_atomic:ident],)*) => ($(
impl<'a> GuestType<'a> 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(ptr: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
let offset = ptr.offset();
let (host_ptr, region) = super::validate_size_align::<$ty_unsigned>(
ptr.mem(),
offset,
1,
)?;
let host_ptr = &host_ptr[0];
if ptr.mem().is_mut_borrowed(region) {
return Err(GuestError::PtrBorrowed(region));
}
let atomic_value_ref: &$ty_atomic =
unsafe { &*(host_ptr.get().cast::<$ty_atomic>()) };
let value = $ty_unsigned::from_le(atomic_value_ref.load(Ordering::Relaxed));
Ok($ty::from_bits(value))
}
#[inline]
fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError> {
let offset = ptr.offset();
let (host_ptr, region) = super::validate_size_align::<$ty_unsigned>(
ptr.mem(),
offset,
1,
)?;
let host_ptr = &host_ptr[0];
if ptr.mem().is_shared_borrowed(region) || ptr.mem().is_mut_borrowed(region) {
return Err(GuestError::PtrBorrowed(region));
}
let atomic_value_ref: &$ty_atomic =
unsafe { &*(host_ptr.get().cast::<$ty_atomic>()) };
let le_value = $ty_unsigned::to_le(val.to_bits());
atomic_value_ref.store(le_value, Ordering::Relaxed);
Ok(())
}
}
unsafe impl<'a> GuestTypeTransparent<'a> 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<'a, T> GuestType<'a> for GuestPtr<'a, T> {
#[inline]
fn guest_size() -> u32 {
u32::guest_size()
}
#[inline]
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>,
{
#[inline]
fn guest_size() -> u32 {
u32::guest_size() * 2
}
#[inline]
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)
}
}