1use crate::Span;
4use crate::memory::{Execution, MemoryError, OwnedVec, Work};
5use crate::source::Snapshot;
6use core::future::{Future, ready};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
10pub struct Stamp<D, G> {
11 pub snapshot: Snapshot<D, G>,
13 pub length: u64,
15}
16
17#[derive(Debug)]
19pub enum ReadError<E> {
20 Resource(MemoryError),
22 Cause(E),
24}
25
26pub trait RangeSource {
33 type Document: Copy + Eq;
35 type Generation: Copy + Eq;
37 type Error;
39
40 fn stamp(&self) -> Stamp<Self::Document, Self::Generation>;
42
43 fn read_at<'q, W: Work + 'q>(
45 &'q self,
46 offset: u64,
47 output: &'q mut [u8],
48 work: &'q W,
49 ) -> impl Future<Output = Result<usize, ReadError<Self::Error>>> + 'q;
50}
51
52pub struct Slice<'a, D, G> {
54 bytes: &'a [u8],
55 stamp: Stamp<D, G>,
56}
57
58impl<'a, D, G> Slice<'a, D, G> {
59 #[must_use]
61 pub fn new(bytes: &'a [u8], snapshot: Snapshot<D, G>) -> Self {
62 Self {
63 bytes,
64 stamp: Stamp {
65 snapshot,
66 length: bytes.len() as u64,
67 },
68 }
69 }
70}
71
72impl<D: Copy + Eq, G: Copy + Eq> RangeSource for Slice<'_, D, G> {
73 type Document = D;
74 type Generation = G;
75 type Error = core::convert::Infallible;
76
77 fn stamp(&self) -> Stamp<D, G> {
78 self.stamp
79 }
80
81 fn read_at<'q, W: Work + 'q>(
82 &'q self,
83 offset: u64,
84 output: &'q mut [u8],
85 _work: &'q W,
86 ) -> impl Future<Output = Result<usize, ReadError<Self::Error>>> + 'q {
87 let count = if let Ok(offset) = usize::try_from(offset)
88 && let Some(input) = self.bytes.get(offset..)
89 {
90 let count = input.len().min(output.len());
91 output[..count].copy_from_slice(&input[..count]);
92 count
93 } else {
94 0
95 };
96 ready(Ok(count))
97 }
98}
99
100#[derive(Debug)]
102pub enum InputError<E> {
103 Resource {
105 range: Span,
107 cause: MemoryError,
109 },
110 Changed {
112 range: Span,
114 },
115 Contract {
117 range: Span,
119 },
120 Cause {
122 range: Span,
124 cause: E,
126 },
127}
128
129const WINDOW: usize = 4096;
131const ZERO_WINDOW: [u8; WINDOW] = [0; WINDOW];
132
133pub struct Window<'q, S: RangeSource> {
137 source: &'q S,
138 stamp: Stamp<S::Document, S::Generation>,
139 bounds: Span,
140 work: Execution<'q>,
141 bytes: OwnedVec<u8, Execution<'q>>,
142 start: u64,
143 filled: usize,
144 aligned: bool,
145 quantum: usize,
146}
147
148impl<'q, S: RangeSource> Window<'q, S> {
149 pub fn new(
155 source: &'q S,
156 stamp: Stamp<S::Document, S::Generation>,
157 bounds: Span,
158 work: Execution<'q>,
159 ) -> Result<Self, InputError<S::Error>> {
160 let Some(end) = bounds.start.checked_add(bounds.length) else {
161 return Err(InputError::Contract { range: bounds });
162 };
163 if end > stamp.length {
164 return Err(InputError::Contract { range: bounds });
165 }
166 Self::guard(source, stamp, &work, bounds)?;
167 let mut bytes = work.vector();
168 let size = usize::try_from(bounds.length.min(WINDOW as u64))
169 .expect("bounded window length fits usize");
170 bytes
171 .try_extend_from_slice(&ZERO_WINDOW[..size])
172 .map_err(|cause| InputError::Resource {
173 range: bounds,
174 cause,
175 })?;
176 Ok(Self {
177 source,
178 stamp,
179 bounds,
180 work,
181 bytes,
182 start: 0,
183 filled: 0,
184 aligned: true,
185 quantum: WINDOW,
186 })
187 }
188
189 #[must_use]
191 pub fn execution(&self) -> Execution<'q> {
192 self.work
193 }
194
195 #[must_use]
197 pub fn stamp(&self) -> Stamp<S::Document, S::Generation> {
198 self.stamp
199 }
200
201 #[must_use]
203 pub fn bounds(&self) -> Span {
204 self.bounds
205 }
206
207 pub fn fork(&self) -> Result<Self, InputError<S::Error>> {
210 let mut fork = Self::new(self.source, self.stamp, self.bounds, self.work)?;
211 fork.aligned = self.aligned;
212 fork.quantum = self.quantum;
213 Ok(fork)
214 }
215
216 pub fn check(&self, range: Span) -> Result<(), InputError<S::Error>> {
218 Self::guard(self.source, self.stamp, &self.work, range)
219 }
220
221 fn guard(
222 source: &S,
223 stamp: Stamp<S::Document, S::Generation>,
224 work: &Execution<'_>,
225 range: Span,
226 ) -> Result<(), InputError<S::Error>> {
227 work.charge_work(1)
228 .map_err(|cause| InputError::Resource { range, cause })?;
229 if source.stamp() != stamp {
230 return Err(InputError::Changed { range });
231 }
232 Ok(())
233 }
234
235 async fn refill(
236 &mut self,
237 start: u64,
238 length: usize,
239 complete: bool,
240 ) -> Result<(), InputError<S::Error>> {
241 self.filled = 0;
244 let mut used = 0;
245 loop {
246 let wanted = (length - used).min(self.quantum);
247 let range = Span {
248 start: start + used as u64,
249 length: wanted as u64,
250 };
251 self.check(range)?;
252 self.work
253 .charge_work(wanted as u64)
254 .map_err(|cause| InputError::Resource { range, cause })?;
255 let count = self
256 .source
257 .read_at(
258 range.start,
259 &mut self.bytes[used..used + wanted],
260 &self.work,
261 )
262 .await
263 .map_err(|error| match error {
264 ReadError::Resource(cause) => InputError::Resource { range, cause },
265 ReadError::Cause(cause) => InputError::Cause { range, cause },
266 })?;
267 self.check(range)?;
268 if count == 0 || count > wanted {
269 return Err(InputError::Contract { range });
270 }
271 if count < wanted {
272 self.quantum = count;
276 self.aligned = false;
277 }
278 used += count;
279 if !complete || used == length {
280 self.start = start;
281 self.filled = used;
282 return Ok(());
283 }
284 }
285 }
286
287 pub async fn byte_at(&mut self, offset: u64) -> Result<Option<u8>, InputError<S::Error>> {
292 let point = Span {
293 start: offset,
294 length: 0,
295 };
296 self.check(point)?;
297 if offset < self.bounds.start {
298 return Err(InputError::Contract { range: point });
299 }
300 let end = self.bounds.end();
301 if offset >= end {
302 return Ok(None);
303 }
304 if offset >= self.start && offset - self.start < self.filled as u64 {
305 let index = usize::try_from(offset - self.start).expect("cached window index");
306 return Ok(Some(self.bytes[index]));
307 }
308 loop {
309 let mut start = if self.aligned {
310 offset / WINDOW as u64 * WINDOW as u64
311 } else {
312 offset
313 };
314 if start < self.bounds.start {
315 start = self.bounds.start;
316 }
317 let wanted = usize::try_from((end - start).min(self.bytes.len() as u64))
318 .expect("bounded requested length");
319 self.refill(start, wanted, false).await?;
320 let index = usize::try_from(offset - start).expect("query is inside window");
321 if index < self.filled {
322 return Ok(Some(self.bytes[index]));
323 }
324 debug_assert!(!self.aligned);
327 }
328 }
329
330 pub async fn chunk_at(&mut self, offset: u64, end: u64) -> Result<&[u8], InputError<S::Error>> {
335 let range = Span {
336 start: offset,
337 length: 0,
338 };
339 if end > self.bounds.end() || offset < self.bounds.start || offset > end {
340 return Err(InputError::Contract { range });
341 }
342 if offset == end {
343 self.check(range)?;
344 return Ok(&[]);
345 }
346 self.byte_at(offset).await?;
347 let start = usize::try_from(offset - self.start).expect("cached offset");
348 let count = usize::try_from((end - offset).min((self.filled - start) as u64))
349 .expect("bounded chunk");
350 Ok(&self.bytes[start..start + count])
351 }
352
353 pub async fn chunk_before(
360 &mut self,
361 end: u64,
362 minimum: u64,
363 ) -> Result<&[u8], InputError<S::Error>> {
364 let point = Span {
365 start: end,
366 length: 0,
367 };
368 if minimum < self.bounds.start || end > self.bounds.end() || minimum > end {
369 return Err(InputError::Contract { range: point });
370 }
371 if end == minimum {
372 self.check(point)?;
373 return Ok(&[]);
374 }
375 self.check(point)?;
376 let last = end - 1;
377 if last < self.start || last - self.start >= self.filled as u64 {
378 let start = minimum.max(end - end.min(self.bytes.len() as u64));
379 let length = usize::try_from(end - start).expect("bounded reverse page");
380 self.refill(start, length, true).await?;
381 }
382 let start =
383 usize::try_from(minimum.max(self.start) - self.start).expect("resident reverse start");
384 let stop = usize::try_from(end - self.start).expect("resident reverse end");
385 Ok(&self.bytes[start..stop])
386 }
387}
388
389#[cfg(test)]
390mod tests;