Skip to main content

hexz_core/store/
mod.rs

1//! Storage backends for archive byte access.
2//!
3//! Implements the `StorageBackend` trait for local files, HTTP (blocking and
4//! async), memory-mapped files, and S3-compatible object storage. Higher
5//! layers use these backends to fetch raw bytes without caring about the
6//! transport.
7
8use bytes::Bytes;
9use hexz_common::Result;
10use std::fmt::Debug;
11
12/// Abstract interface for all byte-addressable archive storage backends.
13///
14/// **Architectural intent:** Decouples the archive decoding logic from the
15/// physical storage medium so that files, HTTP endpoints, memory maps, or
16/// object stores can be swapped without changing higher layers.
17///
18/// **Constraints:** Implementations must be thread-safe (`Send + Sync`) and
19/// provide stable, random-access reads over an immutable byte region whose
20/// length does not change during the lifetime of the backend.
21///
22/// **Side effects:** Individual calls may perform disk or network I/O and may
23/// block the calling thread; callers are responsible for scheduling behavior.
24pub trait StorageBackend: Send + Sync + Debug {
25    /// Reads exactly `len` bytes starting at `offset` from the underlying store.
26    ///
27    /// **Architectural intent:** Provides the minimal primitive needed by the
28    /// format layer to fetch headers, indices, and compressed blocks.
29    ///
30    /// **Constraints:** `offset + len` must not exceed `self.len()`; callers
31    /// should treat short reads or I/O errors as fatal for the current
32    /// operation.
33    ///
34    /// **Side effects:** May perform synchronous I/O and allocate a new
35    /// `Bytes` buffer per call; repeated small reads can be expensive.
36    fn read_exact(&self, offset: u64, len: usize) -> Result<Bytes>;
37
38    /// Returns the total logical size of the underlying archive in bytes.
39    ///
40    /// **Architectural intent:** Allows upper layers to validate range
41    /// requests and compute offsets into the header and index regions.
42    ///
43    /// **Constraints:** The length is assumed to be immutable for the lifetime
44    /// of the backend; changing it concurrently is undefined behavior.
45    fn len(&self) -> u64;
46
47    /// Returns `true` if the underlying store has zero length.
48    ///
49    /// **Architectural intent:** Convenience helper to avoid repeated `len()`
50    /// comparisons in call sites that need to quickly reject empty inputs.
51    ///
52    /// **Constraints:** Equivalent to `self.len() == 0`; implementations
53    /// should not override the default semantics.
54    fn is_empty(&self) -> bool {
55        self.len() == 0
56    }
57}