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}