petaplot_core/storage/
mmap_reader.rs1use std::fs::File;
2use std::path::{Path, PathBuf};
3use std::sync::Arc;
4use memmap2::{Mmap, MmapOptions};
5use crate::error::{Result, TeraError};
6
7#[derive(Clone)]
9pub struct MmapReader {
10 path: PathBuf,
11 mmap: Arc<Mmap>,
12}
13
14impl MmapReader {
15 pub fn open<P: AsRef<Path>>(path: P) -> Result<Self> {
19 let path_buf = path.as_ref().to_path_buf();
20 let file = File::open(&path_buf)?;
21
22 let mmap = unsafe {
23 MmapOptions::new()
24 .map(&file)
25 .map_err(|e| TeraError::Mmap(format!("Falló el mapeo de memoria para {:?}: {}", path_buf, e)))?
26 };
27
28 Ok(Self {
29 path: path_buf,
30 mmap: Arc::new(mmap),
31 })
32 }
33
34 pub fn path(&self) -> &Path {
36 &self.path
37 }
38
39 pub fn len(&self) -> usize {
41 self.mmap.len()
42 }
43
44 pub fn is_empty(&self) -> bool {
46 self.mmap.is_empty()
47 }
48
49 pub fn as_slice(&self) -> &[u8] {
51 &self.mmap[..]
52 }
53
54 pub fn as_slice_range(&self, range: std::ops::Range<usize>) -> Result<&[u8]> {
56 if range.end > self.mmap.len() || range.start > range.end {
57 return Err(TeraError::OutOfRange(format!(
58 "Rango {:?} fuera de los límites del archivo (tamaño total: {} bytes)",
59 range,
60 self.mmap.len()
61 )));
62 }
63 Ok(&self.mmap[range])
64 }
65
66 #[cfg(unix)]
68 pub fn advise_will_need(&self, offset: usize, length: usize) -> Result<()> {
69 let end = offset.saturating_add(length).min(self.mmap.len());
70 if offset >= self.mmap.len() {
71 return Ok(());
72 }
73
74 self.mmap
75 .advise_range(memmap2::Advice::WillNeed, offset, end - offset)
76 .map_err(|e| TeraError::Mmap(format!("Error en madvise(WillNeed): {}", e)))
77 }
78
79 #[cfg(not(unix))]
81 pub fn advise_will_need(&self, _offset: usize, _length: usize) -> Result<()> {
82 Ok(())
83 }
84}
85
86#[cfg(test)]
87mod tests {
88 use super::*;
89 use std::io::Write;
90
91 #[test]
92 fn test_mmap_reader_basic() -> Result<()> {
93 let temp_dir = std::env::temp_dir();
94 let test_file = temp_dir.join("petaplot_test_mmap.bin");
95
96 let sample_data = b"PetaPlot high performance zero-copy time series data engine.";
97 {
98 let mut file = File::create(&test_file)?;
99 file.write_all(sample_data)?;
100 }
101
102 let reader = MmapReader::open(&test_file)?;
103 assert_eq!(reader.len(), sample_data.len());
104 assert_eq!(reader.as_slice(), sample_data);
105 assert_eq!(reader.as_slice_range(0..8)?, b"PetaPlot");
106
107 let _ = std::fs::remove_file(&test_file);
108 Ok(())
109 }
110}