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 {}