wasui_memory/preview1/
mod.rs

1//! A trait that has an interface similar to `wiggle::GuestMemory`.
2//!
3//! This library provides abstractions for guest memory access
4
5mod backends;
6mod guest_type;
7pub use guest_type::{GuestErrorType, GuestType};
8
9#[derive(Debug, thiserror::Error)]
10pub enum GuestError {
11    #[error("Pointer overflow")]
12    PtrOverflow,
13    #[error("Invalid pointer")]
14    InvalidPointer,
15    #[error("Invalid data")]
16    InvalidData,
17    #[error("Invalid memory")]
18    InvalidMemory,
19}
20
21pub trait Memory: Sized {
22    fn copy_to_slice(&self, ptr: GuestPtr<[u8]>, dst: &mut [u8]) -> Result<(), GuestError>;
23
24    fn copy_to_vec(&self, ptr: GuestPtr<[u8]>) -> Result<Vec<u8>, GuestError> {
25        let mut data = vec![0; ptr.len() as usize];
26        self.copy_to_slice(ptr, &mut data)?;
27        Ok(data)
28    }
29
30    fn read<T>(&self, ptr: GuestPtr<T>) -> Result<T, GuestError>
31    where
32        T: GuestType,
33    {
34        T::read(self, ptr)
35    }
36}
37
38pub trait MemoryMut: Sized {
39    fn copy_from_slice(&mut self, ptr: GuestPtr<[u8]>, src: &[u8]) -> Result<(), GuestError>;
40    fn write<T>(&mut self, ptr: GuestPtr<T>, value: T) -> Result<(), GuestError>
41    where
42        T: GuestType,
43    {
44        T::write(self, ptr, value)
45    }
46}
47
48pub trait GuestMemory: Memory + MemoryMut {}
49
50#[repr(transparent)]
51#[derive(Copy, Clone, PartialEq)]
52pub struct GuestPtr<T: ?Sized + Pointee> {
53    pointer: T::Pointer,
54}
55
56impl<T: ?Sized + Pointee> GuestPtr<T> {
57    pub fn new(pointer: T::Pointer) -> Self {
58        Self { pointer }
59    }
60
61    pub fn offset(&self) -> T::Pointer {
62        self.pointer
63    }
64
65    /// Casts this `GuestPtr` type to a different type.
66    ///
67    /// This is a safe method which is useful for simply reinterpreting the type
68    /// parameter on this `GuestPtr`. Note that this is a safe method, where
69    /// again there's no guarantees about alignment, validity, in-bounds-ness,
70    /// etc of the returned pointer.
71    pub fn cast<U>(&self) -> GuestPtr<U>
72    where
73        U: Pointee<Pointer = T::Pointer> + ?Sized,
74    {
75        GuestPtr::new(self.pointer)
76    }
77
78    /// Performs pointer arithmetic on this pointer, moving the pointer forward
79    /// `amt` slots.
80    ///
81    /// This will either return the resulting pointer or `Err` if the pointer
82    /// arithmetic calculation would overflow around the end of the address
83    /// space.
84    pub fn add(&self, amt: u32) -> Result<GuestPtr<T>, GuestError>
85    where
86        T: GuestType + Pointee<Pointer = u32>,
87    {
88        let offset = amt
89            .checked_mul(T::guest_size())
90            .and_then(|o| self.pointer.checked_add(o));
91        let offset = match offset {
92            Some(o) => o,
93            None => return Err(GuestError::PtrOverflow),
94        };
95        Ok(GuestPtr::new(offset))
96    }
97
98    /// Returns a `GuestPtr` for an array of `T`s using this pointer as the
99    /// base.
100    pub fn as_array(&self, elems: u32) -> GuestPtr<[T]>
101    where
102        T: GuestType + Pointee<Pointer = u32>,
103    {
104        GuestPtr::new((self.pointer, elems))
105    }
106}
107
108impl<T> GuestPtr<[T]> {
109    pub fn offset_base(&self) -> u32 {
110        self.pointer.0
111    }
112
113    #[allow(clippy::len_without_is_empty)]
114    pub fn len(&self) -> u32 {
115        self.pointer.1
116    }
117
118    pub fn iter(&self) -> impl ExactSizeIterator<Item = Result<GuestPtr<T>, GuestError>> + '_
119    where
120        T: GuestType,
121    {
122        let base = self.as_ptr();
123        (0..self.len()).map(move |i| base.add(i))
124    }
125
126    pub fn as_ptr(&self) -> GuestPtr<T> {
127        GuestPtr::new(self.pointer.0)
128    }
129}
130
131impl GuestPtr<str> {
132    pub fn as_bytes(&self) -> GuestPtr<[u8]> {
133        GuestPtr::new((self.pointer.0, self.pointer.1))
134    }
135}
136
137mod private {
138    pub trait Sealed {}
139    impl<T> Sealed for T {}
140    impl<T> Sealed for [T] {}
141    impl Sealed for str {}
142}
143
144pub trait Pointee: private::Sealed {
145    #[doc(hidden)]
146    type Pointer: Copy + PartialEq;
147}
148
149impl<T> Pointee for T {
150    type Pointer = u32;
151}
152
153impl<T> Pointee for [T] {
154    type Pointer = (u32, u32);
155}
156
157impl Pointee for str {
158    type Pointer = (u32, u32);
159}