|
| 1 | +use std::io; |
| 2 | +use std::mem::MaybeUninit; |
| 3 | +use std::sync::Arc; |
| 4 | +use tokio::io::{AsyncRead, AsyncReadExt}; |
| 5 | + |
| 6 | +/// Read data from an `AsyncRead` into an `Arc`. |
| 7 | +/// |
| 8 | +/// This uses `Arc::new_uninit_slice` and reads into the resulting uninitialized `Arc`. |
| 9 | +/// |
| 10 | +/// # Example |
| 11 | +/// |
| 12 | +/// ``` |
| 13 | +/// # #[tokio::main] |
| 14 | +/// # async fn main() -> std::io::Result<()> { |
| 15 | +/// use tokio_util::io::read_exact_arc; |
| 16 | +/// |
| 17 | +/// let read = tokio::io::repeat(42); |
| 18 | +/// |
| 19 | +/// let arc = read_exact_arc(read, 4).await?; |
| 20 | +/// |
| 21 | +/// assert_eq!(&arc[..], &[42; 4]); |
| 22 | +/// # Ok(()) |
| 23 | +/// # } |
| 24 | +/// ``` |
| 25 | +pub async fn read_exact_arc<R: AsyncRead>(read: R, len: usize) -> io::Result<Arc<[u8]>> { |
| 26 | + tokio::pin!(read); |
| 27 | + // TODO(MSRV 1.82): When bumping MSRV, switch to `Arc::new_uninit_slice(len)`. The following is |
| 28 | + // equivalent, and generates the same assembly, but works without requiring MSRV 1.82. |
| 29 | + let arc: Arc<[MaybeUninit<u8>]> = (0..len).map(|_| MaybeUninit::uninit()).collect(); |
| 30 | + // TODO(MSRV future): Use `Arc::get_mut_unchecked` once it's stabilized. |
| 31 | + // SAFETY: We're the only owner of the `Arc`, and we keep the `Arc` valid throughout this loop |
| 32 | + // as we write through this reference. |
| 33 | + let mut buf = unsafe { &mut *(Arc::as_ptr(&arc) as *mut [MaybeUninit<u8>]) }; |
| 34 | + while !buf.is_empty() { |
| 35 | + if read.read_buf(&mut buf).await? == 0 { |
| 36 | + return Err(io::Error::new(io::ErrorKind::UnexpectedEof, "early eof")); |
| 37 | + } |
| 38 | + } |
| 39 | + // TODO(MSRV 1.82): When bumping MSRV, switch to `arc.assume_init()`. The following is |
| 40 | + // equivalent, and generates the same assembly, but works without requiring MSRV 1.82. |
| 41 | + // SAFETY: This changes `[MaybeUninit<u8>]` to `[u8]`, and we've initialized all the bytes in |
| 42 | + // the loop above. |
| 43 | + Ok(unsafe { Arc::from_raw(Arc::into_raw(arc) as *const [u8]) }) |
| 44 | +} |
0 commit comments