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}