diff options
Diffstat (limited to 'vendor/rustix/src/buffer.rs')
| -rw-r--r-- | vendor/rustix/src/buffer.rs | 448 |
1 files changed, 448 insertions, 0 deletions
diff --git a/vendor/rustix/src/buffer.rs b/vendor/rustix/src/buffer.rs new file mode 100644 index 00000000..6c86826f --- /dev/null +++ b/vendor/rustix/src/buffer.rs @@ -0,0 +1,448 @@ +//! Utilities for functions that return data via buffers. + +#![allow(unsafe_code)] + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; +use core::mem::MaybeUninit; +use core::slice; + +/// A memory buffer that may be uninitialized. +/// +/// There are three types that implement the `Buffer` trait, and the type you +/// use determines the return type of the functions that use it: +/// +/// | If you pass a… | You get back a… | +/// | ------------------------ | --------------- | +/// | `&mut [u8]` | `usize`, indicating the number of elements initialized. | +/// | `&mut [MaybeUninit<u8>]` | `(&mut [u8], &mut [MaybeUninit<u8>])`, holding the initialized and uninitialized subslices. | +/// | [`SpareCapacity`] | `usize`, indicating the number of elements initialized. And the `Vec` is extended. | +/// +/// # Examples +/// +/// Passing a `&mut [u8]`: +/// +/// ``` +/// # use rustix::io::read; +/// # fn example(fd: rustix::fd::BorrowedFd) -> rustix::io::Result<()> { +/// let mut buf = [0_u8; 64]; +/// let nread = read(fd, &mut buf)?; +/// // `nread` is the number of bytes read. +/// # Ok(()) +/// # } +/// ``` +/// +/// Passing a `&mut [MaybeUninit<u8>]`: +/// +/// ``` +/// # use rustix::io::read; +/// # use std::mem::MaybeUninit; +/// # fn example(fd: rustix::fd::BorrowedFd) -> rustix::io::Result<()> { +/// let mut buf = [MaybeUninit::<u8>::uninit(); 64]; +/// let (init, uninit) = read(fd, &mut buf)?; +/// // `init` is a `&mut [u8]` with the initialized bytes. +/// // `uninit` is a `&mut [MaybeUninit<u8>]` with the remaining bytes. +/// # Ok(()) +/// # } +/// ``` +/// +/// Passing a [`SpareCapacity`], via the [`spare_capacity`] helper function: +/// +/// ``` +/// # use rustix::io::read; +/// # use rustix::buffer::spare_capacity; +/// # fn example(fd: rustix::fd::BorrowedFd) -> rustix::io::Result<()> { +/// let mut buf = Vec::with_capacity(64); +/// let nread = read(fd, spare_capacity(&mut buf))?; +/// // `nread` is the number of bytes read. +/// // Also, `buf.len()` is now `nread` elements longer than it was before. +/// # Ok(()) +/// # } +/// ``` +/// +/// # Guide to error messages +/// +/// Sometimes code using `Buffer` can encounter non-obvious error messages. +/// Here are some we've encountered, along with ways to fix them. +/// +/// If you see errors like +/// "cannot move out of `self` which is behind a mutable reference" +/// and +/// "move occurs because `x` has type `&mut [u8]`, which does not implement the `Copy` trait", +/// replace `x` with `&mut *x`. See `error_buffer_wrapper` in +/// examples/buffer_errors.rs. +/// +/// If you see errors like +/// "type annotations needed" +/// and +/// "cannot infer type of the type parameter `Buf` declared on the function `read`", +/// you may need to change a `&mut []` to `&mut [0_u8; 0]`. See +/// `error_empty_slice` in examples/buffer_errors.rs. +/// +/// If you see errors like +/// "the trait bound `[MaybeUninit<u8>; 1]: Buffer<u8>` is not satisfied", +/// add a `&mut` to pass the array by reference instead of by value. See +/// `error_array_by_value` in examples/buffer_errors.rs. +/// +/// If you see errors like +/// "cannot move out of `x`, a captured variable in an `FnMut` closure", +/// try replacing `x` with `&mut *x`, or, if that doesn't work, try moving a +/// `let` into the closure body. See `error_retry_closure` and +/// `error_retry_indirect_closure` in examples/buffer_errors.rs. +/// +/// If you see errors like +/// "captured variable cannot escape `FnMut` closure body", +/// use an explicit loop instead of `retry_on_intr`, assuming you're using +/// that. See `error_retry_closure_uninit` in examples/buffer_errors.rs. +pub trait Buffer<T>: private::Sealed<T> {} + +// Implement `Buffer` for all the types that implement `Sealed`. +impl<T> Buffer<T> for &mut [T] {} +impl<T, const N: usize> Buffer<T> for &mut [T; N] {} +#[cfg(feature = "alloc")] +impl<T> Buffer<T> for &mut Vec<T> {} +impl<T> Buffer<T> for &mut [MaybeUninit<T>] {} +impl<T, const N: usize> Buffer<T> for &mut [MaybeUninit<T>; N] {} +#[cfg(feature = "alloc")] +impl<T> Buffer<T> for &mut Vec<MaybeUninit<T>> {} +#[cfg(feature = "alloc")] +impl<'a, T> Buffer<T> for SpareCapacity<'a, T> {} + +impl<T> private::Sealed<T> for &mut [T] { + type Output = usize; + + #[inline] + fn parts_mut(&mut self) -> (*mut T, usize) { + (self.as_mut_ptr(), self.len()) + } + + #[inline] + unsafe fn assume_init(self, len: usize) -> Self::Output { + len + } +} + +impl<T, const N: usize> private::Sealed<T> for &mut [T; N] { + type Output = usize; + + #[inline] + fn parts_mut(&mut self) -> (*mut T, usize) { + (self.as_mut_ptr(), N) + } + + #[inline] + unsafe fn assume_init(self, len: usize) -> Self::Output { + len + } +} + +// `Vec` implements `DerefMut` to `&mut [T]`, however it doesn't get +// auto-derefed in a `impl Buffer<u8>`, so we add this `impl` so that our users +// don't have to add an extra `*` in these situations. +#[cfg(feature = "alloc")] +impl<T> private::Sealed<T> for &mut Vec<T> { + type Output = usize; + + #[inline] + fn parts_mut(&mut self) -> (*mut T, usize) { + (self.as_mut_ptr(), self.len()) + } + + #[inline] + unsafe fn assume_init(self, len: usize) -> Self::Output { + len + } +} + +impl<'a, T> private::Sealed<T> for &'a mut [MaybeUninit<T>] { + type Output = (&'a mut [T], &'a mut [MaybeUninit<T>]); + + #[inline] + fn parts_mut(&mut self) -> (*mut T, usize) { + (self.as_mut_ptr().cast(), self.len()) + } + + #[inline] + unsafe fn assume_init(self, len: usize) -> Self::Output { + let (init, uninit) = self.split_at_mut(len); + + // SAFETY: The user asserts that the slice is now initialized. + let init = slice::from_raw_parts_mut(init.as_mut_ptr().cast::<T>(), init.len()); + + (init, uninit) + } +} + +impl<'a, T, const N: usize> private::Sealed<T> for &'a mut [MaybeUninit<T>; N] { + type Output = (&'a mut [T], &'a mut [MaybeUninit<T>]); + + #[inline] + fn parts_mut(&mut self) -> (*mut T, usize) { + (self.as_mut_ptr().cast(), self.len()) + } + + #[inline] + unsafe fn assume_init(self, len: usize) -> Self::Output { + let (init, uninit) = self.split_at_mut(len); + + // SAFETY: The user asserts that the slice is now initialized. + let init = slice::from_raw_parts_mut(init.as_mut_ptr().cast::<T>(), init.len()); + + (init, uninit) + } +} + +#[cfg(feature = "alloc")] +impl<'a, T> private::Sealed<T> for &'a mut Vec<MaybeUninit<T>> { + type Output = (&'a mut [T], &'a mut [MaybeUninit<T>]); + + #[inline] + fn parts_mut(&mut self) -> (*mut T, usize) { + (self.as_mut_ptr().cast(), self.len()) + } + + #[inline] + unsafe fn assume_init(self, len: usize) -> Self::Output { + let (init, uninit) = self.split_at_mut(len); + + // SAFETY: The user asserts that the slice is now initialized. + let init = slice::from_raw_parts_mut(init.as_mut_ptr().cast::<T>(), init.len()); + + (init, uninit) + } +} + +/// A type that implements [`Buffer`] by appending to a `Vec`, up to its +/// capacity. +/// +/// To use this, use the [`spare_capacity`] function. +/// +/// Because this uses the capacity, and never reallocates, the `Vec` should +/// have some non-empty spare capacity. +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +pub struct SpareCapacity<'a, T>(&'a mut Vec<T>); + +/// Construct an [`SpareCapacity`], which implements [`Buffer`]. +/// +/// This wraps a `Vec` and uses the spare capacity of the `Vec` as the buffer +/// to receive data in, automatically calling `set_len` on the `Vec` to set the +/// length to include the received elements. +/// +/// This uses the existing capacity, and never allocates, so the `Vec` should +/// have some non-empty spare capacity! +/// +/// # Examples +/// +/// ``` +/// # fn test(input: rustix::fd::BorrowedFd) -> rustix::io::Result<()> { +/// use rustix::buffer::spare_capacity; +/// use rustix::io::{read, Errno}; +/// +/// let mut buf = Vec::with_capacity(1024); +/// match read(input, spare_capacity(&mut buf)) { +/// Ok(0) => { /* end of stream */ } +/// Ok(n) => { /* `buf` is now `n` bytes longer */ } +/// Err(Errno::INTR) => { /* `buf` is unmodified */ } +/// Err(e) => { +/// return Err(e); +/// } +/// } +/// +/// # Ok(()) +/// # } +/// ``` +#[cfg(feature = "alloc")] +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] +pub fn spare_capacity<'a, T>(v: &'a mut Vec<T>) -> SpareCapacity<'a, T> { + debug_assert_ne!( + v.capacity(), + 0, + "`extend` uses spare capacity, and never allocates new memory, so the `Vec` passed to it \ + should have some spare capacity." + ); + + SpareCapacity(v) +} + +#[cfg(feature = "alloc")] +impl<'a, T> private::Sealed<T> for SpareCapacity<'a, T> { + /// The mutated `Vec` reflects the number of bytes read. We also return + /// this number, and a value of 0 indicates the end of the stream has + /// been reached. + type Output = usize; + + #[inline] + fn parts_mut(&mut self) -> (*mut T, usize) { + let spare = self.0.spare_capacity_mut(); + (spare.as_mut_ptr().cast(), spare.len()) + } + + #[inline] + unsafe fn assume_init(self, len: usize) -> Self::Output { + // We initialized `len` elements; extend the `Vec` to include them. + self.0.set_len(self.0.len() + len); + len + } +} + +mod private { + pub trait Sealed<T> { + /// The result of the process operation. + type Output; + + /// Return a pointer and length for this buffer. + /// + /// The length is the number of elements of type `T`, not a number of + /// bytes. + /// + /// It's tempting to have this return `&mut [MaybeUninit<T>]` instead, + /// however that would require this function to be `unsafe`, because + /// callers could use the `&mut [MaybeUninit<T>]` slice to set elements + /// to `MaybeUninit::<T>::uninit()`, which would be a problem if `Self` + /// is `&mut [T]` or similar. + fn parts_mut(&mut self) -> (*mut T, usize); + + /// Convert a finished buffer pointer into its result. + /// + /// # Safety + /// + /// At least `len` elements of the buffer must now be initialized. + #[must_use] + unsafe fn assume_init(self, len: usize) -> Self::Output; + } +} + +#[cfg(test)] +mod tests { + #[allow(unused_imports)] + use super::*; + + #[cfg(not(windows))] + #[test] + fn test_compilation() { + use crate::io::read; + use core::mem::MaybeUninit; + + // We need to obtain input stream, so open our own source file. + let input = std::fs::File::open("src/buffer.rs").unwrap(); + + let mut buf = vec![0_u8; 3]; + buf.reserve(32); + let _x: usize = read(&input, spare_capacity(&mut buf)).unwrap(); + let _x: (&mut [u8], &mut [MaybeUninit<u8>]) = + read(&input, buf.spare_capacity_mut()).unwrap(); + let _x: usize = read(&input, &mut buf).unwrap(); + let _x: usize = read(&input, &mut *buf).unwrap(); + let _x: usize = read(&input, &mut buf[..]).unwrap(); + let _x: usize = read(&input, &mut (*buf)[..]).unwrap(); + + let mut buf = [0, 0, 0]; + let _x: usize = read(&input, &mut buf).unwrap(); + let _x: usize = read(&input, &mut buf[..]).unwrap(); + + let mut buf = [ + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + ]; + let _x: (&mut [u8], &mut [MaybeUninit<u8>]) = read(&input, &mut buf).unwrap(); + let _x: (&mut [u8], &mut [MaybeUninit<u8>]) = read(&input, &mut buf[..]).unwrap(); + + let mut buf = vec![ + MaybeUninit::uninit(), + MaybeUninit::uninit(), + MaybeUninit::uninit(), + ]; + let _x: (&mut [u8], &mut [MaybeUninit<u8>]) = read(&input, &mut buf).unwrap(); + let _x: (&mut [u8], &mut [MaybeUninit<u8>]) = read(&input, &mut buf[..]).unwrap(); + } + + #[cfg(not(windows))] + #[test] + fn test_slice() { + use crate::io::read; + use std::io::{Seek, SeekFrom}; + + // We need to obtain input stream with contents that we can compare + // against, so open our own source file. + let mut input = std::fs::File::open("src/buffer.rs").unwrap(); + + let mut buf = [0_u8; 64]; + let nread = read(&input, &mut buf).unwrap(); + assert_eq!(nread, buf.len()); + assert_eq!( + &buf[..58], + b"//! Utilities for functions that return data via buffers.\n" + ); + input.seek(SeekFrom::End(-1)).unwrap(); + let nread = read(&input, &mut buf).unwrap(); + assert_eq!(nread, 1); + input.seek(SeekFrom::End(0)).unwrap(); + let nread = read(&input, &mut buf).unwrap(); + assert_eq!(nread, 0); + } + + #[cfg(not(windows))] + #[test] + fn test_slice_uninit() { + use crate::io::read; + use core::mem::MaybeUninit; + use std::io::{Seek, SeekFrom}; + + // We need to obtain input stream with contents that we can compare + // against, so open our own source file. + let mut input = std::fs::File::open("src/buffer.rs").unwrap(); + + let mut buf = [MaybeUninit::<u8>::uninit(); 64]; + let (init, uninit) = read(&input, &mut buf).unwrap(); + assert_eq!(uninit.len(), 0); + assert_eq!( + &init[..58], + b"//! Utilities for functions that return data via buffers.\n" + ); + assert_eq!(init.len(), buf.len()); + assert_eq!( + unsafe { core::mem::transmute::<&mut [MaybeUninit<u8>], &mut [u8]>(&mut buf[..58]) }, + b"//! Utilities for functions that return data via buffers.\n" + ); + input.seek(SeekFrom::End(-1)).unwrap(); + let (init, uninit) = read(&input, &mut buf).unwrap(); + assert_eq!(init.len(), 1); + assert_eq!(uninit.len(), buf.len() - 1); + input.seek(SeekFrom::End(0)).unwrap(); + let (init, uninit) = read(&input, &mut buf).unwrap(); + assert_eq!(init.len(), 0); + assert_eq!(uninit.len(), buf.len()); + } + + #[cfg(not(windows))] + #[test] + fn test_spare_capacity() { + use crate::io::read; + use std::io::{Seek, SeekFrom}; + + // We need to obtain input stream with contents that we can compare + // against, so open our own source file. + let mut input = std::fs::File::open("src/buffer.rs").unwrap(); + + let mut buf = Vec::with_capacity(64); + let nread = read(&input, spare_capacity(&mut buf)).unwrap(); + assert_eq!(nread, buf.capacity()); + assert_eq!(nread, buf.len()); + assert_eq!( + &buf[..58], + b"//! Utilities for functions that return data via buffers.\n" + ); + buf.clear(); + input.seek(SeekFrom::End(-1)).unwrap(); + let nread = read(&input, spare_capacity(&mut buf)).unwrap(); + assert_eq!(nread, 1); + assert_eq!(buf.len(), 1); + buf.clear(); + input.seek(SeekFrom::End(0)).unwrap(); + let nread = read(&input, spare_capacity(&mut buf)).unwrap(); + assert_eq!(nread, 0); + assert!(buf.is_empty()); + } +} |
