mmap_guard/file_data.rs
1//! The [`FileData`] enum — a unified read-only view over memory-mapped and
2//! heap-allocated file data.
3
4use std::fs::File;
5use std::ops::Deref;
6
7use memmap2::Mmap;
8
9/// File data backed by either a memory map or a heap buffer.
10///
11/// Both variants dereference to `&[u8]`, so consumers can treat the data
12/// uniformly regardless of the backing store.
13///
14/// # Errors
15///
16/// This type does not produce errors directly. Errors arise from the
17/// functions that construct it — see [`map_file`](crate::map_file),
18/// [`load()`](crate::load()), and [`load_stdin`](crate::load_stdin).
19///
20/// # Compatibility
21///
22/// This enum is `#[non_exhaustive]`, so match arms must include a wildcard.
23/// The `Mapped` variant carries **two** fields — the memory map and the
24/// file handle (for advisory locking). Always pattern-match with `..`
25/// (e.g., `FileData::Mapped(..)`) rather than a fixed number of fields,
26/// so your code remains forward-compatible if additional fields are added.
27///
28/// # Examples
29///
30/// ```no_run
31/// use mmap_guard::map_file;
32///
33/// let data = map_file("example.bin").unwrap();
34/// let bytes: &[u8] = &data;
35/// println!("first byte: {:#04x}", bytes[0]);
36/// ```
37#[derive(Debug)]
38#[non_exhaustive]
39pub enum FileData {
40 /// Data backed by a read-only memory map (zero-copy).
41 ///
42 /// The [`File`] handle is retained to hold the advisory lock for the
43 /// lifetime of the map. Always match with `Mapped(..)` for forward
44 /// compatibility.
45 Mapped(Mmap, File),
46 /// Data loaded into a heap-allocated buffer.
47 Loaded(Vec<u8>),
48}
49
50impl Deref for FileData {
51 type Target = [u8];
52
53 fn deref(&self) -> &[u8] {
54 match self {
55 Self::Mapped(mmap, _file) => mmap,
56 Self::Loaded(vec) => vec,
57 }
58 }
59}
60
61impl AsRef<[u8]> for FileData {
62 fn as_ref(&self) -> &[u8] {
63 self
64 }
65}
66
67// Compile-time assertions: FileData must be Send + Sync so it can be shared
68// across threads (Mmap and File are both Send + Sync).
69// LCOV_EXCL_START — compile-time only, never called at runtime
70const _: () = {
71 const fn assert_send_sync<T: Send + Sync>() {}
72 #[allow(dead_code)]
73 const fn check() {
74 assert_send_sync::<FileData>();
75 }
76};
77// LCOV_EXCL_STOP
78
79#[cfg(test)]
80mod tests {
81 use super::*;
82
83 #[test]
84 fn loaded_variant_derefs_to_bytes() {
85 let data = FileData::Loaded(vec![0xDE, 0xAD, 0xBE, 0xEF]);
86 let bytes: &[u8] = &data;
87 assert_eq!(bytes, &[0xDE, 0xAD, 0xBE, 0xEF]);
88 }
89
90 #[test]
91 fn loaded_variant_as_ref() {
92 let data = FileData::Loaded(vec![1, 2, 3]);
93 let bytes: &[u8] = data.as_ref();
94 assert_eq!(bytes, &[1, 2, 3]);
95 }
96
97 #[test]
98 fn empty_loaded_variant() {
99 let data = FileData::Loaded(vec![]);
100 assert!(data.is_empty());
101 assert_eq!(data.len(), 0);
102 }
103}