Skip to main content

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}