wiggle_runtime/
guest_type.rs

1use crate::{GuestError, GuestPtr};
2use std::mem;
3
4pub trait GuestErrorType<'a> {
5    type Context;
6    fn success() -> Self;
7    fn from_error(e: GuestError, ctx: &Self::Context) -> Self;
8}
9
10/// A trait for types that are intended to be pointees in `GuestPtr<T>`.
11///
12/// This trait abstracts how to read/write information from the guest memory, as
13/// well as how to offset elements in an array of guest memory. This layer of
14/// abstraction allows the guest representation of a type to be different from
15/// the host representation of a type, if necessary. It also allows for
16/// validation when reading/writing.
17pub trait GuestType<'a>: Sized {
18    /// Returns the size, in bytes, of this type in the guest memory.
19    fn guest_size() -> u32;
20
21    /// Returns the required alignment of this type, in bytes, for both guest
22    /// and host memory.
23    fn guest_align() -> usize;
24
25    /// Reads this value from the provided `ptr`.
26    ///
27    /// Must internally perform any safety checks necessary and is allowed to
28    /// fail if the bytes pointed to are also invalid.
29    ///
30    /// Typically if you're implementing this by hand you'll want to delegate to
31    /// other safe implementations of this trait (e.g. for primitive types like
32    /// `u32`) rather than writing lots of raw code yourself.
33    fn read(ptr: &GuestPtr<'a, Self>) -> Result<Self, GuestError>;
34
35    /// Writes a value to `ptr` after verifying that `ptr` is indeed valid to
36    /// store `val`.
37    ///
38    /// Similar to `read`, you'll probably want to implement this in terms of
39    /// other primitives.
40    fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError>;
41}
42
43/// A trait for `GuestType`s that have the same representation in guest memory
44/// as in Rust. These types can be used with the `GuestPtr::as_raw` method to
45/// view as a slice.
46///
47/// Unsafe trait because a correct GuestTypeTransparent implemengation ensures that the
48/// GuestPtr::as_raw methods are safe. This trait should only ever be implemented
49/// by wiggle_generate-produced code.
50pub unsafe trait GuestTypeTransparent<'a>: GuestType<'a> {
51    /// Checks that the memory at `ptr` is a valid representation of `Self`.
52    ///
53    /// Assumes that memory safety checks have already been performed: `ptr`
54    /// has been checked to be aligned correctly and reside in memory using
55    /// `GuestMemory::validate_size_align`
56    fn validate(ptr: *mut Self) -> Result<(), GuestError>;
57}
58
59macro_rules! primitives {
60    ($($i:ident)*) => ($(
61        impl<'a> GuestType<'a> for $i {
62            fn guest_size() -> u32 { mem::size_of::<Self>() as u32 }
63            fn guest_align() -> usize { mem::align_of::<Self>() }
64
65            #[inline]
66            fn read(ptr: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
67                // Any bit pattern for any primitive implemented with this
68                // macro is safe, so our `validate_size_align` method will
69                // guarantee that if we are given a pointer it's valid for the
70                // size of our type as well as properly aligned. Consequently we
71                // should be able to safely ready the pointer just after we
72                // validated it, returning it along here.
73                let host_ptr = ptr.mem().validate_size_align(
74                    ptr.offset(),
75                    Self::guest_align(),
76                    Self::guest_size(),
77                )?;
78                Ok(unsafe { *host_ptr.cast::<Self>() })
79            }
80
81            #[inline]
82            fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError> {
83                let host_ptr = ptr.mem().validate_size_align(
84                    ptr.offset(),
85                    Self::guest_align(),
86                    Self::guest_size(),
87                )?;
88                // Similar to above `as_raw` will do a lot of validation, and
89                // then afterwards we can safely write our value into the
90                // memory location.
91                unsafe {
92                    *host_ptr.cast::<Self>() = val;
93                }
94                Ok(())
95            }
96        }
97
98        unsafe impl<'a> GuestTypeTransparent<'a> for $i {
99            #[inline]
100            fn validate(_ptr: *mut $i) -> Result<(), GuestError> {
101                // All bit patterns are safe, nothing to do here
102                Ok(())
103            }
104        }
105
106    )*)
107}
108
109primitives! {
110    // signed
111    i8 i16 i32 i64 i128
112    // unsigned
113    u8 u16 u32 u64 u128
114    // floats
115    f32 f64
116}
117
118// Support pointers-to-pointers where pointers are always 32-bits in wasm land
119impl<'a, T> GuestType<'a> for GuestPtr<'a, T> {
120    fn guest_size() -> u32 {
121        u32::guest_size()
122    }
123
124    fn guest_align() -> usize {
125        u32::guest_align()
126    }
127
128    fn read(ptr: &GuestPtr<'a, Self>) -> Result<Self, GuestError> {
129        let offset = ptr.cast::<u32>().read()?;
130        Ok(GuestPtr::new(ptr.mem(), offset))
131    }
132
133    fn write(ptr: &GuestPtr<'_, Self>, val: Self) -> Result<(), GuestError> {
134        ptr.cast::<u32>().write(val.offset())
135    }
136}