uninit_read/
exts.rs

1use std::mem::MaybeUninit;
2
3pub(crate) mod sync_read_ext {
4    use super::as_mut_bytes;
5    use crate::UninitRead;
6    use std::io::Read;
7    use std::mem::MaybeUninit;
8
9    /// An extension trait that provides convenience methods for synchronous readers
10    /// that implement [`UninitRead`].
11    ///
12    /// This trait is automatically implemented for any type that satisfies the bounds
13    /// `Read + UninitRead`. It offers safe wrappers for reading directly into
14    /// uninitialized buffers, abstracting away the underlying `unsafe` operations.
15    pub trait UninitSyncReadExt: UninitRead + Read {
16        /// Pulls some bytes from this source into the provided uninitialized buffer.
17        ///
18        /// This method is a wrapper around [`Read::read`] that accepts a slice of
19        /// [`MaybeUninit<u8>`], avoiding the need for the caller to perform `unsafe`
20        /// operations.
21        ///
22        /// On a successful read, this method returns a slice `&[u8]` that represents the
23        /// portion of the buffer that was initialized by the read. The length of the
24        /// returned slice is equivalent to the number of bytes read. An empty slice indicates
25        /// EOF has been reached.
26        ///
27        /// # Errors
28        ///
29        /// This function will return an error if the underlying call to [`Read::read`]
30        /// returns an error.
31        fn read_uninit<'buf>(
32            &mut self,
33            buf: &'buf mut [MaybeUninit<u8>],
34        ) -> Result<&'buf [u8], std::io::Error> {
35            // Safety: UninitRead guarantees the reader won't read from the buffer
36            // before writing to it, making this transmute safe.
37            let buf = unsafe { as_mut_bytes(buf) };
38            let n = self.read(buf)?;
39            Ok(&buf[..n])
40        }
41
42        /// Reads the exact number of bytes required to fill `buf` from this source.
43        ///
44        /// This method is a wrapper around [`Read::read_exact`] that accepts a slice of
45        /// [`MaybeUninit<u8>`], avoiding the need for the caller to perform `unsafe`
46        /// operations.
47        ///
48        /// On a successful read, this method returns a slice `&[u8]` that represents the
49        /// entire buffer, now guaranteed to be fully initialized.
50        ///
51        /// # Errors
52        ///
53        /// This function will return an error if the underlying call to [`Read::read_exact`]
54        /// returns an error. If an EOF is found before the buffer is filled, an error
55        /// of kind [`std::io::ErrorKind::UnexpectedEof`] is returned.
56        fn read_uninit_exact<'buf>(
57            &mut self,
58            buf: &'buf mut [MaybeUninit<u8>],
59        ) -> Result<&'buf [u8], std::io::Error> {
60            // Safety: UninitRead guarantees the reader won't read from the buffer
61            // before writing to it, making this transmute safe.
62            let buf = unsafe { as_mut_bytes(buf) };
63            self.read_exact(buf)?;
64            Ok(&buf[..])
65        }
66    }
67
68    impl<R: ?Sized> UninitSyncReadExt for R where R: UninitRead + Read {}
69}
70
71#[cfg(feature = "futures-lite")]
72pub(crate) mod async_read_ext {
73    use super::as_mut_bytes;
74    use crate::UninitRead;
75    use futures_io::AsyncRead;
76    use futures_lite::AsyncReadExt;
77    use std::mem::MaybeUninit;
78
79    /// An extension trait that provides convenience methods for asynchronous readers
80    /// that implement [`UninitRead`].
81    ///
82    /// This trait is automatically implemented for any type that satisfies the bounds
83    /// `AsyncRead + UninitRead`. It offers safe wrappers for reading directly into
84    /// uninitialized buffers, abstracting away the underlying `unsafe` operations.
85    pub trait UninitAsyncReadExt: UninitRead + AsyncRead {
86        /// Asynchronously pulls some bytes from this source into the provided
87        /// uninitialized buffer.
88        ///
89        /// This method is a wrapper around [`AsyncReadExt::read`] that accepts a slice of
90        /// [`MaybeUninit<u8>`], avoiding the need for the caller to perform `unsafe`
91        /// operations.
92        ///
93        /// On a successful read, this method returns a slice `&[u8]` that represents the
94        /// portion of the buffer that was initialized by the read. The length of the
95        /// returned slice is equivalent to the number of bytes read. An empty slice indicates
96        /// EOF has been reached.
97        ///
98        /// # Errors
99        ///
100        /// This function will return an error if the underlying call to [`AsyncReadExt::read`]
101        /// returns an error.
102        fn read_uninit<'buf>(
103            &mut self,
104            buf: &'buf mut [MaybeUninit<u8>],
105        ) -> impl Future<Output = Result<&'buf [u8], std::io::Error>>
106        where
107            Self: Unpin,
108        {
109            async move {
110                // Safety: UninitRead guarantees the reader won't read from the buffer
111                // before writing to it, making this transmute safe.
112                let buf = unsafe { as_mut_bytes(buf) };
113                let n = self.read(buf).await?;
114                Ok(&buf[..n])
115            }
116        }
117
118        /// Asynchronously reads the exact number of bytes required to fill `buf`.
119        ///
120        /// This method is a wrapper around [`AsyncReadExt::read_exact`] that accepts a
121        /// slice of [`MaybeUninit<u8>`], avoiding the need for the caller to perform
122        /// `unsafe` operations.
123        ///
124        /// On a successful read, this method returns a slice `&[u8]` that represents the
125        /// entire buffer, now guaranteed to be fully initialized.
126        ///
127        /// # Errors
128        ///
129        /// This function will return an error if the underlying call to
130        /// [`AsyncReadExt::read_exact`] returns an error. If an EOF is found before
131        /// the buffer is filled, an error of kind [`std::io::ErrorKind::UnexpectedEof`]
132        /// is returned.
133        fn read_uninit_exact<'buf>(
134            &mut self,
135            buf: &'buf mut [MaybeUninit<u8>],
136        ) -> impl Future<Output = Result<&'buf [u8], std::io::Error>>
137        where
138            Self: Unpin,
139        {
140            async move {
141                // Safety: UninitRead guarantees the reader won't read from the buffer
142                // before writing to it, making this transmute safe.
143                let buf = unsafe { as_mut_bytes(buf) };
144                self.read_exact(buf).await?;
145                Ok(&buf[..])
146            }
147        }
148    }
149
150    impl<R: ?Sized> UninitAsyncReadExt for R where R: UninitRead + AsyncRead {}
151}
152
153unsafe fn as_mut_bytes(buf: &mut [MaybeUninit<u8>]) -> &mut [u8] {
154    unsafe { std::slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len()) }
155}