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}