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