WARNING: THIS SITE IS A MIRROR OF GITHUB.COM / IT CANNOT LOGIN OR REGISTER ACCOUNTS / THE CONTENTS ARE PROVIDED AS-IS / THIS SITE ASSUMES NO RESPONSIBILITY FOR ANY DISPLAYED CONTENT OR LINKS / IF YOU FOUND SOMETHING MAY NOT GOOD FOR EVERYONE, CONTACT ADMIN AT ilovescratch@foxmail.com
Skip to content

Commit 32b76f4

Browse files
authored
docs(rt): improve Read and ReadBufCursor documentation (#4000)
Add comprehensive documentation for implementing the Read trait: - Explain the difference from tokio's AsyncRead - Provide a complete example of implementing Read using put_slice - Document when to use unsafe methods Improve ReadBufCursor documentation: - Describe safe vs unsafe approaches - Add examples for both put_slice and as_mut/advance usage - Link to relevant methods Fixes #3649
1 parent da80d2a commit 32b76f4

File tree

1 file changed

+101
-2
lines changed

1 file changed

+101
-2
lines changed

src/rt/io.rs

Lines changed: 101 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,52 @@ use std::task::{Context, Poll};
2525
/// Reads bytes from a source.
2626
///
2727
/// This trait is similar to `std::io::Read`, but supports asynchronous reads.
28+
///
29+
/// # Implementing `Read`
30+
///
31+
/// Implementations should read data into the provided [`ReadBufCursor`] and
32+
/// advance the cursor to indicate how many bytes were written. The simplest
33+
/// and safest approach is to use [`ReadBufCursor::put_slice`]:
34+
///
35+
/// ```
36+
/// use hyper::rt::{Read, ReadBufCursor};
37+
/// use std::pin::Pin;
38+
/// use std::task::{Context, Poll};
39+
/// use std::io;
40+
///
41+
/// struct MyReader {
42+
/// data: Vec<u8>,
43+
/// position: usize,
44+
/// }
45+
///
46+
/// impl Read for MyReader {
47+
/// fn poll_read(
48+
/// mut self: Pin<&mut Self>,
49+
/// _cx: &mut Context<'_>,
50+
/// mut buf: ReadBufCursor<'_>,
51+
/// ) -> Poll<Result<(), io::Error>> {
52+
/// let remaining_data = &self.data[self.position..];
53+
/// if remaining_data.is_empty() {
54+
/// // No more data to read, signal EOF by returning Ok without
55+
/// // advancing the buffer
56+
/// return Poll::Ready(Ok(()));
57+
/// }
58+
///
59+
/// // Calculate how many bytes we can write
60+
/// let to_copy = remaining_data.len().min(buf.remaining());
61+
/// // Use put_slice to safely copy data and advance the cursor
62+
/// buf.put_slice(&remaining_data[..to_copy]);
63+
///
64+
/// self.position += to_copy;
65+
/// Poll::Ready(Ok(()))
66+
/// }
67+
/// }
68+
/// ```
69+
///
70+
/// For more advanced use cases where you need direct access to the buffer
71+
/// (e.g., when interfacing with APIs that write directly to a pointer),
72+
/// you can use the unsafe [`ReadBufCursor::as_mut`] and [`ReadBufCursor::advance`]
73+
/// methods. See their documentation for safety requirements.
2874
pub trait Read {
2975
/// Attempts to read bytes into the `buf`.
3076
///
@@ -124,9 +170,62 @@ pub struct ReadBuf<'a> {
124170
init: usize,
125171
}
126172

127-
/// The cursor part of a [`ReadBuf`].
173+
/// The cursor part of a [`ReadBuf`], representing the unfilled portion.
174+
///
175+
/// This is created by calling [`ReadBuf::unfilled()`].
176+
///
177+
/// `ReadBufCursor` provides safe and unsafe methods for writing data into the
178+
/// buffer:
179+
///
180+
/// - **Safe approach**: Use [`put_slice`](Self::put_slice) to copy data from
181+
/// a slice. This handles initialization tracking and cursor advancement
182+
/// automatically.
183+
///
184+
/// - **Unsafe approach**: For zero-copy scenarios or when interfacing with
185+
/// low-level APIs, use [`as_mut`](Self::as_mut) to get a mutable slice
186+
/// of `MaybeUninit<u8>`, then call [`advance`](Self::advance) after writing.
187+
/// This is more efficient but requires careful attention to safety invariants.
128188
///
129-
/// This is created by calling `ReadBuf::unfilled()`.
189+
/// # Example using safe methods
190+
///
191+
/// ```
192+
/// use hyper::rt::ReadBuf;
193+
///
194+
/// let mut backing = [0u8; 64];
195+
/// let mut read_buf = ReadBuf::new(&mut backing);
196+
///
197+
/// {
198+
/// let mut cursor = read_buf.unfilled();
199+
/// // put_slice handles everything safely
200+
/// cursor.put_slice(b"hello");
201+
/// }
202+
///
203+
/// assert_eq!(read_buf.filled(), b"hello");
204+
/// ```
205+
///
206+
/// # Example using unsafe methods
207+
///
208+
/// ```
209+
/// use hyper::rt::ReadBuf;
210+
///
211+
/// let mut backing = [0u8; 64];
212+
/// let mut read_buf = ReadBuf::new(&mut backing);
213+
///
214+
/// {
215+
/// let mut cursor = read_buf.unfilled();
216+
/// // SAFETY: we will initialize exactly 5 bytes
217+
/// let slice = unsafe { cursor.as_mut() };
218+
/// slice[0].write(b'h');
219+
/// slice[1].write(b'e');
220+
/// slice[2].write(b'l');
221+
/// slice[3].write(b'l');
222+
/// slice[4].write(b'o');
223+
/// // SAFETY: we have initialized 5 bytes
224+
/// unsafe { cursor.advance(5) };
225+
/// }
226+
///
227+
/// assert_eq!(read_buf.filled(), b"hello");
228+
/// ```
130229
#[derive(Debug)]
131230
pub struct ReadBufCursor<'a> {
132231
buf: &'a mut ReadBuf<'a>,

0 commit comments

Comments
 (0)