Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
339 changes: 339 additions & 0 deletions library/core/src/io/io_slice.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,339 @@
use crate::fmt;
use crate::mem::take;
use crate::ops::{Deref, DerefMut};

cfg_select! {
any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty", target_os = "wasi") => {
#[path = "io_slice/repr_iovec.rs"]
mod repr;
}
target_os = "windows" => {
#[path = "io_slice/repr_windows.rs"]
mod repr;
}
target_os = "uefi" => {
#[path = "io_slice/repr_uefi.rs"]
mod repr;
}
_ => {
#[path = "io_slice/repr_generic.rs"]
mod repr;
}
}

/// A buffer type used with `Read::read_vectored`.
///
/// It is semantically a wrapper around a `&mut [u8]`, but is guaranteed to be
/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on
/// Windows.
#[stable(feature = "iovec", since = "1.36.0")]
#[repr(transparent)]
pub struct IoSliceMut<'a>(repr::IoSliceMut<'a>);

#[stable(feature = "iovec_send_sync", since = "1.44.0")]
unsafe impl<'a> Send for IoSliceMut<'a> {}

#[stable(feature = "iovec_send_sync", since = "1.44.0")]
unsafe impl<'a> Sync for IoSliceMut<'a> {}

#[stable(feature = "iovec", since = "1.36.0")]
impl<'a> fmt::Debug for IoSliceMut<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.0.as_slice(), fmt)
}
}

impl<'a> IoSliceMut<'a> {
/// Creates a new `IoSliceMut` wrapping a byte slice.
///
/// # Panics
///
/// Panics on Windows if the slice is larger than 4GB.
#[stable(feature = "iovec", since = "1.36.0")]
#[inline]
pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> {
IoSliceMut(repr::IoSliceMut::new(buf))
}

/// Advance the internal cursor of the slice.
///
/// Also see [`IoSliceMut::advance_slices`] to advance the cursors of
/// multiple buffers.
///
/// # Panics
///
/// Panics when trying to advance beyond the end of the slice.
///
/// # Examples
///
/// ```
/// use std::io::IoSliceMut;
/// use std::ops::Deref;
///
/// let mut data = [1; 8];
/// let mut buf = IoSliceMut::new(&mut data);
///
/// // Mark 3 bytes as read.
/// buf.advance(3);
/// assert_eq!(buf.deref(), [1; 5].as_ref());
/// ```
#[stable(feature = "io_slice_advance", since = "1.81.0")]
#[inline]
pub fn advance(&mut self, n: usize) {
self.0.advance(n)
}

/// Advance a slice of slices.
///
/// Shrinks the slice to remove any `IoSliceMut`s that are fully advanced over.
/// If the cursor ends up in the middle of an `IoSliceMut`, it is modified
/// to start at that cursor.
///
/// For example, if we have a slice of two 8-byte `IoSliceMut`s, and we advance by 10 bytes,
/// the result will only include the second `IoSliceMut`, advanced by 2 bytes.
///
/// # Panics
///
/// Panics when trying to advance beyond the end of the slices.
///
/// # Examples
///
/// ```
/// use std::io::IoSliceMut;
/// use std::ops::Deref;
///
/// let mut buf1 = [1; 8];
/// let mut buf2 = [2; 16];
/// let mut buf3 = [3; 8];
/// let mut bufs = &mut [
/// IoSliceMut::new(&mut buf1),
/// IoSliceMut::new(&mut buf2),
/// IoSliceMut::new(&mut buf3),
/// ][..];
///
/// // Mark 10 bytes as read.
/// IoSliceMut::advance_slices(&mut bufs, 10);
/// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
/// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
/// ```
#[stable(feature = "io_slice_advance", since = "1.81.0")]
#[inline]
pub fn advance_slices(bufs: &mut &mut [IoSliceMut<'a>], n: usize) {
// Number of buffers to remove.
let mut remove = 0;
// Remaining length before reaching n.
let mut left = n;
for buf in bufs.iter() {
if let Some(remainder) = left.checked_sub(buf.len()) {
left = remainder;
remove += 1;
} else {
break;
}
}

*bufs = &mut take(bufs)[remove..];
if bufs.is_empty() {
assert!(left == 0, "advancing io slices beyond their length");
} else {
bufs[0].advance(left);
}
}

/// Get the underlying bytes as a mutable slice with the original lifetime.
///
/// # Examples
///
/// ```
/// #![feature(io_slice_as_bytes)]
/// use std::io::IoSliceMut;
///
/// let mut data = *b"abcdef";
/// let io_slice = IoSliceMut::new(&mut data);
/// io_slice.into_slice()[0] = b'A';
///
/// assert_eq!(&data, b"Abcdef");
/// ```
#[unstable(feature = "io_slice_as_bytes", issue = "132818")]
pub const fn into_slice(self) -> &'a mut [u8] {
self.0.into_slice()
}
}

#[stable(feature = "iovec", since = "1.36.0")]
impl<'a> Deref for IoSliceMut<'a> {
type Target = [u8];

#[inline]
fn deref(&self) -> &[u8] {
self.0.as_slice()
}
}

