qubit-fs 0.2.2

Provider-neutral synchronous and asynchronous filesystem abstraction for Rust
Documentation
// =============================================================================
//    Copyright (c) 2026 Haixing Hu.
//
//    SPDX-License-Identifier: Apache-2.0
//
//    Licensed under the Apache License, Version 2.0.
// =============================================================================
//! Concrete synchronous file reader handle.

use std::fmt::Debug;
use std::fmt::Formatter;
use std::fmt::Result as FmtResult;
use std::io::Result as IoResult;

use qubit_io::Input;

use crate::metadata::OpenedFileInfo;

/// Type-erased byte input explicitly associated with an opened file.
///
/// # Examples
///
/// The example runs against an isolated in-memory fixture. Applications obtain
/// their configured facade from a provider or registry integration.
///
/// ```rust
/// # mod support { include!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/common/rustdoc_support.rs")); }
/// # let filesystem = support::rustdoc_provider::filesystem();
/// use qubit_fs::Path;
/// use qubit_fs::read::ReadOptions;
/// use qubit_io::Input;
///
/// let mut reader = filesystem.open_reader(&Path::parse("/report")?, ReadOptions::default())?;
/// let mut prefix = [0; 3];
/// assert_eq!(3, reader.read_fully(&mut prefix)?);
/// assert_eq!(*b"rep", prefix);
/// # Ok::<(), Box<dyn std::error::Error>>(())
/// ```
pub struct FileReader {
    /// Provider byte input.
    inner: Box<dyn Input<Item = u8> + Send>,
    /// Stable identity and metadata captured at open time.
    info: OpenedFileInfo,
}

impl FileReader {
    /// Wraps a provider byte input with its fixed file identity.
    ///
    /// Calling this constructor is the explicit provider adaptation step. An
    /// arbitrary [`Input`] does not automatically become a file reader.
    ///
    /// # Parameters
    /// - `inner`: Already-open byte input.
    /// - `info`: File identity and optional open-time metadata snapshot.
    ///
    /// # Returns
    /// A concrete file reader handle.
    #[inline]
    #[must_use]
    pub(crate) fn new(info: OpenedFileInfo, inner: Box<dyn Input<Item = u8> + Send>) -> Self {
        Self { inner, info }
    }

    /// Returns the fixed identity and open-time metadata snapshot.
    ///
    /// # Returns
    /// Information captured when the reader was opened.
    #[inline]
    #[must_use]
    pub fn info(&self) -> &OpenedFileInfo {
        &self.info
    }
}

impl Input for FileReader {
    type Item = u8;

    #[inline]
    fn is_buffered(&self) -> bool {
        self.inner.is_buffered()
    }

    #[inline]
    unsafe fn read_unchecked(&mut self, output: &mut [u8], index: usize, count: usize) -> IoResult<usize> {
        // SAFETY: The caller guarantees the same range contract required by
        // the wrapped input.
        unsafe { self.inner.read_unchecked(output, index, count) }
    }
}

impl Debug for FileReader {
    #[inline]
    fn fmt(&self, formatter: &mut Formatter<'_>) -> FmtResult {
        formatter
            .debug_struct("FileReader")
            .field("info", &self.info)
            .finish_non_exhaustive()
    }
}