diff --git a/library/core/src/io/io_slice.rs b/library/core/src/io/io_slice.rs new file mode 100644 index 0000000000000..0bdd410d3e964 --- /dev/null +++ b/library/core/src/io/io_slice.rs @@ -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() + } +} diff --git a/library/std/src/sys/io/io_slice/unsupported.rs b/library/core/src/io/io_slice/repr_generic.rs similarity index 50% rename from library/std/src/sys/io/io_slice/unsupported.rs rename to library/core/src/io/io_slice/repr_generic.rs index 1572cac6cd771..1cd54088410a1 100644 --- a/library/std/src/sys/io/io_slice/unsupported.rs +++ b/library/core/src/io/io_slice/repr_generic.rs @@ -1,52 +1,52 @@ use crate::mem; #[derive(Copy, Clone)] -pub struct IoSlice<'a>(&'a [u8]); +pub(super) struct IoSlice<'a>(&'a [u8]); impl<'a> IoSlice<'a> { #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + pub(super) fn new(buf: &'a [u8]) -> IoSlice<'a> { IoSlice(buf) } #[inline] - pub fn advance(&mut self, n: usize) { + pub(super) fn advance(&mut self, n: usize) { self.0 = &self.0[n..] } #[inline] - pub const fn as_slice(&self) -> &'a [u8] { + pub(super) const fn as_slice(&self) -> &'a [u8] { self.0 } } -pub struct IoSliceMut<'a>(&'a mut [u8]); +pub(super) struct IoSliceMut<'a>(&'a mut [u8]); impl<'a> IoSliceMut<'a> { #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + pub(super) fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { IoSliceMut(buf) } #[inline] - pub fn advance(&mut self, n: usize) { + pub(super) fn advance(&mut self, n: usize) { let slice = mem::take(&mut self.0); let (_, remaining) = slice.split_at_mut(n); self.0 = remaining; } #[inline] - pub fn as_slice(&self) -> &[u8] { + pub(super) fn as_slice(&self) -> &[u8] { self.0 } #[inline] - pub const fn into_slice(self) -> &'a mut [u8] { + pub(super) const fn into_slice(self) -> &'a mut [u8] { self.0 } #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { + pub(super) fn as_mut_slice(&mut self) -> &mut [u8] { self.0 } } diff --git a/library/std/src/sys/io/io_slice/iovec.rs b/library/core/src/io/io_slice/repr_iovec.rs similarity index 54% rename from library/std/src/sys/io/io_slice/iovec.rs rename to library/core/src/io/io_slice/repr_iovec.rs index d549aca250d5f..ff1a211fec18b 100644 --- a/library/std/src/sys/io/io_slice/iovec.rs +++ b/library/core/src/io/io_slice/repr_iovec.rs @@ -1,24 +1,24 @@ -#[cfg(target_os = "hermit")] -use hermit_abi::iovec; -#[cfg(any(target_family = "unix", target_os = "trusty", target_os = "wasi"))] -use libc::iovec; - use crate::ffi::c_void; use crate::marker::PhantomData; use crate::slice; -#[cfg(target_os = "solid_asp3")] -use crate::sys::pal::abi::sockets::iovec; + +#[derive(Copy, Clone)] +#[repr(C)] +struct iovec { + iov_base: *mut c_void, + iov_len: usize, +} #[derive(Copy, Clone)] #[repr(transparent)] -pub struct IoSlice<'a> { +pub(super) struct IoSlice<'a> { vec: iovec, _p: PhantomData<&'a [u8]>, } impl<'a> IoSlice<'a> { #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + pub(super) fn new(buf: &'a [u8]) -> IoSlice<'a> { IoSlice { vec: iovec { iov_base: buf.as_ptr() as *mut u8 as *mut c_void, iov_len: buf.len() }, _p: PhantomData, @@ -26,11 +26,14 @@ impl<'a> IoSlice<'a> { } #[inline] - pub fn advance(&mut self, n: usize) { + pub(super) fn advance(&mut self, n: usize) { if self.vec.iov_len < n { panic!("advancing IoSlice beyond its length"); } + // SAFETY: + // * `n <= iov_len` as asserted above. + // * The allocation pointed to by `iov_base` is valid up to `iov_base + iov_len`. unsafe { self.vec.iov_len -= n; self.vec.iov_base = self.vec.iov_base.add(n); @@ -38,20 +41,22 @@ impl<'a> IoSlice<'a> { } #[inline] - pub const fn as_slice(&self) -> &'a [u8] { + pub(super) const fn as_slice(&self) -> &'a [u8] { + // SAFETY: + // * `iov_base` and `iov_len` come from a prior decomposition of a valid slice. unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } } } #[repr(transparent)] -pub struct IoSliceMut<'a> { +pub(super) struct IoSliceMut<'a> { vec: iovec, _p: PhantomData<&'a mut [u8]>, } impl<'a> IoSliceMut<'a> { #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + pub(super) fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { IoSliceMut { vec: iovec { iov_base: buf.as_mut_ptr() as *mut c_void, iov_len: buf.len() }, _p: PhantomData, @@ -59,11 +64,14 @@ impl<'a> IoSliceMut<'a> { } #[inline] - pub fn advance(&mut self, n: usize) { + pub(super) fn advance(&mut self, n: usize) { if self.vec.iov_len < n { panic!("advancing IoSliceMut beyond its length"); } + // SAFETY: + // * `n <= iov_len` as asserted above. + // * The allocation pointed to by `iov_base` is valid up to `iov_base + iov_len`. unsafe { self.vec.iov_len -= n; self.vec.iov_base = self.vec.iov_base.add(n); @@ -71,17 +79,23 @@ impl<'a> IoSliceMut<'a> { } #[inline] - pub fn as_slice(&self) -> &[u8] { + pub(super) fn as_slice(&self) -> &[u8] { + // SAFETY: + // * `iov_base` and `iov_len` come from a prior decomposition of a valid slice. unsafe { slice::from_raw_parts(self.vec.iov_base as *mut u8, self.vec.iov_len) } } #[inline] - pub const fn into_slice(self) -> &'a mut [u8] { + pub(super) const fn into_slice(self) -> &'a mut [u8] { + // SAFETY: + // * `iov_base` and `iov_len` come from a prior decomposition of a valid slice. unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } } #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { + pub(super) fn as_mut_slice(&mut self) -> &mut [u8] { + // SAFETY: + // * `iov_base` and `iov_len` come from a prior decomposition of a valid slice. unsafe { slice::from_raw_parts_mut(self.vec.iov_base as *mut u8, self.vec.iov_len) } } } diff --git a/library/std/src/sys/io/io_slice/uefi.rs b/library/core/src/io/io_slice/repr_uefi.rs similarity index 56% rename from library/std/src/sys/io/io_slice/uefi.rs rename to library/core/src/io/io_slice/repr_uefi.rs index 909cfbea0b7ba..af1f13c8f085a 100644 --- a/library/std/src/sys/io/io_slice/uefi.rs +++ b/library/core/src/io/io_slice/repr_uefi.rs @@ -6,7 +6,7 @@ use crate::slice; #[derive(Copy, Clone)] #[repr(C)] -pub struct IoSlice<'a> { +pub(super) struct IoSlice<'a> { len: u32, data: *const u8, _p: PhantomData<&'a [u8]>, @@ -14,28 +14,34 @@ pub struct IoSlice<'a> { impl<'a> IoSlice<'a> { #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { + pub(super) fn new(buf: &'a [u8]) -> IoSlice<'a> { let len = buf.len().try_into().unwrap(); Self { len, data: buf.as_ptr(), _p: PhantomData } } #[inline] - pub fn advance(&mut self, n: usize) { + pub(super) fn advance(&mut self, n: usize) { self.len = u32::try_from(n) .ok() .and_then(|n| self.len.checked_sub(n)) .expect("advancing IoSlice beyond its length"); + + // SAFETY: + // * `n <= len` as asserted above. + // * The allocation pointed to by `data` is valid up to `data + len`. unsafe { self.data = self.data.add(n) }; } #[inline] - pub const fn as_slice(&self) -> &'a [u8] { + pub(super) const fn as_slice(&self) -> &'a [u8] { + // SAFETY: + // * `data` and `len` come from a prior decomposition of a valid slice. unsafe { slice::from_raw_parts(self.data, self.len as usize) } } } #[repr(C)] -pub struct IoSliceMut<'a> { +pub(super) struct IoSliceMut<'a> { len: u32, data: *mut u8, _p: PhantomData<&'a mut [u8]>, @@ -43,32 +49,42 @@ pub struct IoSliceMut<'a> { impl<'a> IoSliceMut<'a> { #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + pub(super) fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { let len = buf.len().try_into().unwrap(); Self { len, data: buf.as_mut_ptr(), _p: PhantomData } } #[inline] - pub fn advance(&mut self, n: usize) { + pub(super) fn advance(&mut self, n: usize) { self.len = u32::try_from(n) .ok() .and_then(|n| self.len.checked_sub(n)) .expect("advancing IoSlice beyond its length"); + + // SAFETY: + // * `n <= len` as asserted above. + // * The allocation pointed to by `data` is valid up to `data + len`. unsafe { self.data = self.data.add(n) }; } #[inline] - pub fn as_slice(&self) -> &[u8] { + pub(super) fn as_slice(&self) -> &[u8] { + // SAFETY: + // * `data` and `len` come from a prior decomposition of a valid slice. unsafe { slice::from_raw_parts(self.data, self.len as usize) } } #[inline] - pub const fn into_slice(self) -> &'a mut [u8] { + pub(super) const fn into_slice(self) -> &'a mut [u8] { + // SAFETY: + // * `data` and `len` come from a prior decomposition of a valid slice. unsafe { slice::from_raw_parts_mut(self.data, self.len as usize) } } #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { + pub(super) fn as_mut_slice(&mut self) -> &mut [u8] { + // SAFETY: + // * `data` and `len` come from a prior decomposition of a valid slice. unsafe { slice::from_raw_parts_mut(self.data, self.len as usize) } } } diff --git a/library/core/src/io/io_slice/repr_windows.rs b/library/core/src/io/io_slice/repr_windows.rs new file mode 100644 index 0000000000000..5c7b0a68feae4 --- /dev/null +++ b/library/core/src/io/io_slice/repr_windows.rs @@ -0,0 +1,99 @@ +use crate::marker::PhantomData; +use crate::slice; + +#[repr(C)] +#[derive(Clone, Copy)] +struct WSABUF { + len: u32, + buf: *mut u8, +} + +#[derive(Copy, Clone)] +#[repr(transparent)] +pub(super) struct IoSlice<'a> { + vec: WSABUF, + _p: PhantomData<&'a [u8]>, +} + +impl<'a> IoSlice<'a> { + #[inline] + pub(super) fn new(buf: &'a [u8]) -> IoSlice<'a> { + assert!(buf.len() <= u32::MAX as usize); + IoSlice { + vec: WSABUF { len: buf.len() as u32, buf: buf.as_ptr() as *mut u8 }, + _p: PhantomData, + } + } + + #[inline] + pub(super) fn advance(&mut self, n: usize) { + if (self.vec.len as usize) < n { + panic!("advancing IoSlice beyond its length"); + } + + // SAFETY: + // * `n <= len` as asserted above. + // * The allocation pointed to by `buf` is valid up to `buf + len`. + unsafe { + self.vec.len -= n as u32; + self.vec.buf = self.vec.buf.add(n); + } + } + + #[inline] + pub(super) const fn as_slice(&self) -> &'a [u8] { + // SAFETY: + // * `buf` and `len` come from a prior decomposition of a valid slice. + unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) } + } +} + +#[repr(transparent)] +pub(super) struct IoSliceMut<'a> { + vec: WSABUF, + _p: PhantomData<&'a mut [u8]>, +} + +impl<'a> IoSliceMut<'a> { + #[inline] + pub(super) fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { + assert!(buf.len() <= u32::MAX as usize); + IoSliceMut { vec: WSABUF { len: buf.len() as u32, buf: buf.as_mut_ptr() }, _p: PhantomData } + } + + #[inline] + pub(super) fn advance(&mut self, n: usize) { + if (self.vec.len as usize) < n { + panic!("advancing IoSliceMut beyond its length"); + } + + // SAFETY: + // * `n <= len` as asserted above. + // * The allocation pointed to by `buf` is valid up to `buf + len`. + unsafe { + self.vec.len -= n as u32; + self.vec.buf = self.vec.buf.add(n); + } + } + + #[inline] + pub(super) fn as_slice(&self) -> &[u8] { + // SAFETY: + // * `buf` and `len` come from a prior decomposition of a valid slice. + unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) } + } + + #[inline] + pub(super) const fn into_slice(self) -> &'a mut [u8] { + // SAFETY: + // * `buf` and `len` come from a prior decomposition of a valid slice. + unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) } + } + + #[inline] + pub(super) fn as_mut_slice(&mut self) -> &mut [u8] { + // SAFETY: + // * `buf` and `len` come from a prior decomposition of a valid slice. + unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) } + } +} diff --git a/library/core/src/io/mod.rs b/library/core/src/io/mod.rs index 2d8273dd1b2d0..0184d8a49667c 100644 --- a/library/core/src/io/mod.rs +++ b/library/core/src/io/mod.rs @@ -2,6 +2,7 @@ mod borrowed_buf; mod error; +mod io_slice; #[unstable(feature = "core_io_borrowed_buf", issue = "117693")] pub use self::borrowed_buf::{BorrowedBuf, BorrowedCursor}; @@ -9,3 +10,5 @@ pub use self::borrowed_buf::{BorrowedBuf, BorrowedCursor}; pub use self::error::ErrorKind; #[unstable(feature = "raw_os_error_ty", issue = "107792")] pub use self::error::RawOsError; +#[unstable(feature = "core_io", issue = "154046")] +pub use self::io_slice::{IoSlice, IoSliceMut}; diff --git a/library/coretests/tests/io/io_slice.rs b/library/coretests/tests/io/io_slice.rs new file mode 100644 index 0000000000000..4639ef2c6ac41 --- /dev/null +++ b/library/coretests/tests/io/io_slice.rs @@ -0,0 +1,100 @@ +use core::io::{IoSlice, IoSliceMut}; +use core::ops::Deref; + +#[test] +fn io_slice_mut_advance_slices() { + 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), + ][..]; + + // Only in a single buffer.. + IoSliceMut::advance_slices(&mut bufs, 1); + assert_eq!(bufs[0].deref(), [1; 7].as_ref()); + assert_eq!(bufs[1].deref(), [2; 16].as_ref()); + assert_eq!(bufs[2].deref(), [3; 8].as_ref()); + + // Removing a buffer, leaving others as is. + IoSliceMut::advance_slices(&mut bufs, 7); + assert_eq!(bufs[0].deref(), [2; 16].as_ref()); + assert_eq!(bufs[1].deref(), [3; 8].as_ref()); + + // Removing a buffer and removing from the next buffer. + IoSliceMut::advance_slices(&mut bufs, 18); + assert_eq!(bufs[0].deref(), [3; 6].as_ref()); +} + +#[test] +#[should_panic] +fn io_slice_mut_advance_slices_empty_slice() { + let mut empty_bufs = &mut [][..]; + IoSliceMut::advance_slices(&mut empty_bufs, 1); +} + +#[test] +#[should_panic] +fn io_slice_mut_advance_slices_beyond_total_length() { + let mut buf1 = [1; 8]; + let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..]; + + IoSliceMut::advance_slices(&mut bufs, 9); + assert!(bufs.is_empty()); +} + +#[test] +fn io_slice_advance_slices() { + 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)][..]; + + // Only in a single buffer.. + IoSlice::advance_slices(&mut bufs, 1); + assert_eq!(bufs[0].deref(), [1; 7].as_ref()); + assert_eq!(bufs[1].deref(), [2; 16].as_ref()); + assert_eq!(bufs[2].deref(), [3; 8].as_ref()); + + // Removing a buffer, leaving others as is. + IoSlice::advance_slices(&mut bufs, 7); + assert_eq!(bufs[0].deref(), [2; 16].as_ref()); + assert_eq!(bufs[1].deref(), [3; 8].as_ref()); + + // Removing a buffer and removing from the next buffer. + IoSlice::advance_slices(&mut bufs, 18); + assert_eq!(bufs[0].deref(), [3; 6].as_ref()); +} + +#[test] +#[should_panic] +fn io_slice_advance_slices_empty_slice() { + let mut empty_bufs = &mut [][..]; + IoSlice::advance_slices(&mut empty_bufs, 1); +} + +#[test] +#[should_panic] +fn io_slice_advance_slices_beyond_total_length() { + let buf1 = [1; 8]; + let mut bufs = &mut [IoSlice::new(&buf1)][..]; + + IoSlice::advance_slices(&mut bufs, 9); + assert!(bufs.is_empty()); +} + +#[test] +fn io_slice_as_slice() { + let buf = [1; 8]; + let slice = IoSlice::new(&buf).as_slice(); + assert_eq!(slice, buf); +} + +#[test] +fn io_slice_into_slice() { + let mut buf = [1; 8]; + let slice = IoSliceMut::new(&mut buf).into_slice(); + assert_eq!(slice, [1; 8]); +} diff --git a/library/coretests/tests/io/mod.rs b/library/coretests/tests/io/mod.rs index a24893a525a9d..7683131a54034 100644 --- a/library/coretests/tests/io/mod.rs +++ b/library/coretests/tests/io/mod.rs @@ -1 +1,2 @@ mod borrowed_buf; +mod io_slice; diff --git a/library/coretests/tests/lib.rs b/library/coretests/tests/lib.rs index c4292c2a421b1..a1e08ae40f4e1 100644 --- a/library/coretests/tests/lib.rs +++ b/library/coretests/tests/lib.rs @@ -67,6 +67,7 @@ #![feature(hashmap_internals)] #![feature(int_from_ascii)] #![feature(int_roundings)] +#![feature(io_slice_as_bytes)] #![feature(ip)] #![feature(is_ascii_octdigit)] #![feature(iter_advance_by)] diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 934d4bd684034..a492d63915917 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -299,6 +299,8 @@ mod tests; #[unstable(feature = "read_buf", issue = "78485")] pub use core::io::{BorrowedBuf, BorrowedCursor}; +#[stable(feature = "iovec", since = "1.36.0")] +pub use core::io::{IoSlice, IoSliceMut}; use core::slice::memchr; #[stable(feature = "bufwriter_into_parts", since = "1.56.0")] @@ -330,9 +332,8 @@ pub use self::{ stdio::{Stderr, StderrLock, Stdin, StdinLock, Stdout, StdoutLock, stderr, stdin, stdout}, util::{Empty, Repeat, Sink, empty, repeat, sink}, }; -use crate::mem::{MaybeUninit, take}; -use crate::ops::{Deref, DerefMut}; -use crate::{cmp, fmt, slice, str, sys}; +use crate::mem::MaybeUninit; +use crate::{cmp, fmt, slice, str}; mod buffered; pub(crate) mod copy; @@ -1331,323 +1332,6 @@ pub fn read_to_string(mut reader: R) -> Result { Ok(buf) } -/// 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>(sys::io::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(sys::io::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>(sys::io::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(sys::io::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() - } -} - /// A trait for objects which are byte-oriented sinks. /// /// Implementors of the `Write` trait are sometimes called 'writers'. diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs index 12cbb1d50233c..56d3bd678e104 100644 --- a/library/std/src/io/tests.rs +++ b/library/std/src/io/tests.rs @@ -1,10 +1,7 @@ use super::{BorrowedBuf, Cursor, SeekFrom, repeat}; use crate::cmp::{self, min}; -use crate::io::{ - self, BufRead, BufReader, DEFAULT_BUF_SIZE, IoSlice, IoSliceMut, Read, Seek, Write, -}; +use crate::io::{self, BufRead, BufReader, DEFAULT_BUF_SIZE, IoSlice, Read, Seek, Write}; use crate::mem::MaybeUninit; -use crate::ops::Deref; #[test] fn read_until() { @@ -565,104 +562,6 @@ fn test_read_to_end_capacity() -> io::Result<()> { Ok(()) } -#[test] -fn io_slice_mut_advance_slices() { - 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), - ][..]; - - // Only in a single buffer.. - IoSliceMut::advance_slices(&mut bufs, 1); - assert_eq!(bufs[0].deref(), [1; 7].as_ref()); - assert_eq!(bufs[1].deref(), [2; 16].as_ref()); - assert_eq!(bufs[2].deref(), [3; 8].as_ref()); - - // Removing a buffer, leaving others as is. - IoSliceMut::advance_slices(&mut bufs, 7); - assert_eq!(bufs[0].deref(), [2; 16].as_ref()); - assert_eq!(bufs[1].deref(), [3; 8].as_ref()); - - // Removing a buffer and removing from the next buffer. - IoSliceMut::advance_slices(&mut bufs, 18); - assert_eq!(bufs[0].deref(), [3; 6].as_ref()); -} - -#[test] -#[should_panic] -fn io_slice_mut_advance_slices_empty_slice() { - let mut empty_bufs = &mut [][..]; - IoSliceMut::advance_slices(&mut empty_bufs, 1); -} - -#[test] -#[should_panic] -fn io_slice_mut_advance_slices_beyond_total_length() { - let mut buf1 = [1; 8]; - let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..]; - - IoSliceMut::advance_slices(&mut bufs, 9); - assert!(bufs.is_empty()); -} - -#[test] -fn io_slice_advance_slices() { - 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)][..]; - - // Only in a single buffer.. - IoSlice::advance_slices(&mut bufs, 1); - assert_eq!(bufs[0].deref(), [1; 7].as_ref()); - assert_eq!(bufs[1].deref(), [2; 16].as_ref()); - assert_eq!(bufs[2].deref(), [3; 8].as_ref()); - - // Removing a buffer, leaving others as is. - IoSlice::advance_slices(&mut bufs, 7); - assert_eq!(bufs[0].deref(), [2; 16].as_ref()); - assert_eq!(bufs[1].deref(), [3; 8].as_ref()); - - // Removing a buffer and removing from the next buffer. - IoSlice::advance_slices(&mut bufs, 18); - assert_eq!(bufs[0].deref(), [3; 6].as_ref()); -} - -#[test] -#[should_panic] -fn io_slice_advance_slices_empty_slice() { - let mut empty_bufs = &mut [][..]; - IoSlice::advance_slices(&mut empty_bufs, 1); -} - -#[test] -#[should_panic] -fn io_slice_advance_slices_beyond_total_length() { - let buf1 = [1; 8]; - let mut bufs = &mut [IoSlice::new(&buf1)][..]; - - IoSlice::advance_slices(&mut bufs, 9); - assert!(bufs.is_empty()); -} - -#[test] -fn io_slice_as_slice() { - let buf = [1; 8]; - let slice = IoSlice::new(&buf).as_slice(); - assert_eq!(slice, buf); -} - -#[test] -fn io_slice_into_slice() { - let mut buf = [1; 8]; - let slice = IoSliceMut::new(&mut buf).into_slice(); - assert_eq!(slice, [1; 8]); -} - /// Creates a new writer that reads from at most `n_bufs` and reads /// `per_call` bytes (in total) per call to write. fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter { diff --git a/library/std/src/sys/io/io_slice/windows.rs b/library/std/src/sys/io/io_slice/windows.rs deleted file mode 100644 index c3d8ec87c19e3..0000000000000 --- a/library/std/src/sys/io/io_slice/windows.rs +++ /dev/null @@ -1,82 +0,0 @@ -use crate::marker::PhantomData; -use crate::slice; -use crate::sys::c; - -#[derive(Copy, Clone)] -#[repr(transparent)] -pub struct IoSlice<'a> { - vec: c::WSABUF, - _p: PhantomData<&'a [u8]>, -} - -impl<'a> IoSlice<'a> { - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - assert!(buf.len() <= u32::MAX as usize); - IoSlice { - vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_ptr() as *mut u8 }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if (self.vec.len as usize) < n { - panic!("advancing IoSlice beyond its length"); - } - - unsafe { - self.vec.len -= n as u32; - self.vec.buf = self.vec.buf.add(n); - } - } - - #[inline] - pub const fn as_slice(&self) -> &'a [u8] { - unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) } - } -} - -#[repr(transparent)] -pub struct IoSliceMut<'a> { - vec: c::WSABUF, - _p: PhantomData<&'a mut [u8]>, -} - -impl<'a> IoSliceMut<'a> { - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - assert!(buf.len() <= u32::MAX as usize); - IoSliceMut { - vec: c::WSABUF { len: buf.len() as u32, buf: buf.as_mut_ptr() }, - _p: PhantomData, - } - } - - #[inline] - pub fn advance(&mut self, n: usize) { - if (self.vec.len as usize) < n { - panic!("advancing IoSliceMut beyond its length"); - } - - unsafe { - self.vec.len -= n as u32; - self.vec.buf = self.vec.buf.add(n); - } - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - unsafe { slice::from_raw_parts(self.vec.buf, self.vec.len as usize) } - } - - #[inline] - pub const fn into_slice(self) -> &'a mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) } - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { - unsafe { slice::from_raw_parts_mut(self.vec.buf, self.vec.len as usize) } - } -} diff --git a/library/std/src/sys/io/mod.rs b/library/std/src/sys/io/mod.rs index 445bcdef0aa1f..0158137174087 100644 --- a/library/std/src/sys/io/mod.rs +++ b/library/std/src/sys/io/mod.rs @@ -2,27 +2,6 @@ mod error; -mod io_slice { - cfg_select! { - any(target_family = "unix", target_os = "hermit", target_os = "solid_asp3", target_os = "trusty", target_os = "wasi") => { - mod iovec; - pub use iovec::*; - } - target_os = "windows" => { - mod windows; - pub use windows::*; - } - target_os = "uefi" => { - mod uefi; - pub use uefi::*; - } - _ => { - mod unsupported; - pub use unsupported::*; - } - } -} - mod is_terminal { cfg_select! { any(target_family = "unix", target_os = "wasi") => { @@ -63,7 +42,6 @@ pub use error::errno_location; ))] pub use error::set_errno; pub use error::{decode_error_kind, errno, error_string, is_interrupted}; -pub use io_slice::{IoSlice, IoSliceMut}; pub use is_terminal::is_terminal; pub use kernel_copy::{CopyState, kernel_copy}; diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index e07a0784cdb3a..e7455fc701cfb 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -78,6 +78,20 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[ ("core/primitive.slice.html", &["#method.to_ascii_uppercase", "#method.to_ascii_lowercase", "core/slice::sort_by_key", "core\\slice::sort_by_key", "#method.sort_by_cached_key"]), + ("core/io/struct.IoSlice.html", &[ + "#method.to_ascii_uppercase", + "#method.to_ascii_lowercase", + "core/io/slice::sort_by_key", + "core\\io\\slice::sort_by_key", + "#method.sort_by_cached_key" + ]), + ("core/io/struct.IoSliceMut.html", &[ + "#method.to_ascii_uppercase", + "#method.to_ascii_lowercase", + "core/io/slice::sort_by_key", + "core\\io\\slice::sort_by_key", + "#method.sort_by_cached_key" + ]), ]; #[rustfmt::skip]