Skip to main content

qubit_io/traits/
async_byte_input.rs

1// =============================================================================
2//    Copyright (c) 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8
9use crate::AsyncInput;
10
11/// An asynchronous input whose items are bytes.
12///
13/// This trait adds no methods. Every [`AsyncInput<Item = u8>`](AsyncInput),
14/// including unsized streams, implements it automatically. Implement
15/// [`AsyncInput`] to provide the operations; no separate implementation of
16/// `AsyncByteInput` is needed.
17///
18/// The inherited polling methods retain their pinning and readiness contracts;
19/// implementors do not need to be `Unpin`.
20///
21/// # Examples
22/// `ByteSlice` is always ready and reads from an in-memory byte slice:
23///
24/// ```
25/// use std::io;
26/// use std::pin::Pin;
27/// use std::task::Context;
28/// use std::task::Poll;
29/// use std::task::Waker;
30///
31/// use qubit_io::AsyncByteInput;
32/// use qubit_io::AsyncInput;
33///
34/// struct ByteSlice<'a> {
35///     items: &'a [u8],
36///     position: usize,
37/// }
38///
39/// impl AsyncInput for ByteSlice<'_> {
40///     type Item = u8;
41///
42///     unsafe fn poll_read_unchecked(
43///         self: Pin<&mut Self>,
44///         _cx: &mut Context<'_>,
45///         output: &mut [u8],
46///         index: usize,
47///         count: usize,
48///     ) -> Poll<io::Result<usize>> {
49///         let this = self.get_mut();
50///         let n = count.min(this.items.len() - this.position);
51///         output[index..index + n]
52///             .copy_from_slice(&this.items[this.position..this.position + n]);
53///         this.position += n;
54///         Poll::Ready(Ok(n))
55///     }
56/// }
57///
58/// fn read<S: AsyncByteInput + ?Sized>(
59///     stream: Pin<&mut S>,
60///     cx: &mut Context<'_>,
61///     output: &mut [u8],
62/// ) -> Poll<io::Result<usize>> {
63///     stream.poll_read(cx, output)
64/// }
65///
66/// let mut stream = ByteSlice {
67///     items: b"QBIT",
68///     position: 0,
69/// };
70/// let mut cx = Context::from_waker(Waker::noop());
71/// let mut output = [0; 4];
72/// assert!(matches!(
73///     read(Pin::new(&mut stream), &mut cx, &mut output),
74///     Poll::Ready(Ok(4))
75/// ));
76/// assert_eq!(&output, b"QBIT");
77/// assert!(matches!(
78///     read(Pin::new(&mut stream), &mut cx, &mut output),
79///     Poll::Ready(Ok(0))
80/// ));
81/// ```
82/// Streams with a different item type do not satisfy this bound:
83///
84/// ```compile_fail
85/// use qubit_io::AsyncByteInput;
86/// use qubit_io::AsyncInput;
87///
88/// fn accept(stream: impl AsyncByteInput) {}
89///
90/// fn reject(stream: impl AsyncInput<Item = char>) {
91///     accept(stream);
92/// }
93/// ```
94pub trait AsyncByteInput: AsyncInput<Item = u8> {
95    // empty
96}
97
98impl<T: AsyncInput<Item = u8> + ?Sized> AsyncByteInput for T {}