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 bounds once at construction
41 let total = parent.current_len()?;
42 let _ = slice_range(offset, len, total)?;
43 Ok(Self {
44 parent,
45 offset,
46 len,
47 })
48 }
49
50 /// Return the segment as a read-only byte slice.
51 ///
52 /// # Errors
53 ///
54 /// Returns errors from the underlying `MemoryMappedFile::as_slice` call.
55 ///
56 /// Note: Bounds are already validated at construction, so as_slice
57 /// will not perform redundant validation.
58 pub fn as_slice(&self) -> Result<&[u8]> {
59 // Bounds already validated in constructor
60 self.parent.as_slice(self.offset, self.len)
61 }
62
63 /// Length of the segment.
64 #[must_use]
65 pub fn len(&self) -> u64 {
66 self.len
67 }
68
69 /// Check if the segment is empty.
70 #[must_use]
71 pub fn is_empty(&self) -> bool {
72 self.len == 0
73 }
74
75 /// Offset of the segment in the file.
76 #[must_use]
77 pub fn offset(&self) -> u64 {
78 self.offset
79 }
80
81 /// Parent mapping.
82 #[must_use]
83 pub fn parent(&self) -> &MemoryMappedFile {
84 &self.parent
85 }
86}
87
88/// Mutable view into a region of a memory-mapped file.
89/// Holds a reference to the parent map; mutable access is provided on demand.
90///
91/// # Examples
92///
93/// ```no_run
94/// use std::sync::Arc;
95/// use mmap_io::{MemoryMappedFile, segment::SegmentMut};
96///
97/// let mmap = Arc::new(MemoryMappedFile::create_rw("data.bin", 1024)?);
98///
99/// // Create a mutable segment for bytes 0-100
100/// let segment = SegmentMut::new(mmap.clone(), 0, 100)?;
101///
102/// // Write data to the segment
103/// segment.write(b"Hello from segment!")?;
104/// # Ok::<(), mmap_io::MmapIoError>(())
105/// ```
106#[derive(Clone, Debug)]
107pub struct SegmentMut {
108 parent: Arc<MemoryMappedFile>,
109 offset: u64,
110 len: u64,
111}
112
113impl SegmentMut {
114 /// Create a new mutable segment view. Performs bounds checks.
115 ///
116 /// # Errors
117 ///
118 /// Returns `MmapIoError::OutOfBounds` if the segment exceeds file bounds.
119 pub fn new(parent: Arc<MemoryMappedFile>, offset: u64, len: u64) -> Result<Self> {
120 // Validate bounds once at construction
121 let total = parent.current_len()?;
122 let _ = slice_range(offset, len, total)?;
123 Ok(Self {
124 parent,
125 offset,
126 len,
127 })
128 }
129
130 /// Return a write-capable guard to the underlying bytes for this segment.
131 /// The guard holds the write lock for the duration of the mutable borrow.
132 ///
133 /// # Errors
134 ///
135 /// Returns errors from the underlying `MemoryMappedFile::as_slice_mut` call.
136 ///
137 /// Note: Bounds are already validated at construction, so as_slice_mut
138 /// will not perform redundant validation.
139 pub fn as_slice_mut(&self) -> Result<crate::mmap::MappedSliceMut<'_>> {
140 // Bounds already validated in constructor
141 self.parent.as_slice_mut(self.offset, self.len)
142 }
143
144 /// Write bytes into this segment from the provided slice.
145 ///
146 /// # Errors
147 ///
148 /// Returns errors from the underlying `MemoryMappedFile::update_region` call.
149 pub fn write(&self, data: &[u8]) -> Result<()> {
150 if data.len() as u64 != self.len {
151 // Allow partial writes by delegating to update_region only over provided length.
152 return self.parent.update_region(self.offset, data);
153 }
154 self.parent.update_region(self.offset, data)
155 }
156
157 /// Length of the segment.
158 #[must_use]
159 pub fn len(&self) -> u64 {
160 self.len
161 }
162
163 /// Check if the segment is empty.
164 #[must_use]
165 pub fn is_empty(&self) -> bool {
166 self.len == 0
167 }
168
169 /// Offset of the segment in the file.
170 #[must_use]
171 pub fn offset(&self) -> u64 {
172 self.offset
173 }
174
175 /// Parent mapping.
176 #[must_use]
177 pub fn parent(&self) -> &MemoryMappedFile {
178 &self.parent
179 }
180}