// Copyright 2023 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34//! Cross platform [`IoBuf`] and [`IoBufMut`] types wrapping `iovec`/`WSABUF`.56use std::fmt;7use std::fmt::Debug;8use std::marker::PhantomData;9use std::slice;1011pub use crate::IoBuf;1213pub(crate) trait PlatformIoBuf {14fn new(ptr: *mut u8, len: usize) -> Self;15fn len(&self) -> usize;16fn ptr(&self) -> *mut u8;17fn set_len(&mut self, len: usize);18fn set_ptr(&mut self, ptr: *mut u8);19}2021/// Cross-platform mutable buffer.22///23/// This type is essentialy `std::io::IoSliceMut`, and guaranteed to be ABI-compatible with24/// `libc::iovec` on Linux/`WSABUF` on Windows; however, it does NOT automatically deref to `&mut25/// [u8]`, which is critical because it can point to guest memory. (Guest memory is implicitly26/// mutably borrowed by the guest, so another mutable borrow would violate Rust assumptions about27/// references.)28#[derive(Copy, Clone)]29#[repr(transparent)]30pub struct IoBufMut<'a> {31iobuf: IoBuf,32phantom: PhantomData<&'a mut [u8]>,33}3435impl<'a> IoBufMut<'a> {36pub fn new(buf: &mut [u8]) -> IoBufMut<'a> {37// SAFETY:38// Safe because buf's memory is of the supplied length, and39// guaranteed to exist for the lifetime of the returned value.40unsafe { Self::from_raw_parts(buf.as_mut_ptr(), buf.len()) }41}4243/// Creates a `IoBufMut` from a pointer and a length.44///45/// # Safety46///47/// In order to use this method safely, `addr` must be valid for reads and writes of `len` bytes48/// and should live for the entire duration of lifetime `'a`.49pub unsafe fn from_raw_parts(addr: *mut u8, len: usize) -> IoBufMut<'a> {50IoBufMut {51iobuf: IoBuf::new(addr, len),52phantom: PhantomData,53}54}5556/// Creates a `IoBufMut` from an IoBuf.57///58/// # Safety59///60/// In order to use this method safely, `iobuf` must be valid for reads and writes through its61/// length and should live for the entire duration of lifetime `'a`.62pub unsafe fn from_iobuf(iobuf: IoBuf) -> IoBufMut<'a> {63IoBufMut {64iobuf,65phantom: PhantomData,66}67}6869/// Advance the internal position of the buffer.70///71/// Panics if `count > self.len()`.72pub fn advance(&mut self, count: usize) {73assert!(count <= self.len());7475self.iobuf.set_len(self.len() - count);7677// SAFETY:78// Safe because we've checked that `count <= self.len()` so both the starting and resulting79// pointer are within the bounds of the allocation.80self.iobuf.set_ptr(unsafe { self.as_mut_ptr().add(count) });81}8283/// Shorten the length of the buffer.84///85/// Has no effect if `len > self.len()`.86pub fn truncate(&mut self, len: usize) {87if len < self.len() {88self.iobuf.set_len(len);89}90}9192#[inline]93pub fn len(&self) -> usize {94self.iobuf.len()95}9697#[inline]98pub fn is_empty(&self) -> bool {99self.len() == 0100}101102/// Gets a const pointer to this slice's memory.103#[inline]104pub fn as_ptr(&self) -> *const u8 {105self.iobuf.ptr() as *const u8106}107108/// Gets a mutable pointer to this slice's memory.109#[inline]110pub fn as_mut_ptr(&self) -> *mut u8 {111self.iobuf.ptr()112}113114/// Converts a slice of `IoBufMut`s into a slice of `IoBuf`s.115#[allow(clippy::wrong_self_convention)]116#[inline]117pub fn as_iobufs<'slice>(iovs: &'slice [IoBufMut<'_>]) -> &'slice [IoBuf] {118// SAFETY:119// Safe because `IoBufMut` is ABI-compatible with `IoBuf`.120unsafe { slice::from_raw_parts(iovs.as_ptr() as *const IoBuf, iovs.len()) }121}122123/// Converts a mutable slice of `IoBufMut`s into a mutable slice of `IoBuf`s.124#[inline]125pub fn as_iobufs_mut<'slice>(iovs: &'slice mut [IoBufMut<'_>]) -> &'slice mut [IoBuf] {126// SAFETY:127// Safe because `IoBufMut` is ABI-compatible with `IoBuf`.128unsafe { slice::from_raw_parts_mut(iovs.as_mut_ptr() as *mut IoBuf, iovs.len()) }129}130}131132impl AsRef<IoBuf> for IoBufMut<'_> {133fn as_ref(&self) -> &IoBuf {134&self.iobuf135}136}137138impl AsMut<IoBuf> for IoBufMut<'_> {139fn as_mut(&mut self) -> &mut IoBuf {140&mut self.iobuf141}142}143144// SAFETY:145// It's safe to implement Send + Sync for this type for the same reason that `std::io::IoSliceMut`146// is Send + Sync. Internally, it contains a pointer and a length. The integer length is safely Send147// + Sync. There's nothing wrong with sending a pointer between threads and de-referencing the148// pointer requires an unsafe block anyway. See also https://github.com/rust-lang/rust/pull/70342.149unsafe impl Send for IoBufMut<'_> {}150// SAFETY: See comments for impl Send151unsafe impl Sync for IoBufMut<'_> {}152153impl Debug for IoBufMut<'_> {154fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {155f.debug_struct("IoBufMut")156.field("ptr", &self.iobuf.ptr())157.field("len", &self.iobuf.len())158.finish()159}160}161162163