mmap_io/segment.rs
1//! Zero-copy segment views into a memory-mapped file.
2
3use std::sync::Arc;
4
5use crate::errors::Result;
6use crate::mmap::MemoryMappedFile;
7use crate::utils::slice_range;
8
9/// Immutable view into a region of a memory-mapped file.
10///
11/// # Examples
12///
13/// ```no_run
14/// use std::sync::Arc;
15/// use mmap_io::{MemoryMappedFile, segment::Segment};
16///
17/// let mmap = Arc::new(MemoryMappedFile::open_ro("data.bin")?);
18///
19/// // Create a segment for bytes 100-200
20/// let segment = Segment::new(mmap.clone(), 100, 100)?;
21///
22/// // Read the segment data
23/// let data = segment.as_slice()?;
24/// # Ok::<(), mmap_io::MmapIoError>(())
25/// ```
26#[derive(Clone, Debug)]
27pub struct Segment {
28 parent: Arc<MemoryMappedFile>,
29 offset: u64,
30 len: u64,
31}
32
33impl Segment {
34 /// Create a new immutable segment view. Performs bounds checks.
35 ///
36 /// # Errors
37 ///
38 /// Returns `MmapIoError::OutOfBounds` if the segment exceeds file bounds.
39 pub fn new(parent: Arc<MemoryMappedFile>, offset: u64, len: u64) -> Result<Self> {
40 // Validate at construction
41 let total = parent.current_len()?;
42 // slice_range also validates bounds
43 let _ = slice_range(offset, len, total)?;
44 Ok(Self { parent, offset, len })
45 }
46
47 /// Return the segment as a read-only byte slice.
48 ///
49 /// # Errors
50 ///
51 /// Returns errors from the underlying `MemoryMappedFile::as_slice` call.
52 pub fn as_slice(&self) -> Result<&[u8]> {
53 self.parent.as_slice(self.offset, self.len)
54 }
55
56 /// Length of the segment.
57 #[must_use]
58 pub fn len(&self) -> u64 {
59 self.len
60 }
61
62 /// Check if the segment is empty.
63 #[must_use]
64 pub fn is_empty(&self) -> bool {
65 self.len == 0
66 }
67
68 /// Offset of the segment in the file.
69 #[must_use]
70 pub fn offset(&self) -> u64 {
71 self.offset
72 }
73
74 /// Parent mapping.
75 #[must_use]
76 pub fn parent(&self) -> &MemoryMappedFile {
77 &self.parent
78 }
79}
80
81/// Mutable view into a region of a memory-mapped file.
82/// Holds a reference to the parent map; mutable access is provided on demand.
83///
84/// # Examples
85///
86/// ```no_run
87/// use std::sync::Arc;
88/// use mmap_io::{MemoryMappedFile, segment::SegmentMut};
89///
90/// let mmap = Arc::new(MemoryMappedFile::create_rw("data.bin", 1024)?);
91///
92/// // Create a mutable segment for bytes 0-100
93/// let segment = SegmentMut::new(mmap.clone(), 0, 100)?;
94///
95/// // Write data to the segment
96/// segment.write(b"Hello from segment!")?;
97/// # Ok::<(), mmap_io::MmapIoError>(())
98/// ```
99#[derive(Clone, Debug)]
100pub struct SegmentMut {
101 parent: Arc<MemoryMappedFile>,
102 offset: u64,
103 len: u64,
104}
105
106impl SegmentMut {
107 /// Create a new mutable segment view. Performs bounds checks.
108 ///
109 /// # Errors
110 ///
111 /// Returns `MmapIoError::OutOfBounds` if the segment exceeds file bounds.
112 pub fn new(parent: Arc<MemoryMappedFile>, offset: u64, len: u64) -> Result<Self> {
113 let total = parent.current_len()?;
114 let _ = slice_range(offset, len, total)?;
115 Ok(Self { parent, offset, len })
116 }
117
118 /// Return a write-capable guard to the underlying bytes for this segment.
119 /// The guard holds the write lock for the duration of the mutable borrow.
120 ///
121 /// # Errors
122 ///
123 /// Returns errors from the underlying `MemoryMappedFile::as_slice_mut` call.
124 pub fn as_slice_mut(&self) -> Result<crate::mmap::MappedSliceMut<'_>> {
125 self.parent.as_slice_mut(self.offset, self.len)
126 }
127
128 /// Write bytes into this segment from the provided slice.
129 ///
130 /// # Errors
131 ///
132 /// Returns errors from the underlying `MemoryMappedFile::update_region` call.
133 pub fn write(&self, data: &[u8]) -> Result<()> {
134 if data.len() as u64 != self.len {
135 // Allow partial writes by delegating to update_region only over provided length.
136 return self.parent.update_region(self.offset, data);
137 }
138 self.parent.update_region(self.offset, data)
139 }
140
141 /// Length of the segment.
142 #[must_use]
143 pub fn len(&self) -> u64 {
144 self.len
145 }
146
147 /// Check if the segment is empty.
148 #[must_use]
149 pub fn is_empty(&self) -> bool {
150 self.len == 0
151 }
152
153 /// Offset of the segment in the file.
154 #[must_use]
155 pub fn offset(&self) -> u64 {
156 self.offset
157 }
158
159 /// Parent mapping.
160 #[must_use]
161 pub fn parent(&self) -> &MemoryMappedFile {
162 &self.parent
163 }
164}