qubit_io/traits/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 std::io::Error;
10use std::io::ErrorKind;
11use std::io::Result;
12
13use super::validate_read_count;
14use crate::ByteInput;
15use crate::StdRead;
16use crate::util::SliceRange;
17
18/// Minimal indexed input interface over items.
19///
20/// `Input` is intentionally smaller and lower-level than [`std::io::Read`]. It
21/// only states that an implementor can read up to `count` items into
22/// `output[index..index + count]`. The caller owns range validation so hot
23/// paths can avoid repeated slicing and bounds checks.
24///
25/// # Coherence note
26///
27/// Every [`std::io::Read`] value automatically implements `Input<Item = u8>`
28/// through the standard I/O integration. Because [`Input::Item`] is an
29/// associated type rather than a trait parameter, a concrete type that
30/// implements [`std::io::Read`] cannot also provide any other direct `Input`
31/// implementation for the same type, including one with a different item type.
32///
33/// Use a wrapper/newtype when a type needs item-oriented input semantics that
34/// differ from its byte-oriented [`std::io::Read`] implementation.
35///
36/// # Examples
37///
38/// Standard readers implement `Input<Item = u8>` automatically, so callers
39/// can use the trait methods directly on them:
40///
41/// ```
42/// use std::io::Cursor;
43///
44/// use qubit_io::Input;
45///
46/// let mut input = Cursor::new(b"data");
47/// let mut output = [0; 4];
48/// assert_eq!(Input::read(&mut input, &mut output).unwrap(), 4);
49/// assert_eq!(&output, b"data");
50/// ```
51pub trait Input {
52 /// The item type read from this input.
53 type Item;
54
55 /// Converts this byte input into a standard library reader.
56 ///
57 /// The conversion only wraps `self`; it performs no I/O and does not
58 /// allocate. The wrapped input can be recovered with
59 /// [`StdRead::into_inner`].
60 ///
61 /// # Returns
62 ///
63 /// A standard library reader that owns the converted input.
64 ///
65 /// # Examples
66 ///
67 /// ```
68 /// use qubit_io::Input;
69 /// use std::io::Read;
70 ///
71 /// let input = std::io::Cursor::new(b"hello");
72 /// let mut reader = input.into_std_read();
73 /// let mut bytes = Vec::new();
74 /// reader.read_to_end(&mut bytes).unwrap();
75 /// assert_eq!(bytes, b"hello");
76 /// let input = reader.into_inner();
77 /// assert_eq!(input.position(), 5);
78 /// ```
79 ///
80 /// Non-byte inputs cannot be converted:
81 ///
82 /// ```compile_fail
83 /// use qubit_io::Input;
84 ///
85 /// fn convert<I: Input<Item = char>>(input: I) {
86 /// let _reader = input.into_std_read();
87 /// }
88 /// ```
89 #[inline]
90 fn into_std_read(self) -> StdRead<Self>
91 where
92 Self: Sized + ByteInput,
93 {
94 StdRead::new(self)
95 }
96
97 /// Returns whether this input already buffers items internally.
98 ///
99 /// # Returns
100 ///
101 /// `true` when callers should avoid wrapping this input in another generic
102 /// item buffer automatically.
103 #[inline(always)]
104 #[must_use]
105 fn is_buffered(&self) -> bool {
106 false
107 }
108
109 /// Reads items into an indexed output range without checking the range.
110 ///
111 /// # Parameters
112 ///
113 /// * `output` - Destination storage.
114 /// * `index` - Start index inside `output`.
115 /// * `count` - Maximum number of items to read.
116 ///
117 /// # Returns
118 ///
119 /// The number of items written into `output[index..index + count]`. The
120 /// value must be in `0..=count`. A successful call transfers a prefix of
121 /// the requested range and may be short. For a non-empty request, `Ok(0)`
122 /// means that no items were available in this call or that the stream
123 /// reached its end; it does not promise permanent EOF. Aggregate reads
124 /// stop on this zero progress: [`Input::read_fully`] returns the
125 /// accumulated count, while [`Input::read_exactly`] reports
126 /// [`ErrorKind::UnexpectedEof`] if the destination is not full. For a
127 /// zero-length request, a successful call returns zero, which does not
128 /// establish EOF. Empty requests are not guaranteed to suppress
129 /// implementation errors or avoid an inner call.
130 ///
131 /// # Errors
132 ///
133 /// Returns the input error reported by the implementation. An
134 /// [`ErrorKind::Interrupted`] result is retried by aggregate read methods
135 /// and therefore means this call made no confirmed transfer. If a valid
136 /// prefix was transferred, return `Ok(n)` for it and report a later error
137 /// on a subsequent call. A later aggregate error does not undo successful
138 /// earlier calls. Errors with applied or uncertain side effects must not
139 /// be represented as retryable `Interrupted` solely to request a retry;
140 /// the adapter or caller must choose a policy for those effects.
141 ///
142 /// # Safety
143 ///
144 /// The caller must guarantee that `index..index + count` is a valid range
145 /// inside `output` and that the addition does not overflow.
146 unsafe fn read_unchecked(&mut self, output: &mut [Self::Item], index: usize, count: usize) -> Result<usize>;
147
148 /// Reads items into the full output slice.
149 ///
150 /// # Parameters
151 /// - `output`: Destination storage.
152 ///
153 /// # Returns
154 /// The number of items read into `output`. A successful call transfers a
155 /// prefix and may be short. For a non-empty request, `Ok(0)` means that no
156 /// items were available in this call or that the stream reached its end;
157 /// it does not promise permanent EOF. Aggregate reads stop on this zero
158 /// progress: [`Input::read_fully`] returns the accumulated count, while
159 /// [`Input::read_exactly`] reports [`ErrorKind::UnexpectedEof`] if the
160 /// destination is not full. For a zero-length request, a successful call
161 /// returns zero, which does not establish EOF. Empty requests are not
162 /// guaranteed to suppress implementation errors or avoid an inner call.
163 ///
164 /// # Errors
165 ///
166 /// Returns the input error reported by the implementation. Returns
167 /// [`ErrorKind::InvalidData`] if the implementation reports reading more
168 /// items than requested.
169 #[inline(always)]
170 fn read(&mut self, output: &mut [Self::Item]) -> Result<usize> {
171 // SAFETY: The caller ensured the destination slice is valid.
172 let read = unsafe { self.read_unchecked(output, 0, output.len()) }?;
173 validate_read_count(read, output.len())?;
174 Ok(read)
175 }
176
177 /// Reads items into an indexed output range until it is full or EOF is
178 /// reached.
179 ///
180 /// This method retries interrupted reads and treats EOF as a successful
181 /// partial result.
182 ///
183 /// # Parameters
184 ///
185 /// * `output` - Destination storage.
186 /// * `index` - Start index inside `output`.
187 /// * `count` - Maximum number of items to read.
188 ///
189 /// # Returns
190 ///
191 /// The number of items written into `output[index..index + count]`.
192 ///
193 /// # Errors
194 ///
195 /// Returns the first non-[`ErrorKind::Interrupted`] input error. Returns
196 /// [`ErrorKind::InvalidData`] if the implementation reports more items than
197 /// requested.
198 ///
199 /// # Panics
200 ///
201 /// Panics in debug builds if the requested output range does not fit.
202 ///
203 /// # Safety
204 ///
205 /// The caller must guarantee that `index..index + count` is a valid range
206 /// inside `output` and that the addition does not overflow.
207 unsafe fn read_fully_unchecked(&mut self, output: &mut [Self::Item], index: usize, count: usize) -> Result<usize> {
208 debug_assert!(
209 SliceRange::range_fits(output.len(), index, count),
210 "unchecked read-fully range exceeds output buffer"
211 );
212 let mut total = 0;
213 while total < count {
214 let remaining = count - total;
215 // SAFETY: The caller guarantees the original destination range is
216 // valid; `total < count`, so this suffix remains inside it.
217 match unsafe { self.read_unchecked(output, index + total, remaining) } {
218 Ok(0) => break,
219 Ok(read) => {
220 validate_read_count(read, remaining)?;
221 total += read;
222 }
223 Err(error) if error.kind() == ErrorKind::Interrupted => {}
224 Err(error) => return Err(error),
225 }
226 }
227 Ok(total)
228 }
229
230 /// Reads items into the full output slice until it is full or EOF is
231 /// reached.
232 ///
233 /// # Parameters
234 /// - `output`: Destination storage to fill as far as possible.
235 ///
236 /// # Returns
237 /// The number of items written into `output`.
238 ///
239 /// # Errors
240 /// Returns the first non-interrupted input error, or
241 /// [`ErrorKind::InvalidData`] if the implementation reports an impossible
242 /// item count.
243 #[inline(always)]
244 fn read_fully(&mut self, output: &mut [Self::Item]) -> Result<usize> {
245 // SAFETY: The full output slice is a valid destination range.
246 let read = unsafe { self.read_fully_unchecked(output, 0, output.len()) }?;
247 validate_read_count(read, output.len())?;
248 Ok(read)
249 }
250
251 /// Reads items until the full output slice is filled.
252 ///
253 /// # Parameters
254 ///
255 /// * `output` - Destination storage that must be filled completely.
256 ///
257 /// # Returns
258 ///
259 /// `Ok(())` after the destination has been filled completely.
260 ///
261 /// # Errors
262 ///
263 /// Returns [`ErrorKind::UnexpectedEof`] if the input ends before filling
264 /// `output`. Returns the first non-interrupted input error, or
265 /// [`ErrorKind::InvalidData`] if the implementation reports an impossible
266 /// item count.
267 #[inline]
268 fn read_exactly(&mut self, output: &mut [Self::Item]) -> Result<()> {
269 let read = self.read_fully(output)?;
270 validate_read_count(read, output.len())?;
271 if read == output.len() {
272 Ok(())
273 } else {
274 Err(Error::new(
275 ErrorKind::UnexpectedEof,
276 "failed to fill whole input buffer",
277 ))
278 }
279 }
280
281 /// Reads items into multiple buffers in list order.
282 ///
283 /// The buffers form one logical sequence in list order. `Ok(n)` means that
284 /// the first `n` items of that sequence were read, and `n` must not exceed
285 /// the total requested length. A read may make short progress and need not
286 /// fill every buffer; `n` may cross a buffer boundary. For a non-empty
287 /// request, `Ok(0)` means that no data was available in this call or that
288 /// the stream reached its end; it does not promise permanent EOF.
289 ///
290 /// The default implementation skips empty buffers and calls [`Input::read`]
291 /// once on the first non-empty buffer. It does not continue to later
292 /// buffers after a short read. This is only the default strategy, not a
293 /// limit on overrides. Empty lists and lists whose buffers are all empty
294 /// return `Ok(0)` without performing I/O. Interrupted errors are not
295 /// retried. An error does not undo progress from earlier independent calls.
296 /// An override must uphold the sequence and count contract itself; this
297 /// trait does not validate counts returned by arbitrary overrides. Use
298 /// UFCS when a standard I/O method with the same name is also in scope.
299 ///
300 /// # Parameters
301 ///
302 /// - `buffers`: Mutable destination slices, in the order to read them.
303 ///
304 /// # Returns
305 ///
306 /// The number of items read from the start of the logical sequence.
307 ///
308 /// # Errors
309 ///
310 /// Returns an error from the input operation. The default implementation
311 /// returns [`ErrorKind::InvalidData`] if the selected buffer reports more
312 /// items than it can hold. The standard I/O blanket implementation also
313 /// returns [`ErrorKind::InvalidInput`] if the total length overflows,
314 /// [`ErrorKind::OutOfMemory`] if preparing descriptors fails, or
315 /// [`ErrorKind::InvalidData`] if the standard reader reports more than the
316 /// total capacity. A custom override is responsible for its own checks.
317 ///
318 /// # Examples
319 ///
320 /// This example uses a non-byte stream through a trait object. The default
321 /// method reads only the first non-empty slice; an override may use more.
322 /// For vectored overrides, a count can cross a slice boundary: if two
323 /// destination slices each have length 2, `Ok(3)` means the first slice
324 /// and the first item of the second slice were filled.
325 ///
326 /// ```
327 /// use qubit_io::Input;
328 ///
329 /// struct Characters;
330 /// impl Input for Characters {
331 /// type Item = char;
332 /// unsafe fn read_unchecked(
333 /// &mut self,
334 /// output: &mut [char],
335 /// index: usize,
336 /// count: usize,
337 /// ) -> std::io::Result<usize> {
338 /// if count == 0 {
339 /// return Ok(0);
340 /// }
341 /// output[index] = '甲';
342 /// Ok(1)
343 /// }
344 /// }
345 /// let mut input = Characters;
346 /// let input: &mut dyn Input<Item = char> = &mut input;
347 /// let mut first = ['!'; 2];
348 /// let mut second = ['?'; 2];
349 /// assert_eq!(Input::read_vectored(input, &mut [&mut first, &mut second])?, 1);
350 /// assert_eq!(first, ['甲', '!']);
351 /// assert_eq!(second, ['?', '?']);
352 /// # Ok::<(), std::io::Error>(())
353 /// ```
354 fn read_vectored(&mut self, buffers: &mut [&mut [Self::Item]]) -> Result<usize> {
355 let Some(buffer) = buffers.iter_mut().find(|buffer| !buffer.is_empty()) else {
356 return Ok(0);
357 };
358 let count = self.read(buffer)?;
359 validate_read_count(count, buffer.len())?;
360 Ok(count)
361 }
362}