multiple layers of pointers work!
This commit is contained in:
@@ -1,11 +1,9 @@
|
||||
use std::cell::RefCell;
|
||||
use std::marker::PhantomData;
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
|
||||
use crate::borrow::{BorrowHandle, GuestBorrows};
|
||||
use crate::guest_type::GuestType;
|
||||
use crate::region::Region;
|
||||
use crate::{GuestError, GuestType, Region};
|
||||
|
||||
pub struct GuestMemory<'a> {
|
||||
ptr: *mut u8,
|
||||
@@ -30,13 +28,13 @@ impl<'a> GuestMemory<'a> {
|
||||
&& r.start < (self.len - r.len)
|
||||
}
|
||||
|
||||
pub fn ptr<T: GuestType>(&'a self, at: u32) -> Result<GuestPtr<'a, T>, MemoryError> {
|
||||
pub fn ptr<T: GuestType>(&'a self, at: u32) -> Result<GuestPtr<'a, T>, GuestError> {
|
||||
let region = Region {
|
||||
start: at,
|
||||
len: T::size(),
|
||||
};
|
||||
if !self.contains(region) {
|
||||
Err(MemoryError::OutOfBounds(region))?;
|
||||
Err(GuestError::PtrOutOfBounds(region))?;
|
||||
}
|
||||
let mut borrows = self.borrows.borrow_mut();
|
||||
if let Some(handle) = borrows.borrow_immut(region) {
|
||||
@@ -47,17 +45,17 @@ impl<'a> GuestMemory<'a> {
|
||||
type_: PhantomData,
|
||||
})
|
||||
} else {
|
||||
Err(MemoryError::Borrowed(region))
|
||||
Err(GuestError::PtrBorrowed(region))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ptr_mut<T: GuestType>(&'a self, at: u32) -> Result<GuestPtrMut<'a, T>, MemoryError> {
|
||||
pub fn ptr_mut<T: GuestType>(&'a self, at: u32) -> Result<GuestPtrMut<'a, T>, GuestError> {
|
||||
let region = Region {
|
||||
start: at,
|
||||
len: T::size(),
|
||||
};
|
||||
if !self.contains(region) {
|
||||
Err(MemoryError::OutOfBounds(region))?;
|
||||
Err(GuestError::PtrOutOfBounds(region))?;
|
||||
}
|
||||
let mut borrows = self.borrows.borrow_mut();
|
||||
if let Some(handle) = borrows.borrow_mut(region) {
|
||||
@@ -68,13 +66,19 @@ impl<'a> GuestMemory<'a> {
|
||||
type_: PhantomData,
|
||||
})
|
||||
} else {
|
||||
Err(MemoryError::Borrowed(region))
|
||||
Err(GuestError::PtrBorrowed(region))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub trait GuestPtrRead<T> {
|
||||
fn ptr(&self) -> *const u8;
|
||||
/// These methods should not be used by the end user - just by implementations of the
|
||||
/// GuestValueClone and GuestValueCopy traits!
|
||||
pub trait GuestPtrRead<'a, T> {
|
||||
fn mem(&self) -> &'a GuestMemory<'a>;
|
||||
fn region(&self) -> &Region;
|
||||
fn ptr(&self) -> *const u8 {
|
||||
(self.mem().ptr as usize + self.region().start as usize) as *const u8
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GuestPtr<'a, T> {
|
||||
@@ -84,9 +88,31 @@ pub struct GuestPtr<'a, T> {
|
||||
type_: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: GuestType> GuestPtrRead<T> for GuestPtr<'a, T> {
|
||||
fn ptr(&self) -> *const u8 {
|
||||
(self.mem.ptr as usize + self.region.start as usize) as *const u8
|
||||
impl<'a, T> GuestPtrRead<'a, T> for GuestPtr<'a, T> {
|
||||
fn mem(&self) -> &'a GuestMemory<'a> {
|
||||
self.mem
|
||||
}
|
||||
fn region(&self) -> &Region {
|
||||
&self.region
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> GuestType for GuestPtr<'a, T> {
|
||||
fn size() -> u32 {
|
||||
4
|
||||
}
|
||||
fn name() -> &'static str {
|
||||
"GuestPtr<...>"
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: GuestType> GuestPtr<'a, T> {
|
||||
pub fn read_ptr<P: GuestPtrRead<'a, Self>>(src: &P) -> Result<Self, GuestError> {
|
||||
let raw_ptr = unsafe { ::std::ptr::read_unaligned(src.ptr() as *const u32) };
|
||||
src.mem().ptr(raw_ptr)
|
||||
}
|
||||
pub fn write_ptr(ptr: &Self, dest: &GuestPtrMut<Self>) {
|
||||
unsafe { ::std::ptr::write_unaligned(dest.ptr_mut() as *mut u32, ptr.region.start) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,9 +130,12 @@ pub struct GuestPtrMut<'a, T> {
|
||||
type_: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<'a, T: GuestType> GuestPtrRead<T> for GuestPtrMut<'a, T> {
|
||||
fn ptr(&self) -> *const u8 {
|
||||
(self.mem.ptr as usize + self.region.start as usize) as *const u8
|
||||
impl<'a, T> GuestPtrRead<'a, T> for GuestPtrMut<'a, T> {
|
||||
fn mem(&self) -> &'a GuestMemory<'a> {
|
||||
self.mem
|
||||
}
|
||||
fn region(&self) -> &Region {
|
||||
&self.region
|
||||
}
|
||||
}
|
||||
|
||||
@@ -115,6 +144,7 @@ impl<'a, T> GuestPtrMut<'a, T> {
|
||||
(self.mem.ptr as usize + self.region.start as usize) as *mut u8
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for GuestPtrMut<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
let mut borrows = self.mem.borrows.borrow_mut();
|
||||
@@ -122,10 +152,29 @@ impl<'a, T> Drop for GuestPtrMut<'a, T> {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum MemoryError {
|
||||
#[error("Out of bounds: {0:?}")]
|
||||
OutOfBounds(Region),
|
||||
#[error("Borrowed: {0:?}")]
|
||||
Borrowed(Region),
|
||||
impl<'a, T> GuestType for GuestPtrMut<'a, T> {
|
||||
fn size() -> u32 {
|
||||
4
|
||||
}
|
||||
fn name() -> &'static str {
|
||||
"GuestPtrMut<...>"
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T: GuestType> GuestPtrMut<'a, T> {
|
||||
pub fn read_ptr<P: GuestPtrRead<'a, Self>>(src: &P) -> Result<Self, GuestError> {
|
||||
let raw_ptr = unsafe { ::std::ptr::read_unaligned(src.ptr() as *const u32) };
|
||||
src.mem().ptr_mut(raw_ptr)
|
||||
}
|
||||
pub fn write_ptr(ptr: &Self, dest: &GuestPtrMut<Self>) {
|
||||
unsafe { ::std::ptr::write_unaligned(dest.ptr_mut() as *mut u32, ptr.region.start) }
|
||||
}
|
||||
|
||||
pub fn as_immut(self) -> GuestPtr<'a, T> {
|
||||
let mem = self.mem;
|
||||
let start = self.region.start;
|
||||
drop(self);
|
||||
mem.ptr(start)
|
||||
.expect("can borrow just-dropped mutable region as immut")
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user