Skip to main content

hyper/rt/
io.rs

1use std::fmt;
2use std::mem::MaybeUninit;
3use std::ops::DerefMut;
4use std::pin::Pin;
5use std::task::{Context, Poll};
6
7// New IO traits? What?! Why, are you bonkers?
8//
9// I mean, yes, probably. But, here's the goals:
10//
11// 1. Supports poll-based IO operations.
12// 2. Opt-in vectored IO.
13// 3. Can use an optional buffer pool.
14// 4. Able to add completion-based (uring) IO eventually.
15//
16// Frankly, the last point is the entire reason we're doing this. We want to
17// have forwards-compatibility with an eventually stable io-uring runtime. We
18// don't need that to work right away. But it must be possible to add in here
19// without breaking hyper 1.0.
20//
21// While in here, if there's small tweaks to poll_read or poll_write that would
22// allow even the "slow" path to be faster, such as if someone didn't remember
23// to forward along an `is_completion` call.
24
25/// Reads bytes from a source.
26///
27/// 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.
74pub trait Read {
75    /// Attempts to read bytes into the `buf`.
76    ///
77    /// On success, returns `Poll::Ready(Ok(()))` and places data in the
78    /// unfilled portion of `buf`. If no data was read (`buf.remaining()` is
79    /// unchanged), it implies that EOF has been reached.
80    ///
81    /// If no data is available for reading, the method returns `Poll::Pending`
82    /// and arranges for the current task (via `cx.waker()`) to receive a
83    /// notification when the object becomes readable or is closed.
84    fn poll_read(
85        self: Pin<&mut Self>,
86        cx: &mut Context<'_>,
87        buf: ReadBufCursor<'_>,
88    ) -> Poll<Result<(), std::io::Error>>;
89}
90
91/// Write bytes asynchronously.
92///
93/// This trait is similar to `std::io::Write`, but for asynchronous writes.
94pub trait Write {
95    /// Attempt to write bytes from `buf` into the destination.
96    ///
97    /// On success, returns `Poll::Ready(Ok(num_bytes_written)))`. If
98    /// successful, it must be guaranteed that `n <= buf.len()`. A return value
99    /// of `0` means that the underlying object is no longer able to accept
100    /// bytes, or that the provided buffer is empty.
101    ///
102    /// If the object is not ready for writing, the method returns
103    /// `Poll::Pending` and arranges for the current task (via `cx.waker()`) to
104    /// receive a notification when the object becomes writable or is closed.
105    fn poll_write(
106        self: Pin<&mut Self>,
107        cx: &mut Context<'_>,
108        buf: &[u8],
109    ) -> Poll<Result<usize, std::io::Error>>;
110
111    /// Attempts to flush the object.
112    ///
113    /// On success, returns `Poll::Ready(Ok(()))`.
114    ///
115    /// If flushing cannot immediately complete, this method returns
116    /// `Poll::Pending` and arranges for the current task (via `cx.waker()`) to
117    /// receive a notification when the object can make progress.
118    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), std::io::Error>>;
119
120    /// Attempts to shut down this writer.
121    fn poll_shutdown(
122        self: Pin<&mut Self>,
123        cx: &mut Context<'_>,
124    ) -> Poll<Result<(), std::io::Error>>;
125
126    /// Returns whether this writer has an efficient `poll_write_vectored`
127    /// implementation.
128    ///
129    /// The default implementation returns `false`.
130    fn is_write_vectored(&self) -> bool {
131        false
132    }
133
134    /// Like `poll_write`, except that it writes from a slice of buffers.
135    fn poll_write_vectored(
136        self: Pin<&mut Self>,
137        cx: &mut Context<'_>,
138        bufs: &[std::io::IoSlice<'_>],
139    ) -> Poll<Result<usize, std::io::Error>> {
140        let buf = bufs
141            .iter()
142            .find(|b| !b.is_empty())
143            .map_or(&[][..], |b| &**b);
144        self.poll_write(cx, buf)
145    }
146}
147
148/// A wrapper around a byte buffer that is incrementally filled and initialized.
149///
150/// This type is a sort of "double cursor". It tracks three regions in the
151/// buffer: a region at the beginning of the buffer that has been logically
152/// filled with data, a region that has been initialized at some point but not
153/// yet logically filled, and a region at the end that may be uninitialized.
154/// The filled region is guaranteed to be a subset of the initialized region.
155///
156/// In summary, the contents of the buffer can be visualized as:
157///
158/// ```not_rust
159/// [             capacity              ]
160/// [ filled |         unfilled         ]
161/// [    initialized    | uninitialized ]
162/// ```
163///
164/// It is undefined behavior to de-initialize any bytes from the uninitialized
165/// region, since it is merely unknown whether this region is uninitialized or
166/// not, and if part of it turns out to be initialized, it must stay initialized.
167pub struct ReadBuf<'data> {
168    raw: &'data mut [MaybeUninit<u8>],
169    filled: usize,
170    init: usize,
171}
172
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.
188///
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/// ```
229#[derive(Debug)]
230pub struct ReadBufCursor<'buf> {
231    buf: &'buf mut ReadBuf<'buf>,
232}
233
234impl<'data> ReadBuf<'data> {
235    /// Create a new `ReadBuf` with a slice of initialized bytes.
236    #[inline]
237    pub fn new(raw: &'data mut [u8]) -> Self {
238        let len = raw.len();
239        Self {
240            // SAFETY: We never de-init the bytes ourselves.
241            raw: unsafe { &mut *(raw as *mut [u8] as *mut [MaybeUninit<u8>]) },
242            filled: 0,
243            init: len,
244        }
245    }
246
247    /// Create a new `ReadBuf` with a slice of uninitialized bytes.
248    #[inline]
249    pub fn uninit(raw: &'data mut [MaybeUninit<u8>]) -> Self {
250        Self {
251            raw,
252            filled: 0,
253            init: 0,
254        }
255    }
256
257    /// Get a slice of the buffer that has been filled in with bytes.
258    #[inline]
259    pub fn filled(&self) -> &[u8] {
260        // SAFETY: We only slice the filled part of the buffer, which is always valid
261        unsafe { &*(std::ptr::addr_of!(self.raw[0..self.filled]) as *const [u8]) }
262    }
263
264    /// Get a cursor to the unfilled portion of the buffer.
265    #[inline]
266    pub fn unfilled<'cursor>(&'cursor mut self) -> ReadBufCursor<'cursor> {
267        ReadBufCursor {
268            // SAFETY: self.buf is never re-assigned, so its safe to narrow
269            // the lifetime.
270            buf: unsafe {
271                std::mem::transmute::<&'cursor mut ReadBuf<'data>, &'cursor mut ReadBuf<'cursor>>(
272                    self,
273                )
274            },
275        }
276    }
277
278    #[inline]
279    #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
280    pub(crate) unsafe fn set_init(&mut self, n: usize) {
281        self.init = self.init.max(n);
282    }
283
284    #[inline]
285    #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
286    pub(crate) unsafe fn set_filled(&mut self, n: usize) {
287        self.filled = self.filled.max(n);
288    }
289
290    #[inline]
291    #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
292    pub(crate) fn len(&self) -> usize {
293        self.filled
294    }
295
296    #[inline]
297    #[cfg(all(any(feature = "client", feature = "server"), feature = "http2"))]
298    pub(crate) fn init_len(&self) -> usize {
299        self.init
300    }
301
302    #[inline]
303    fn remaining(&self) -> usize {
304        self.capacity() - self.filled
305    }
306
307    #[inline]
308    fn capacity(&self) -> usize {
309        self.raw.len()
310    }
311}
312
313impl fmt::Debug for ReadBuf<'_> {
314    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
315        f.debug_struct("ReadBuf")
316            .field("filled", &self.filled)
317            .field("init", &self.init)
318            .field("capacity", &self.capacity())
319            .finish()
320    }
321}
322
323impl ReadBufCursor<'_> {
324    /// Access the unfilled part of the buffer.
325    ///
326    /// # Safety
327    ///
328    /// The caller must not uninitialize any bytes that may have been
329    /// initialized before.
330    #[inline]
331    pub unsafe fn as_mut(&mut self) -> &mut [MaybeUninit<u8>] {
332        &mut self.buf.raw[self.buf.filled..]
333    }
334
335    /// Advance the `filled` cursor by `n` bytes.
336    ///
337    /// # Safety
338    ///
339    /// The caller must take care that `n` more bytes have been initialized.
340    ///
341    /// # Panics
342    ///
343    /// This method will panic if advancing would cause the filled cursor to
344    /// overflow `usize`.
345    #[inline]
346    pub unsafe fn advance(&mut self, n: usize) {
347        self.buf.filled = self.buf.filled.checked_add(n).expect("overflow");
348        self.buf.init = self.buf.filled.max(self.buf.init);
349    }
350
351    /// Returns the number of bytes that can be written from the current
352    /// position until the end of the buffer is reached.
353    ///
354    /// This value is equal to the length of the slice returned by `as_mut()`.
355    #[inline]
356    pub fn remaining(&self) -> usize {
357        self.buf.remaining()
358    }
359
360    /// Transfer bytes into `self` from `src` and advance the cursor
361    /// by the number of bytes written.
362    ///
363    /// # Panics
364    ///
365    /// `self` must have enough remaining capacity to contain all of `src`.
366    #[inline]
367    pub fn put_slice(&mut self, src: &[u8]) {
368        assert!(
369            self.buf.remaining() >= src.len(),
370            "src.len() must fit in remaining()"
371        );
372
373        let amt = src.len();
374        // Cannot overflow, asserted above
375        let end = self.buf.filled + amt;
376
377        // Safety: the length is asserted above
378        unsafe {
379            self.buf.raw[self.buf.filled..end]
380                .as_mut_ptr()
381                .cast::<u8>()
382                .copy_from_nonoverlapping(src.as_ptr(), amt);
383        }
384
385        if self.buf.init < end {
386            self.buf.init = end;
387        }
388        self.buf.filled = end;
389    }
390
391    /// Returns a mutable reference to the unfilled part of the buffer, ensuring it is fully initialized.
392    #[inline]
393    pub fn initialize_unfilled(&mut self) -> &mut [u8] {
394        self.initialize_unfilled_to(self.remaining())
395    }
396
397    /// Returns a mutable reference to the first `n` bytes of the unfilled part of the buffer, ensuring it is
398    /// fully initialized.
399    ///
400    /// # Panics
401    ///
402    /// Panics if `self.remaining()` is less than `n`.
403    #[inline]
404    pub fn initialize_unfilled_to(&mut self, n: usize) -> &mut [u8] {
405        assert!(self.remaining() >= n, "n overflows remaining");
406
407        // This can't overflow as the assert above would have panicked otherwise.
408        let end = self.buf.filled + n;
409
410        if self.buf.init < end {
411            // SAFETY:
412            // 1. The raw pointer is not null and not dangling either as the slice outlives the
413            // pointer's usage. The pointer is also properly aligned.
414            // 2. Further, `end - self.buf.init` is inbounds and hence safe to write
415            // to.
416            unsafe {
417                self.buf.raw[self.buf.init..end]
418                    .as_mut_ptr()
419                    .write_bytes(0, end - self.buf.init);
420            }
421            self.buf.init = end;
422        }
423
424        let slice = &mut self.buf.raw[self.buf.filled..end];
425
426        // SAFETY: `MaybeUninit<u8>` has the same memory layout as u8 and we properly initialized
427        // the slice above.
428        unsafe { &mut *(slice as *mut [MaybeUninit<u8>] as *mut [u8]) }
429    }
430}
431
432macro_rules! deref_async_read {
433    () => {
434        fn poll_read(
435            mut self: Pin<&mut Self>,
436            cx: &mut Context<'_>,
437            buf: ReadBufCursor<'_>,
438        ) -> Poll<std::io::Result<()>> {
439            Pin::new(&mut **self).poll_read(cx, buf)
440        }
441    };
442}
443
444impl<T: ?Sized + Read + Unpin> Read for Box<T> {
445    deref_async_read!();
446}
447
448impl<T: ?Sized + Read + Unpin> Read for &mut T {
449    deref_async_read!();
450}
451
452impl<P> Read for Pin<P>
453where
454    P: DerefMut,
455    P::Target: Read,
456{
457    fn poll_read(
458        self: Pin<&mut Self>,
459        cx: &mut Context<'_>,
460        buf: ReadBufCursor<'_>,
461    ) -> Poll<std::io::Result<()>> {
462        pin_as_deref_mut(self).poll_read(cx, buf)
463    }
464}
465
466macro_rules! deref_async_write {
467    () => {
468        fn poll_write(
469            mut self: Pin<&mut Self>,
470            cx: &mut Context<'_>,
471            buf: &[u8],
472        ) -> Poll<std::io::Result<usize>> {
473            Pin::new(&mut **self).poll_write(cx, buf)
474        }
475
476        fn poll_write_vectored(
477            mut self: Pin<&mut Self>,
478            cx: &mut Context<'_>,
479            bufs: &[std::io::IoSlice<'_>],
480        ) -> Poll<std::io::Result<usize>> {
481            Pin::new(&mut **self).poll_write_vectored(cx, bufs)
482        }
483
484        fn is_write_vectored(&self) -> bool {
485            (**self).is_write_vectored()
486        }
487
488        fn poll_flush(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
489            Pin::new(&mut **self).poll_flush(cx)
490        }
491
492        fn poll_shutdown(
493            mut self: Pin<&mut Self>,
494            cx: &mut Context<'_>,
495        ) -> Poll<std::io::Result<()>> {
496            Pin::new(&mut **self).poll_shutdown(cx)
497        }
498    };
499}
500
501impl<T: ?Sized + Write + Unpin> Write for Box<T> {
502    deref_async_write!();
503}
504
505impl<T: ?Sized + Write + Unpin> Write for &mut T {
506    deref_async_write!();
507}
508
509impl<P> Write for Pin<P>
510where
511    P: DerefMut,
512    P::Target: Write,
513{
514    fn poll_write(
515        self: Pin<&mut Self>,
516        cx: &mut Context<'_>,
517        buf: &[u8],
518    ) -> Poll<std::io::Result<usize>> {
519        pin_as_deref_mut(self).poll_write(cx, buf)
520    }
521
522    fn poll_write_vectored(
523        self: Pin<&mut Self>,
524        cx: &mut Context<'_>,
525        bufs: &[std::io::IoSlice<'_>],
526    ) -> Poll<std::io::Result<usize>> {
527        pin_as_deref_mut(self).poll_write_vectored(cx, bufs)
528    }
529
530    fn is_write_vectored(&self) -> bool {
531        (**self).is_write_vectored()
532    }
533
534    fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
535        pin_as_deref_mut(self).poll_flush(cx)
536    }
537
538    fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<std::io::Result<()>> {
539        pin_as_deref_mut(self).poll_shutdown(cx)
540    }
541}
542
543/// Polyfill for `Pin::as_deref_mut()`.
544/// TODO: use `Pin::as_deref_mut()` instead once stabilized.
545fn pin_as_deref_mut<P: DerefMut>(pin: Pin<&mut Pin<P>>) -> Pin<&mut P::Target> {
546    // SAFETY: we go directly from Pin<&mut Pin<P>> to Pin<&mut P::Target>, without moving or
547    // giving out the &mut Pin<P> in the process. See Pin::as_deref_mut() for more detail.
548    unsafe { pin.get_unchecked_mut() }.as_mut()
549}