qubit_fs/read/file_reader.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//! Concrete synchronous file reader handle.
9
10use std::fmt::Debug;
11use std::fmt::Formatter;
12use std::fmt::Result as FmtResult;
13use std::io::Result as IoResult;
14
15use qubit_io::Input;
16
17use crate::metadata::OpenedFileInfo;
18
19/// Type-erased byte input explicitly associated with an opened file.
20///
21/// # Examples
22///
23/// The example runs against an isolated in-memory fixture. Applications obtain
24/// their configured facade from a provider or registry integration.
25///
26/// ```rust
27/// # mod support { include!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/common/rustdoc_support.rs")); }
28/// # let filesystem = support::rustdoc_provider::filesystem();
29/// use qubit_fs::Path;
30/// use qubit_fs::read::ReadOptions;
31/// use qubit_io::Input;
32///
33/// let mut reader = filesystem.open_reader(&Path::parse("/report")?, ReadOptions::default())?;
34/// let mut prefix = [0; 3];
35/// assert_eq!(3, reader.read_fully(&mut prefix)?);
36/// assert_eq!(*b"rep", prefix);
37/// # Ok::<(), Box<dyn std::error::Error>>(())
38/// ```
39pub struct FileReader {
40 /// Provider byte input.
41 inner: Box<dyn Input<Item = u8> + Send>,
42 /// Stable identity and metadata captured at open time.
43 info: OpenedFileInfo,
44}
45
46impl FileReader {
47 /// Wraps a provider byte input with its fixed file identity.
48 ///
49 /// Calling this constructor is the explicit provider adaptation step. An
50 /// arbitrary [`Input`] does not automatically become a file reader.
51 ///
52 /// # Parameters
53 /// - `inner`: Already-open byte input.
54 /// - `info`: File identity and optional open-time metadata snapshot.
55 ///
56 /// # Returns
57 /// A concrete file reader handle.
58 #[inline]
59 #[must_use]
60 pub(crate) fn new(info: OpenedFileInfo, inner: Box<dyn Input<Item = u8> + Send>) -> Self {
61 Self { inner, info }
62 }
63
64 /// Returns the fixed identity and open-time metadata snapshot.
65 ///
66 /// # Returns
67 /// Information captured when the reader was opened.
68 #[inline]
69 #[must_use]
70 pub fn info(&self) -> &OpenedFileInfo {
71 &self.info
72 }
73}
74
75impl Input for FileReader {
76 type Item = u8;
77
78 #[inline]
79 fn is_buffered(&self) -> bool {
80 self.inner.is_buffered()
81 }
82
83 #[inline]
84 unsafe fn read_unchecked(&mut self, output: &mut [u8], index: usize, count: usize) -> IoResult<usize> {
85 // SAFETY: The caller guarantees the same range contract required by
86 // the wrapped input.
87 unsafe { self.inner.read_unchecked(output, index, count) }
88 }
89}
90
91impl Debug for FileReader {
92 #[inline]
93 fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
94 formatter
95 .debug_struct("FileReader")
96 .field("info", &self.info)
97 .finish_non_exhaustive()
98 }
99}