Skip to main content

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