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
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 101 additions & 2 deletions src/rt/io.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,52 @@ use std::task::{Context, Poll};
/// Reads bytes from a source.
///
/// This trait is similar to `std::io::Read`, but supports asynchronous reads.
///
/// # Implementing `Read`
///
/// Implementations should read data into the provided [`ReadBufCursor`] and
/// advance the cursor to indicate how many bytes were written. The simplest
/// and safest approach is to use [`ReadBufCursor::put_slice`]:
///
/// ```
/// use hyper::rt::{Read, ReadBufCursor};
/// use std::pin::Pin;
/// use std::task::{Context, Poll};
/// use std::io;
///
/// struct MyReader {
/// data: Vec<u8>,
/// position: usize,
/// }
///
/// impl Read for MyReader {
/// fn poll_read(
/// mut self: Pin<&mut Self>,
/// _cx: &mut Context<'_>,
/// mut buf: ReadBufCursor<'_>,
/// ) -> Poll<Result<(), io::Error>> {
/// let remaining_data = &self.data[self.position..];
/// if remaining_data.is_empty() {
/// // No more data to read, signal EOF by returning Ok without
/// // advancing the buffer
/// return Poll::Ready(Ok(()));
/// }
///
/// // Calculate how many bytes we can write
/// let to_copy = remaining_data.len().min(buf.remaining());
/// // Use put_slice to safely copy data and advance the cursor
/// buf.put_slice(&remaining_data[..to_copy]);
///
/// self.position += to_copy;
/// Poll::Ready(Ok(()))
/// }
/// }
/// ```
///
/// For more advanced use cases where you need direct access to the buffer
/// (e.g., when interfacing with APIs that write directly to a pointer),
/// you can use the unsafe [`ReadBufCursor::as_mut`] and [`ReadBufCursor::advance`]
/// methods. See their documentation for safety requirements.
pub trait Read {
/// Attempts to read bytes into the `buf`.
///
Expand Down Expand Up @@ -124,9 +170,62 @@ pub struct ReadBuf<'a> {
init: usize,
}

/// The cursor part of a [`ReadBuf`].
/// The cursor part of a [`ReadBuf`], representing the unfilled portion.
///
/// This is created by calling [`ReadBuf::unfilled()`].
///
/// `ReadBufCursor` provides safe and unsafe methods for writing data into the
/// buffer:
///
/// - **Safe approach**: Use [`put_slice`](Self::put_slice) to copy data from
/// a slice. This handles initialization tracking and cursor advancement
/// automatically.
///
/// - **Unsafe approach**: For zero-copy scenarios or when interfacing with
/// low-level APIs, use [`as_mut`](Self::as_mut) to get a mutable slice
/// of `MaybeUninit<u8>`, then call [`advance`](Self::advance) after writing.
/// This is more efficient but requires careful attention to safety invariants.
///
/// This is created by calling `ReadBuf::unfilled()`.
/// # Example using safe methods
///
/// ```
/// use hyper::rt::ReadBuf;
///
/// let mut backing = [0u8; 64];
/// let mut read_buf = ReadBuf::new(&mut backing);
///
/// {
/// let mut cursor = read_buf.unfilled();
/// // put_slice handles everything safely
/// cursor.put_slice(b"hello");
/// }
///
/// assert_eq!(read_buf.filled(), b"hello");
/// ```
///
/// # Example using unsafe methods
///
/// ```
/// use hyper::rt::ReadBuf;
///
/// let mut backing = [0u8; 64];
/// let mut read_buf = ReadBuf::new(&mut backing);
///
/// {
/// let mut cursor = read_buf.unfilled();
/// // SAFETY: we will initialize exactly 5 bytes
/// let slice = unsafe { cursor.as_mut() };
/// slice[0].write(b'h');
/// slice[1].write(b'e');
/// slice[2].write(b'l');
/// slice[3].write(b'l');
/// slice[4].write(b'o');
/// // SAFETY: we have initialized 5 bytes
/// unsafe { cursor.advance(5) };
/// }
///
/// assert_eq!(read_buf.filled(), b"hello");
/// ```
#[derive(Debug)]
pub struct ReadBufCursor<'a> {
buf: &'a mut ReadBuf<'a>,
Expand Down