Skip to main content

qubit_io/buffered/
ensured_buffered_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    Result,
11    SeekFrom,
12};
13
14use crate::{
15    BufferedInput,
16    Input,
17    Seekable,
18    SeekableInput,
19};
20
21/// Input value that is guaranteed to report itself as buffered.
22///
23/// This enum is returned by [`BufferedInput::ensure`]. It keeps an input that
24/// already buffers items as-is, and wraps an unbuffered input in
25/// [`BufferedInput`]. Operations delegate to the selected branch.
26pub enum EnsuredBufferedInput<I>
27where
28    I: Input,
29    I::Item: Copy + Default,
30{
31    /// The original input already reported itself as buffered.
32    AlreadyBuffered(I),
33
34    /// The original input was wrapped in [`BufferedInput`].
35    Buffered(BufferedInput<I>),
36}
37
38impl<I> Input for EnsuredBufferedInput<I>
39where
40    I: Input,
41    I::Item: Copy + Default,
42{
43    type Item = I::Item;
44
45    /// Reports that this input is buffered.
46    #[inline(always)]
47    fn is_buffered(&self) -> bool {
48        true
49    }
50
51    /// Reads items from the selected input branch.
52    #[inline(always)]
53    unsafe fn read_unchecked(
54        &mut self,
55        output: &mut [Self::Item],
56        index: usize,
57        count: usize,
58    ) -> Result<usize> {
59        match self {
60            Self::AlreadyBuffered(input) => {
61                // SAFETY: Forwarded from the trait caller.
62                unsafe { input.read_unchecked(output, index, count) }
63            }
64            Self::Buffered(input) => {
65                // SAFETY: Forwarded from the trait caller.
66                unsafe { input.read_unchecked(output, index, count) }
67            }
68        }
69    }
70
71    /// Reads items into the full output slice.
72    #[inline(always)]
73    fn read(&mut self, output: &mut [Self::Item]) -> Result<usize> {
74        match self {
75            Self::AlreadyBuffered(input) => input.read(output),
76            Self::Buffered(input) => input.read(output),
77        }
78    }
79
80    /// Reads items until the indexed output range is full or EOF is reached.
81    #[inline(always)]
82    unsafe fn read_fully_unchecked(
83        &mut self,
84        output: &mut [Self::Item],
85        index: usize,
86        count: usize,
87    ) -> Result<usize> {
88        match self {
89            Self::AlreadyBuffered(input) => {
90                // SAFETY: Forwarded from the trait caller.
91                unsafe { input.read_fully_unchecked(output, index, count) }
92            }
93            Self::Buffered(input) => {
94                // SAFETY: Forwarded from the trait caller.
95                unsafe { input.read_fully_unchecked(output, index, count) }
96            }
97        }
98    }
99
100    /// Reads items into the full output slice until it is full or EOF is
101    /// reached.
102    #[inline(always)]
103    fn read_fully(&mut self, output: &mut [Self::Item]) -> Result<usize> {
104        match self {
105            Self::AlreadyBuffered(input) => input.read_fully(output),
106            Self::Buffered(input) => input.read_fully(output),
107        }
108    }
109}
110
111impl<I> Seekable for EnsuredBufferedInput<I>
112where
113    I: SeekableInput,
114    <I as Input>::Item: Copy + Default,
115{
116    type Unit = <I as Input>::Item;
117
118    /// Seeks in item offsets through the selected input branch.
119    #[inline(always)]
120    fn seek_to(&mut self, position: SeekFrom) -> Result<u64> {
121        match self {
122            Self::AlreadyBuffered(input) => input.seek_to(position),
123            Self::Buffered(input) => input.seek_to(position),
124        }
125    }
126}