wiggle: make Mut variants of GuestStr, GuestPtr
This commit is contained in:
@@ -301,12 +301,14 @@ unsafe impl<T: ?Sized + GuestMemory> GuestMemory for Arc<T> {
|
|||||||
/// Note that the type parameter does not need to implement the `Sized` trait,
|
/// Note that the type parameter does not need to implement the `Sized` trait,
|
||||||
/// so you can implement types such as this:
|
/// so you can implement types such as this:
|
||||||
///
|
///
|
||||||
/// * `GuestPtr<'_, str>` - a pointer to a guest string. Has the method
|
/// * `GuestPtr<'_, str>` - a pointer to a guest string. Has the methods
|
||||||
/// [`GuestPtr::as_str`], which gives a dynamically borrow-checked
|
/// [`GuestPtr::as_str_mut`], which gives a dynamically borrow-checked
|
||||||
/// `GuestStr<'_>`, which `DerefMut`s to a `&mut str`.
|
/// `GuestStrMut<'_>`, which `DerefMut`s to a `&mut str`, and
|
||||||
/// * `GuestPtr<'_, [T]>` - a pointer to a guest array. Has the method
|
/// [`GuestPtr::as_str`], which is the immutable version of same.
|
||||||
/// [`GuestPtr::as_slice`], which gives a dynamically borrow-checked
|
/// * `GuestPtr<'_, [T]>` - a pointer to a guest array. Has methods
|
||||||
/// `GuestSlice<'_, T>`, which `DerefMut`s to a `&mut [T]`.
|
/// [`GuestPtr::as_slice_mut`], which gives a dynamically borrow-checked
|
||||||
|
/// `GuestSliceMut<'_, T>`, which `DerefMut`s to a `&mut [T]` and
|
||||||
|
/// [`GuestPtr::as_slice`], which is the immutable version of same.
|
||||||
///
|
///
|
||||||
/// Unsized types such as this may have extra methods and won't have methods
|
/// Unsized types such as this may have extra methods and won't have methods
|
||||||
/// like [`GuestPtr::read`] or [`GuestPtr::write`].
|
/// like [`GuestPtr::read`] or [`GuestPtr::write`].
|
||||||
@@ -486,14 +488,58 @@ impl<'a, T> GuestPtr<'a, [T]> {
|
|||||||
|
|
||||||
/// Attempts to create a [`GuestSlice<'_, T>`] from this pointer, performing
|
/// Attempts to create a [`GuestSlice<'_, T>`] from this pointer, performing
|
||||||
/// bounds checks and type validation. The `GuestSlice` is a smart pointer
|
/// bounds checks and type validation. The `GuestSlice` is a smart pointer
|
||||||
/// that can be used as a `&[T]` or a `&mut [T]` via the `Deref` and `DerefMut`
|
/// that can be used as a `&[T]` via the `Deref` trait.
|
||||||
/// traits. The region of memory backing the slice will be marked as borrowed
|
/// The region of memory backing the slice will be marked as immutably
|
||||||
/// by the [`GuestMemory`] until the `GuestSlice` is dropped.
|
/// borrowed by the [`GuestMemory`] until the `GuestSlice` is dropped.
|
||||||
|
/// Multiple immutable borrows of the same memory are permitted, but only
|
||||||
|
/// one mutable borrow.
|
||||||
///
|
///
|
||||||
/// This function will return a `GuestSlice` into host memory if all checks
|
/// This function will return a `GuestSlice` into host memory if all checks
|
||||||
/// succeed (valid utf-8, valid pointers, memory is not borrowed, etc). If
|
/// succeed (valid utf-8, valid pointers, memory is not borrowed, etc). If
|
||||||
/// any checks fail then `GuestError` will be returned.
|
/// any checks fail then `GuestError` will be returned.
|
||||||
pub fn as_slice(&self) -> Result<GuestSlice<'a, T>, GuestError>
|
pub fn as_slice(&self) -> Result<GuestSlice<'a, T>, GuestError>
|
||||||
|
where
|
||||||
|
T: GuestTypeTransparent<'a>,
|
||||||
|
{
|
||||||
|
let len = match self.pointer.1.checked_mul(T::guest_size()) {
|
||||||
|
Some(l) => l,
|
||||||
|
None => return Err(GuestError::PtrOverflow),
|
||||||
|
};
|
||||||
|
let ptr =
|
||||||
|
self.mem
|
||||||
|
.validate_size_align(self.pointer.0, T::guest_align(), len)? as *mut T;
|
||||||
|
|
||||||
|
let borrow = self.mem.immut_borrow(Region {
|
||||||
|
start: self.pointer.0,
|
||||||
|
len,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// Validate all elements in slice.
|
||||||
|
// SAFETY: ptr has been validated by self.mem.validate_size_align
|
||||||
|
for offs in 0..self.pointer.1 {
|
||||||
|
T::validate(unsafe { ptr.add(offs as usize) })?;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: iff there are no overlapping mut borrows it is valid to construct a &[T]
|
||||||
|
let ptr = unsafe { slice::from_raw_parts(ptr, self.pointer.1 as usize) };
|
||||||
|
|
||||||
|
Ok(GuestSlice {
|
||||||
|
ptr,
|
||||||
|
mem: self.mem,
|
||||||
|
borrow,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempts to create a [`GuestSliceMut<'_, T>`] from this pointer, performing
|
||||||
|
/// bounds checks and type validation. The `GuestSliceMut` is a smart pointer
|
||||||
|
/// that can be used as a `&[T]` or a `&mut [T]` via the `Deref` and `DerefMut`
|
||||||
|
/// traits. The region of memory backing the slice will be marked as borrowed
|
||||||
|
/// by the [`GuestMemory`] until the `GuestSlice` is dropped.
|
||||||
|
///
|
||||||
|
/// This function will return a `GuestSliceMut` into host memory if all checks
|
||||||
|
/// succeed (valid utf-8, valid pointers, memory is not borrowed, etc). If
|
||||||
|
/// any checks fail then `GuestError` will be returned.
|
||||||
|
pub fn as_slice_mut(&self) -> Result<GuestSliceMut<'a, T>, GuestError>
|
||||||
where
|
where
|
||||||
T: GuestTypeTransparent<'a>,
|
T: GuestTypeTransparent<'a>,
|
||||||
{
|
{
|
||||||
@@ -519,7 +565,7 @@ impl<'a, T> GuestPtr<'a, [T]> {
|
|||||||
// SAFETY: iff there are no overlapping borrows it is valid to construct a &mut [T]
|
// SAFETY: iff there are no overlapping borrows it is valid to construct a &mut [T]
|
||||||
let ptr = unsafe { slice::from_raw_parts_mut(ptr, self.pointer.1 as usize) };
|
let ptr = unsafe { slice::from_raw_parts_mut(ptr, self.pointer.1 as usize) };
|
||||||
|
|
||||||
Ok(GuestSlice {
|
Ok(GuestSliceMut {
|
||||||
ptr,
|
ptr,
|
||||||
mem: self.mem,
|
mem: self.mem,
|
||||||
borrow,
|
borrow,
|
||||||
@@ -543,7 +589,7 @@ impl<'a, T> GuestPtr<'a, [T]> {
|
|||||||
T: GuestTypeTransparent<'a> + Copy,
|
T: GuestTypeTransparent<'a> + Copy,
|
||||||
{
|
{
|
||||||
// bounds check ...
|
// bounds check ...
|
||||||
let mut self_slice = self.as_slice()?;
|
let mut self_slice = self.as_slice_mut()?;
|
||||||
// ... length check ...
|
// ... length check ...
|
||||||
if self_slice.len() != slice.len() {
|
if self_slice.len() != slice.len() {
|
||||||
return Err(GuestError::SliceLengthsDiffer);
|
return Err(GuestError::SliceLengthsDiffer);
|
||||||
@@ -621,9 +667,9 @@ impl<'a> GuestPtr<'a, str> {
|
|||||||
|
|
||||||
/// Attempts to create a [`GuestStr<'_>`] from this pointer, performing
|
/// Attempts to create a [`GuestStr<'_>`] from this pointer, performing
|
||||||
/// bounds checks and utf-8 checks. The resulting `GuestStr` can be used
|
/// bounds checks and utf-8 checks. The resulting `GuestStr` can be used
|
||||||
/// as a `&str` or `&mut str` via the `Deref` and `DerefMut` traits. The
|
/// as a `&str` via the `Deref` trait. The region of memory backing the
|
||||||
/// region of memory backing the `str` will be marked as borrowed by the
|
/// `str` will be marked as immutably borrowed by the [`GuestMemory`]
|
||||||
/// [`GuestMemory`] until the `GuestStr` is dropped.
|
/// until the `GuestStr` is dropped.
|
||||||
///
|
///
|
||||||
/// This function will return `GuestStr` into host memory if all checks
|
/// This function will return `GuestStr` into host memory if all checks
|
||||||
/// succeed (valid utf-8, valid pointers, etc). If any checks fail then
|
/// succeed (valid utf-8, valid pointers, etc). If any checks fail then
|
||||||
@@ -633,6 +679,39 @@ impl<'a> GuestPtr<'a, str> {
|
|||||||
.mem
|
.mem
|
||||||
.validate_size_align(self.pointer.0, 1, self.pointer.1)?;
|
.validate_size_align(self.pointer.0, 1, self.pointer.1)?;
|
||||||
|
|
||||||
|
let borrow = self.mem.immut_borrow(Region {
|
||||||
|
start: self.pointer.0,
|
||||||
|
len: self.pointer.1,
|
||||||
|
})?;
|
||||||
|
|
||||||
|
// SAFETY: iff there are no overlapping borrows it is ok to construct
|
||||||
|
// a &mut str.
|
||||||
|
let ptr = unsafe { slice::from_raw_parts(ptr, self.pointer.1 as usize) };
|
||||||
|
// Validate that contents are utf-8:
|
||||||
|
match str::from_utf8(ptr) {
|
||||||
|
Ok(ptr) => Ok(GuestStr {
|
||||||
|
ptr,
|
||||||
|
mem: self.mem,
|
||||||
|
borrow,
|
||||||
|
}),
|
||||||
|
Err(e) => Err(GuestError::InvalidUtf8(e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Attempts to create a [`GuestStrMut<'_>`] from this pointer, performing
|
||||||
|
/// bounds checks and utf-8 checks. The resulting `GuestStrMut` can be used
|
||||||
|
/// as a `&str` or `&mut str` via the `Deref` and `DerefMut` traits. The
|
||||||
|
/// region of memory backing the `str` will be marked as borrowed by the
|
||||||
|
/// [`GuestMemory`] until the `GuestStrMut` is dropped.
|
||||||
|
///
|
||||||
|
/// This function will return `GuestStrMut` into host memory if all checks
|
||||||
|
/// succeed (valid utf-8, valid pointers, etc). If any checks fail then
|
||||||
|
/// `GuestError` will be returned.
|
||||||
|
pub fn as_str_mut(&self) -> Result<GuestStrMut<'a>, GuestError> {
|
||||||
|
let ptr = self
|
||||||
|
.mem
|
||||||
|
.validate_size_align(self.pointer.0, 1, self.pointer.1)?;
|
||||||
|
|
||||||
let borrow = self.mem.mut_borrow(Region {
|
let borrow = self.mem.mut_borrow(Region {
|
||||||
start: self.pointer.0,
|
start: self.pointer.0,
|
||||||
len: self.pointer.1,
|
len: self.pointer.1,
|
||||||
@@ -643,7 +722,7 @@ impl<'a> GuestPtr<'a, str> {
|
|||||||
let ptr = unsafe { slice::from_raw_parts_mut(ptr, self.pointer.1 as usize) };
|
let ptr = unsafe { slice::from_raw_parts_mut(ptr, self.pointer.1 as usize) };
|
||||||
// Validate that contents are utf-8:
|
// Validate that contents are utf-8:
|
||||||
match str::from_utf8_mut(ptr) {
|
match str::from_utf8_mut(ptr) {
|
||||||
Ok(ptr) => Ok(GuestStr {
|
Ok(ptr) => Ok(GuestStrMut {
|
||||||
ptr,
|
ptr,
|
||||||
mem: self.mem,
|
mem: self.mem,
|
||||||
borrow,
|
borrow,
|
||||||
@@ -675,11 +754,10 @@ impl<T: ?Sized + Pointee> fmt::Debug for GuestPtr<'_, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A smart pointer to a mutable slice in guest memory.
|
/// A smart pointer to an immutable slice in guest memory.
|
||||||
/// Usable as a `&'a [T]` via [`std::ops::Deref`] and as a `&'a mut [T]` via
|
/// Usable as a `&'a [T]` via [`std::ops::Deref`].
|
||||||
/// [`std::ops::DerefMut`].
|
|
||||||
pub struct GuestSlice<'a, T> {
|
pub struct GuestSlice<'a, T> {
|
||||||
ptr: &'a mut [T],
|
ptr: &'a [T],
|
||||||
mem: &'a dyn GuestMemory,
|
mem: &'a dyn GuestMemory,
|
||||||
borrow: BorrowHandle,
|
borrow: BorrowHandle,
|
||||||
}
|
}
|
||||||
@@ -691,23 +769,44 @@ impl<'a, T> std::ops::Deref for GuestSlice<'a, T> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, T> std::ops::DerefMut for GuestSlice<'a, T> {
|
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
|
||||||
self.ptr
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<'a, T> Drop for GuestSlice<'a, T> {
|
impl<'a, T> Drop for GuestSlice<'a, T> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.mem.unborrow(self.borrow)
|
self.mem.unborrow(self.borrow)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A smart pointer to a mutable `str` in guest memory.
|
/// A smart pointer to a mutable slice in guest memory.
|
||||||
/// Usable as a `&'a str` via [`std::ops::Deref`] and as a `&'a mut str` via
|
/// Usable as a `&'a [T]` via [`std::ops::Deref`] and as a `&'a mut [T]` via
|
||||||
/// [`std::ops::DerefMut`].
|
/// [`std::ops::DerefMut`].
|
||||||
|
pub struct GuestSliceMut<'a, T> {
|
||||||
|
ptr: &'a mut [T],
|
||||||
|
mem: &'a dyn GuestMemory,
|
||||||
|
borrow: BorrowHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> std::ops::Deref for GuestSliceMut<'a, T> {
|
||||||
|
type Target = [T];
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> std::ops::DerefMut for GuestSliceMut<'a, T> {
|
||||||
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
|
self.ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T> Drop for GuestSliceMut<'a, T> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.mem.unborrow(self.borrow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A smart pointer to an immutable `str` in guest memory.
|
||||||
|
/// Usable as a `&'a str` via [`std::ops::Deref`].
|
||||||
pub struct GuestStr<'a> {
|
pub struct GuestStr<'a> {
|
||||||
ptr: &'a mut str,
|
ptr: &'a str,
|
||||||
mem: &'a dyn GuestMemory,
|
mem: &'a dyn GuestMemory,
|
||||||
borrow: BorrowHandle,
|
borrow: BorrowHandle,
|
||||||
}
|
}
|
||||||
@@ -719,13 +818,35 @@ impl<'a> std::ops::Deref for GuestStr<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> std::ops::DerefMut for GuestStr<'a> {
|
impl<'a> Drop for GuestStr<'a> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.mem.unborrow(self.borrow)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A smart pointer to a mutable `str` in guest memory.
|
||||||
|
/// Usable as a `&'a str` via [`std::ops::Deref`] and as a `&'a mut str` via
|
||||||
|
/// [`std::ops::DerefMut`].
|
||||||
|
pub struct GuestStrMut<'a> {
|
||||||
|
ptr: &'a mut str,
|
||||||
|
mem: &'a dyn GuestMemory,
|
||||||
|
borrow: BorrowHandle,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> std::ops::Deref for GuestStrMut<'a> {
|
||||||
|
type Target = str;
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.ptr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> std::ops::DerefMut for GuestStrMut<'a> {
|
||||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||||
self.ptr
|
self.ptr
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Drop for GuestStr<'a> {
|
impl<'a> Drop for GuestStrMut<'a> {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
self.mem.unborrow(self.borrow)
|
self.mem.unborrow(self.borrow)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user