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}