Skip to main content

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::{
10    Error,
11    ErrorKind,
12    Read,
13    Result,
14};
15
16use crate::util::UncheckedSlice;
17
18/// Minimal indexed input interface over items.
19///
20/// `Input` is intentionally smaller and lower-level than [`Read`]. It only
21/// 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.
24pub trait Input {
25    /// The item type read from this input.
26    type Item;
27
28    /// Reads items into an indexed output range without checking the range.
29    ///
30    /// # Parameters
31    ///
32    /// * `output` - Destination storage.
33    /// * `index` - Start index inside `output`.
34    /// * `count` - Maximum number of items to read.
35    ///
36    /// # Returns
37    ///
38    /// The number of items written into `output[index..index + count]`. The
39    /// value must be in `0..=count`.
40    ///
41    /// # Errors
42    ///
43    /// Returns the input error reported by the implementation.
44    ///
45    /// # Safety
46    ///
47    /// The caller must guarantee that `index..index + count` is a valid range
48    /// inside `output` and that the addition does not overflow.
49    unsafe fn read_unchecked(
50        &mut self,
51        output: &mut [Self::Item],
52        index: usize,
53        count: usize,
54    ) -> Result<usize>;
55
56    /// Reads items into the full output slice.
57    ///
58    /// # Parameters
59    /// - `output`: Destination storage.
60    ///
61    /// # Returns
62    /// The number of items read into `output`.
63    ///
64    /// # Errors
65    ///
66    /// Returns the input error reported by the implementation. Returns
67    /// [`ErrorKind::InvalidData`] if the implementation reports reading more
68    /// items than requested.
69    #[inline(always)]
70    fn read(&mut self, output: &mut [Self::Item]) -> Result<usize> {
71        // SAFETY: The caller ensured the destination slice is valid.
72        let read = unsafe { self.read_unchecked(output, 0, output.len()) }?;
73        validate_read_count(read, output.len())?;
74        Ok(read)
75    }
76}
77
78impl<R> Input for R
79where
80    R: Read + ?Sized,
81{
82    type Item = u8;
83
84    /// Reads bytes from a standard [`Read`] value into an indexed range.
85    #[inline(always)]
86    unsafe fn read_unchecked(
87        &mut self,
88        output: &mut [u8],
89        index: usize,
90        count: usize,
91    ) -> Result<usize> {
92        debug_assert!(
93            UncheckedSlice::range_fits(output.len(), index, count),
94            "unchecked read range exceeds output buffer"
95        );
96        // SAFETY: The caller guarantees that the range is valid inside
97        // `output`.
98        let target =
99            unsafe { UncheckedSlice::subslice_mut(output, index, count) };
100        Read::read(self, target)
101    }
102
103    /// Reads items into the full output slice.
104    #[inline(always)]
105    fn read(&mut self, output: &mut [Self::Item]) -> Result<usize> {
106        Read::read(self, output)
107    }
108}
109
110/// Validates an item count returned by an input.
111///
112/// # Parameters
113///
114/// * `read` - Item count reported by the input.
115/// * `requested` - Maximum item count requested from the input.
116///
117/// # Errors
118///
119/// Returns [`ErrorKind::InvalidData`] when the input reports more items than
120/// the destination range could hold.
121#[inline(always)]
122pub fn validate_read_count(read: usize, requested: usize) -> Result<()> {
123    if read > requested {
124        return Err(Error::new(
125            ErrorKind::InvalidData,
126            format!(
127                "reader reported {read} items for a {requested}-item buffer"
128            ),
129        ));
130    }
131    Ok(())
132}