cherenkov_model_data/
source.rs1use crate::{DataSpan, ObjectId};
2use anyhow::{Context, Result, ensure};
3use memmap2::Mmap;
4use std::{fs::File, io::Write, path::Path, sync::Arc};
5
6#[derive(Debug, Clone)]
8pub struct ObjectInfo {
9 pub id: ObjectId,
11 pub bytes: u64,
13}
14
15pub trait ByteSource {
18 fn objects(&self) -> Vec<ObjectInfo>;
20 fn read(&self, span: &DataSpan, output: &mut dyn Write) -> Result<()>;
22
23 fn map(&self, _span: &DataSpan) -> Result<Option<MappedBytes>> {
26 Ok(None)
27 }
28}
29
30#[derive(Clone, Default)]
32pub struct MappedObjects {
33 mappings: Vec<Arc<Mmap>>,
34}
35
36#[derive(Clone)]
39pub struct MappedBytes {
40 backing: Arc<Mmap>,
41 range: std::ops::Range<usize>,
42}
43
44impl AsRef<[u8]> for MappedBytes {
45 fn as_ref(&self) -> &[u8] {
46 &self.backing[self.range.clone()]
47 }
48}
49
50impl MappedObjects {
51 pub fn open<'a>(paths: impl IntoIterator<Item = &'a Path>) -> Result<Self> {
54 let mappings = paths
55 .into_iter()
56 .map(|path| {
57 let file =
58 File::open(path).with_context(|| format!("opening {}", path.display()))?;
59 let map = unsafe { Mmap::map(&file) }
62 .with_context(|| format!("mapping {}", path.display()))?;
63
64 Ok(Arc::new(map))
65 })
66 .collect::<Result<_>>()?;
67
68 Ok(Self { mappings })
69 }
70
71 pub fn mapping(&self, id: ObjectId) -> Result<&Mmap> {
74 self.mappings
75 .get(id.0)
76 .map(AsRef::as_ref)
77 .context("unknown checkpoint object")
78 }
79
80 pub fn bytes(&self, span: &DataSpan) -> Result<&[u8]> {
82 let map = self.mapping(span.object)?;
83 let range = checked_range(span, map.len())?;
84
85 Ok(&map[range])
86 }
87
88 pub fn view(&self, span: &DataSpan) -> Result<MappedBytes> {
90 let backing = self
91 .mappings
92 .get(span.object.0)
93 .context("unknown checkpoint object")?
94 .clone();
95 let range = checked_range(span, backing.len())?;
96
97 Ok(MappedBytes { backing, range })
98 }
99}
100
101impl ByteSource for MappedObjects {
102 fn objects(&self) -> Vec<ObjectInfo> {
103 self.mappings
104 .iter()
105 .enumerate()
106 .map(|(id, map)| ObjectInfo {
107 id: ObjectId(id),
108 bytes: map.len() as u64,
109 })
110 .collect()
111 }
112
113 fn read(&self, span: &DataSpan, output: &mut dyn Write) -> Result<()> {
114 output.write_all(self.bytes(span)?)?;
115
116 Ok(())
117 }
118
119 fn map(&self, span: &DataSpan) -> Result<Option<MappedBytes>> {
120 Ok(Some(self.view(span)?))
121 }
122}
123
124fn checked_range(span: &DataSpan, size: usize) -> Result<std::ops::Range<usize>> {
125 let end = span
126 .offset
127 .checked_add(span.length)
128 .context("data span overflow")?;
129
130 ensure!(end <= size as u64, "data span exceeds checkpoint object");
131
132 Ok(span.offset as usize..end as usize)
133}