#[stable(feature = "iovec", since = "1.36.0")]
impl<'a> DerefMut for IoSliceMut<'a> {
#[inline]
fn deref_mut(&mut self) -> &mut [u8] {
self.0.as_mut_slice()
}
}

/// A buffer type used with `Write::write_vectored`.
///
/// It is semantically a wrapper around a `&[u8]`, but is guaranteed to be
/// ABI compatible with the `iovec` type on Unix platforms and `WSABUF` on
/// Windows.
#[stable(feature = "iovec", since = "1.36.0")]
#[derive(Copy, Clone)]
#[repr(transparent)]
pub struct IoSlice<'a>(repr::IoSlice<'a>);

#[stable(feature = "iovec_send_sync", since = "1.44.0")]
unsafe impl<'a> Send for IoSlice<'a> {}

#[stable(feature = "iovec_send_sync", since = "1.44.0")]
unsafe impl<'a> Sync for IoSlice<'a> {}

#[stable(feature = "iovec", since = "1.36.0")]
impl<'a> fmt::Debug for IoSlice<'a> {
fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Debug::fmt(self.0.as_slice(), fmt)
}
}

impl<'a> IoSlice<'a> {
/// Creates a new `IoSlice` wrapping a byte slice.
///
/// # Panics
///
/// Panics on Windows if the slice is larger than 4GB.
#[stable(feature = "iovec", since = "1.36.0")]
#[must_use]
#[inline]
pub fn new(buf: &'a [u8]) -> IoSlice<'a> {
IoSlice(repr::IoSlice::new(buf))
}

/// Advance the internal cursor of the slice.
///
/// Also see [`IoSlice::advance_slices`] to advance the cursors of multiple
/// buffers.
///
/// # Panics
///
/// Panics when trying to advance beyond the end of the slice.
///
/// # Examples
///
/// ```
/// use std::io::IoSlice;
/// use std::ops::Deref;
///
/// let data = [1; 8];
/// let mut buf = IoSlice::new(&data);
///
/// // Mark 3 bytes as read.
/// buf.advance(3);
/// assert_eq!(buf.deref(), [1; 5].as_ref());
/// ```
#[stable(feature = "io_slice_advance", since = "1.81.0")]
#[inline]
pub fn advance(&mut self, n: usize) {
self.0.advance(n)
}

/// Advance a slice of slices.
///
/// Shrinks the slice to remove any `IoSlice`s that are fully advanced over.
/// If the cursor ends up in the middle of an `IoSlice`, it is modified
/// to start at that cursor.
///
/// For example, if we have a slice of two 8-byte `IoSlice`s, and we advance by 10 bytes,
/// the result will only include the second `IoSlice`, advanced by 2 bytes.
///
/// # Panics
///
/// Panics when trying to advance beyond the end of the slices.
///
/// # Examples
///
/// ```
/// use std::io::IoSlice;
/// use std::ops::Deref;
///
/// let buf1 = [1; 8];
/// let buf2 = [2; 16];
/// let buf3 = [3; 8];
/// let mut bufs = &mut [
/// IoSlice::new(&buf1),
/// IoSlice::new(&buf2),
/// IoSlice::new(&buf3),
/// ][..];
///
/// // Mark 10 bytes as written.
/// IoSlice::advance_slices(&mut bufs, 10);
/// assert_eq!(bufs[0].deref(), [2; 14].as_ref());
/// assert_eq!(bufs[1].deref(), [3; 8].as_ref());
#[stable(feature = "io_slice_advance", since = "1.81.0")]
#[inline]
pub fn advance_slices(bufs: &mut &mut [IoSlice<'a>], n: usize) {
// Number of buffers to remove.
let mut remove = 0;
// Remaining length before reaching n. This prevents overflow
// that could happen if the length of slices in `bufs` were instead
// accumulated. Those slice may be aliased and, if they are large
// enough, their added length may overflow a `usize`.
let mut left = n;
for buf in bufs.iter() {
if let Some(remainder) = left.checked_sub(buf.len()) {
left = remainder;
remove += 1;
} else {
break;
}
}

*bufs = &mut take(bufs)[remove..];
if bufs.is_empty() {
assert!(left == 0, "advancing io slices beyond their length");
} else {
bufs[0].advance(left);
}
}

/// Get the underlying bytes as a slice with the original lifetime.
///
/// This doesn't borrow from `self`, so is less restrictive than calling
/// `.deref()`, which does.
///
/// # Examples
///
/// ```
/// #![feature(io_slice_as_bytes)]
/// use std::io::IoSlice;
///
/// let data = b"abcdef";
///
/// let mut io_slice = IoSlice::new(data);
/// let tail = &io_slice.as_slice()[3..];
///
/// // This works because `tail` doesn't borrow `io_slice`
/// io_slice = IoSlice::new(tail);
///
/// assert_eq!(io_slice.as_slice(), b"def");
/// ```
#[unstable(feature = "io_slice_as_bytes", issue = "132818")]
pub const fn as_slice(self) -> &'a [u8] {
self.0.as_slice()
}
}

#[stable(feature = "iovec", since = "1.36.0")]
impl<'a> Deref for IoSlice<'a> {
type Target = [u8];

#[inline]
fn deref(&self) -> &[u8] {
self.0.as_slice()
}
}
Loading
Loading