qualia_core_db/q42/volume/
opfs_source.rs1use std::io;
16use std::path::Path;
17
18use super::car::{decode_and_verify_car, VerifiedCarBlock};
19use super::cid::CidSha256;
20use super::range::{validate_exact_range_response, Q42ByteRange, Q42RangeSource};
21
22fn invalid(message: impl Into<String>) -> io::Error {
23 io::Error::new(io::ErrorKind::InvalidInput, message.into())
24}
25
26fn short_fill() -> io::Error {
27 io::Error::new(
28 io::ErrorKind::InvalidData,
29 "OPFS range fill did not return exactly the requested Q42 bytes",
30 )
31}
32
33pub struct OpfsSliceRangeSource<B> {
35 bytes: B,
36}
37
38impl<B> OpfsSliceRangeSource<B> {
39 pub fn new(bytes: B) -> Self {
40 Self { bytes }
41 }
42}
43
44impl<B: AsRef<[u8]>> OpfsSliceRangeSource<B> {
45 pub fn as_bytes(&self) -> &[u8] {
46 self.bytes.as_ref()
47 }
48}
49
50impl<B: AsRef<[u8]>> Q42RangeSource for OpfsSliceRangeSource<B> {
51 fn length(&self) -> io::Result<u64> {
52 Ok(self.bytes.as_ref().len() as u64)
53 }
54
55 fn read_range_into(&self, range: Q42ByteRange, out: &mut [u8]) -> io::Result<()> {
56 copy_exact_slice(self.bytes.as_ref(), range, out)
57 }
58}
59
60pub struct OpfsCallbackRangeSource<F> {
65 length: u64,
66 fill: F,
67}
68
69impl<F> OpfsCallbackRangeSource<F>
70where
71 F: Fn(u64, usize, &mut [u8]) -> io::Result<usize>,
72{
73 pub fn new(length: u64, fill: F) -> Self {
74 Self { length, fill }
75 }
76}
77
78impl<F> Q42RangeSource for OpfsCallbackRangeSource<F>
79where
80 F: Fn(u64, usize, &mut [u8]) -> io::Result<usize>,
81{
82 fn length(&self) -> io::Result<u64> {
83 Ok(self.length)
84 }
85
86 fn read_range_into(&self, range: Q42ByteRange, out: &mut [u8]) -> io::Result<()> {
87 if out.len() != range.length {
88 return Err(invalid(
89 "Q42 range output buffer length does not match request",
90 ));
91 }
92 range.validate_for(self.length)?;
93 let filled = (self.fill)(range.offset, range.length, out)?;
94 if filled != range.length {
95 return Err(short_fill());
96 }
97 validate_exact_range_response(range, self.length, range.offset, filled)
98 }
99}
100
101pub type VerifiedCarRangeSource = OpfsSliceRangeSource<Vec<u8>>;
103
104pub fn verify_car_bytes_as_q42_source(car: &[u8]) -> io::Result<VerifiedCarRangeSource> {
106 let blocks = decode_and_verify_car(car)?;
107 Ok(OpfsSliceRangeSource::new(concatenate_raw_leaves(&blocks)))
108}
109
110pub fn verify_local_car_as_q42_source(path: &Path) -> io::Result<VerifiedCarRangeSource> {
116 let car = std::fs::read(path)?;
117 verify_car_bytes_as_q42_source(&car)
118}
119
120fn concatenate_raw_leaves(blocks: &[VerifiedCarBlock]) -> Vec<u8> {
121 let mut total = 0usize;
122 for block in blocks {
123 if block.cid.codec == CidSha256::RAW {
124 total = total.saturating_add(block.data.len());
125 }
126 }
127 let mut entity = Vec::with_capacity(total);
128 for block in blocks {
129 if block.cid.codec == CidSha256::RAW {
130 entity.extend_from_slice(&block.data);
131 }
132 }
133 entity
134}
135
136fn copy_exact_slice(bytes: &[u8], range: Q42ByteRange, out: &mut [u8]) -> io::Result<()> {
137 if out.len() != range.length {
138 return Err(invalid(
139 "Q42 range output buffer length does not match request",
140 ));
141 }
142 let source_length = bytes.len() as u64;
143 range.validate_for(source_length)?;
144 let start = usize::try_from(range.offset)
145 .map_err(|_| invalid("Q42 range offset exceeds platform"))?;
146 let end = start
147 .checked_add(range.length)
148 .ok_or_else(|| invalid("Q42 range overflows platform usize"))?;
149 out.copy_from_slice(&bytes[start..end]);
150 Ok(())
151}
152
153#[cfg(test)]
154mod tests {
155 use super::*;
156 use crate::q42_volume::write_unified_volume;
157 use crate::specialized_libs::computational_geometry::allocation_counter::assert_zero_alloc;
158 use crate::NQuin;
159 use std::collections::HashMap;
160 use std::io::Write;
161
162 use super::super::car::encode_raw_car;
163 use super::super::range::LocalFileRangeSource;
164 use tempfile::NamedTempFile;
165
166 fn tiny_unified_volume() -> NamedTempFile {
167 let file = NamedTempFile::new().unwrap();
168 write_unified_volume(
169 file.path(),
170 &HashMap::new(),
171 &[(3, 3)],
172 &[vec![NQuin {
173 subject: 1,
174 predicate: 2,
175 object: 3,
176 context: 0,
177 metadata: 0,
178 parity: 0,
179 }]],
180 )
181 .unwrap();
182 file
183 }
184
185 fn read_all<S: Q42RangeSource>(source: &S) -> Vec<u8> {
186 let length = usize::try_from(source.length().unwrap()).unwrap();
187 let mut out = vec![0u8; length];
188 source
189 .read_range_into(
190 Q42ByteRange {
191 offset: 0,
192 length,
193 },
194 &mut out,
195 )
196 .unwrap();
197 out
198 }
199
200 fn assert_same_ranges<A: Q42RangeSource, B: Q42RangeSource>(left: &A, right: &B) {
201 let left_len = left.length().unwrap();
202 let right_len = right.length().unwrap();
203 assert_eq!(left_len, right_len);
204 assert_eq!(read_all(left), read_all(right));
205
206 let mid_len = 16.min(left_len as usize);
207 if left_len >= 8 && mid_len > 0 {
208 let mut from_left = vec![0u8; mid_len];
209 let mut from_right = vec![0u8; mid_len];
210 let range = Q42ByteRange {
211 offset: 4,
212 length: mid_len,
213 };
214 left.read_range_into(range, &mut from_left).unwrap();
215 right.read_range_into(range, &mut from_right).unwrap();
216 assert_eq!(from_left, from_right);
217 }
218
219 let overflow = Q42ByteRange {
220 offset: left_len,
221 length: 1,
222 };
223 assert!(left.read_range_into(overflow, &mut [0u8; 1]).is_err());
224 assert!(right.read_range_into(overflow, &mut [0u8; 1]).is_err());
225 }
226
227 #[test]
228 fn slice_source_matches_local_file_on_tiny_unified_volume() {
229 let file = tiny_unified_volume();
230 let disk = LocalFileRangeSource::open(file.path()).unwrap();
231 let bytes = std::fs::read(file.path()).unwrap();
232 let slice = OpfsSliceRangeSource::new(bytes.as_slice());
233 assert_same_ranges(&disk, &slice);
234 assert_eq!(slice.as_bytes(), bytes.as_slice());
235 }
236
237 #[test]
238 fn callback_source_matches_local_file_on_tiny_unified_volume() {
239 let file = tiny_unified_volume();
240 let disk = LocalFileRangeSource::open(file.path()).unwrap();
241 let bytes = std::fs::read(file.path()).unwrap();
242 let callback = OpfsCallbackRangeSource::new(bytes.len() as u64, |offset, len, buf| {
243 copy_exact_slice(
244 &bytes,
245 Q42ByteRange {
246 offset,
247 length: len,
248 },
249 buf,
250 )?;
251 Ok(len)
252 });
253 assert_same_ranges(&disk, &callback);
254 }
255
256 #[test]
257 fn verified_local_car_exposes_the_same_entity_as_the_q42_file() {
258 let file = tiny_unified_volume();
259 let entity = std::fs::read(file.path()).unwrap();
260 let car = encode_raw_car(&[entity.as_slice()]);
261 let mut car_file = NamedTempFile::new().unwrap();
262 car_file.write_all(&car).unwrap();
263 car_file.flush().unwrap();
264
265 let source = verify_local_car_as_q42_source(car_file.path()).unwrap();
266 assert_eq!(source.as_bytes(), entity.as_slice());
267
268 let disk = LocalFileRangeSource::open(file.path()).unwrap();
269 assert_same_ranges(&disk, &source);
270 }
271
272 #[test]
273 fn tampered_local_car_is_rejected() {
274 let mut car = encode_raw_car(&[b"intact-q42-entity".as_slice()]);
275 *car.last_mut().unwrap() ^= 0xff;
276 let mut car_file = NamedTempFile::new().unwrap();
277 car_file.write_all(&car).unwrap();
278 car_file.flush().unwrap();
279 assert!(verify_local_car_as_q42_source(car_file.path()).is_err());
280 assert!(verify_car_bytes_as_q42_source(&car).is_err());
281 }
282
283 #[test]
284 fn short_callback_fill_is_rejected() {
285 let source = OpfsCallbackRangeSource::new(8, |_offset, _len, buf| {
286 buf[..2].copy_from_slice(b"ab");
287 Ok(2)
288 });
289 assert!(source
290 .read_range_into(
291 Q42ByteRange {
292 offset: 0,
293 length: 4
294 },
295 &mut [0u8; 4]
296 )
297 .is_err());
298 }
299
300 #[test]
301 fn slice_and_callback_hot_reads_are_zero_heap() {
302 let file = tiny_unified_volume();
303 let bytes = std::fs::read(file.path()).unwrap();
304 let slice = OpfsSliceRangeSource::new(bytes.as_slice());
305 let callback = OpfsCallbackRangeSource::new(bytes.len() as u64, |offset, len, buf| {
306 copy_exact_slice(
307 &bytes,
308 Q42ByteRange {
309 offset,
310 length: len,
311 },
312 buf,
313 )?;
314 Ok(len)
315 });
316 let mut slice_buf = [0u8; 8];
317 let mut callback_buf = [0u8; 8];
318 let range = Q42ByteRange {
319 offset: 0,
320 length: 8,
321 };
322 assert_zero_alloc("q42_opfs_slice_range_read", || {
323 slice.read_range_into(range, &mut slice_buf).unwrap();
324 });
325 assert_zero_alloc("q42_opfs_callback_range_read", || {
326 callback
327 .read_range_into(range, &mut callback_buf)
328 .unwrap();
329 });
330 assert_eq!(slice_buf, callback_buf);
331 }
332}