//! 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]` | `(&mut [u8], &mut [MaybeUninit])`, 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]`: /// /// ``` /// # use rustix::io::read; /// # use std::mem::MaybeUninit; /// # fn example(fd: rustix::fd::BorrowedFd) -> rustix::io::Result<()> { /// let mut buf = [MaybeUninit::::uninit(); 64]; /// let (init, uninit) = read(fd, &mut buf)?; /// // `init` is a `&mut [u8]` with the initialized bytes. /// // `uninit` is a `&mut [MaybeUninit]` 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; 1]: Buffer` 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: private::Sealed {} // Implement `Buffer` for all the types that implement `Sealed`. impl Buffer for &mut [T] {} impl Buffer for &mut [T; N] {} #[cfg(feature = "alloc")] impl Buffer for &mut Vec {} impl Buffer for &mut [MaybeUninit] {} impl Buffer for &mut [MaybeUninit; N] {} #[cfg(feature = "alloc")] impl Buffer for &mut Vec> {} #[cfg(feature = "alloc")] impl<'a, T> Buffer for SpareCapacity<'a, T> {} impl private::Sealed 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 private::Sealed 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`, so we add this `impl` so that our users // don't have to add an extra `*` in these situations. #[cfg(feature = "alloc")] impl private::Sealed for &mut Vec { 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 for &'a mut [MaybeUninit] { type Output = (&'a mut [T], &'a mut [MaybeUninit]); #[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::(), init.len()); (init, uninit) } } impl<'a, T, const N: usize> private::Sealed for &'a mut [MaybeUninit; N] { type Output = (&'a mut [T], &'a mut [MaybeUninit]); #[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::(), init.len()); (init, uninit) } } #[cfg(feature = "alloc")] impl<'a, T> private::Sealed for &'a mut Vec> { type Output = (&'a mut [T], &'a mut [MaybeUninit]); #[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::(), 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); /// 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) -> 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 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 { /// 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]` instead, /// however that would require this function to be `unsafe`, because /// callers could use the `&mut [MaybeUninit]` slice to set elements /// to `MaybeUninit::::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]) = 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]) = read(&input, &mut buf).unwrap(); let _x: (&mut [u8], &mut [MaybeUninit]) = read(&input, &mut buf[..]).unwrap(); let mut buf = vec![ MaybeUninit::uninit(), MaybeUninit::uninit(), MaybeUninit::uninit(), ]; let _x: (&mut [u8], &mut [MaybeUninit]) = read(&input, &mut buf).unwrap(); let _x: (&mut [u8], &mut [MaybeUninit]) = 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::::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], &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()); } }