1use std::{iter::FusedIterator, ops::Range};
2
3use crate::{Compression, Config, Error, FORMAT_VERSION, Framing, Lengths, Result};
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
7pub struct FrameSizes {
8 pub(crate) raw: u64,
9 pub(crate) payload: u64,
10}
11
12impl FrameSizes {
13 pub fn new(raw: u64, payload: u64) -> Result<Self> {
15 if raw == 0 || payload == 0 || payload > raw {
16 return Err(Error::InvalidMetadata);
17 }
18 Ok(Self { raw, payload })
19 }
20 pub const fn raw_len(self) -> u64 {
22 self.raw
23 }
24 pub const fn payload_len(self) -> u64 {
26 self.payload
27 }
28}
29
30#[derive(Clone, Copy, Debug, Eq, PartialEq)]
32pub struct FrameSpec {
33 pub(crate) config: Config,
34 pub(crate) index: u64,
35 pub(crate) sizes: FrameSizes,
36}
37
38impl FrameSpec {
39 pub const fn index(self) -> u64 {
41 self.index
42 }
43 pub fn raw_len(self) -> usize {
45 self.sizes.raw as usize
46 }
47 pub fn stored_len(self) -> usize {
49 self.sizes.payload as usize + self.config.encryption().tag_len()
50 }
51 pub fn payload_len(self) -> usize {
53 self.sizes.payload as usize
54 }
55}
56
57#[derive(Clone, Debug, Eq, PartialEq)]
59pub struct FrameRead {
60 pub spec: FrameSpec,
62 pub selected: Range<usize>,
64}
65
66#[derive(Clone, Debug, Eq, PartialEq)]
69pub struct MetadataParts {
70 pub version: u8,
72 pub config: Config,
74 pub frame_count: u64,
76 pub last_frame_len: Option<u64>,
78 pub raw_lengths: Option<Lengths>,
80 pub payload_lengths: Option<Lengths>,
82}
83
84#[derive(Clone, Debug, Eq, PartialEq)]
87pub struct Metadata {
88 parts: MetadataParts,
89 logical_len: u64,
90 stored_len: u64,
91}
92
93impl Metadata {
94 pub fn new(config: Config) -> Self {
96 let table = || Lengths::new(config.max_frame_len()).expect("validated maximum");
97 Self {
98 parts: MetadataParts {
99 version: FORMAT_VERSION,
100 config,
101 frame_count: 0,
102 last_frame_len: None,
103 raw_lengths: matches!(config.framing(), Framing::Variable(_)).then(table),
104 payload_lengths: (config.compression() != Compression::None).then(table),
105 },
106 logical_len: 0,
107 stored_len: 0,
108 }
109 }
110
111 pub fn from_parts(parts: MetadataParts) -> Result<Self> {
114 if parts.version != FORMAT_VERSION {
115 return Err(Error::UnsupportedVersion);
116 }
117 let config = parts.config;
118 let count = parts.frame_count;
119 if count > config.max_frames() {
120 return Err(Error::UsageLimit);
121 }
122 let width = Lengths::new(config.max_frame_len())?.width();
123 let check_table = |table: &Option<Lengths>, required: bool| -> Result<()> {
124 match (table, required) {
125 (None, false) => Ok(()),
126 (Some(table), true) if table.len() as u64 == count && table.width() == width => {
127 Ok(())
128 }
129 _ => Err(Error::InvalidMetadata),
130 }
131 };
132 check_table(
133 &parts.raw_lengths,
134 matches!(config.framing(), Framing::Variable(_)),
135 )?;
136 check_table(
137 &parts.payload_lengths,
138 config.compression() != Compression::None,
139 )?;
140 match (config.framing(), count, parts.last_frame_len) {
141 (Framing::Fixed(max), 1.., Some(last)) if last > 0 && last <= max => {}
142 (Framing::Fixed(_), 0, None) | (Framing::Variable(_), _, None) => {}
143 _ => return Err(Error::InvalidMetadata),
144 }
145 let mut result = Self {
146 parts,
147 logical_len: 0,
148 stored_len: 0,
149 };
150 if let Framing::Fixed(size) = config.framing() {
151 if config.compression() == Compression::None {
152 let logical = if count == 0 {
153 0
154 } else {
155 (count - 1)
156 .checked_mul(size)
157 .and_then(|n| n.checked_add(result.parts.last_frame_len.unwrap()))
158 .ok_or(Error::Overflow)?
159 };
160 result.logical_len = logical;
161 result.stored_len = count
162 .checked_mul(config.encryption().tag_len() as u64)
163 .and_then(|tags| logical.checked_add(tags))
164 .ok_or(Error::Overflow)?;
165 return Ok(result);
166 }
167 }
168 for i in 0..count {
169 let raw = match config.framing() {
170 Framing::Fixed(size) if i + 1 < count => size,
171 Framing::Fixed(_) => result.parts.last_frame_len.unwrap(),
172 Framing::Variable(_) => result
173 .parts
174 .raw_lengths
175 .as_ref()
176 .unwrap()
177 .get(i as usize)
178 .ok_or(Error::InvalidMetadata)?,
179 };
180 let payload = match &result.parts.payload_lengths {
181 Some(table) => table.get(i as usize).ok_or(Error::InvalidMetadata)?,
182 None => raw,
183 };
184 config.validate_frame(i, raw, payload)?;
185 result.logical_len = result.logical_len.checked_add(raw).ok_or(Error::Overflow)?;
186 result.stored_len = result
187 .stored_len
188 .checked_add(payload)
189 .and_then(|n| n.checked_add(config.encryption().tag_len() as u64))
190 .ok_or(Error::Overflow)?;
191 }
192 Ok(result)
193 }
194
195 pub fn parts(&self) -> &MetadataParts {
197 &self.parts
198 }
199 pub fn into_parts(self) -> MetadataParts {
201 self.parts
202 }
203 pub fn config(&self) -> Config {
205 self.parts.config
206 }
207 pub fn frame_count(&self) -> u64 {
209 self.parts.frame_count
210 }
211 pub fn logical_len(&self) -> u64 {
213 self.logical_len
214 }
215 pub fn stored_len(&self) -> u64 {
217 self.stored_len
218 }
219 pub fn last_frame_len(&self) -> Option<u64> {
221 self.frame_count().checked_sub(1).map(|i| self.sizes(i).raw)
222 }
223
224 pub fn push(&mut self, sizes: FrameSizes) -> Result<()> {
227 let config = self.config();
228 config.validate_frame(self.frame_count(), sizes.raw, sizes.payload)?;
229 if let Framing::Fixed(size) = config.framing() {
230 if self.parts.last_frame_len.is_some_and(|last| last != size) {
231 return Err(Error::FrameAfterFinal);
232 }
233 }
234 let count = self.frame_count().checked_add(1).ok_or(Error::Overflow)?;
235 let logical = self
236 .logical_len
237 .checked_add(sizes.raw)
238 .ok_or(Error::Overflow)?;
239 let stored = self
240 .stored_len
241 .checked_add(sizes.payload)
242 .and_then(|n| n.checked_add(config.encryption().tag_len() as u64))
243 .ok_or(Error::Overflow)?;
244 if let Some(table) = &mut self.parts.raw_lengths {
246 table.reserve_one()?;
247 }
248 if let Some(table) = &mut self.parts.payload_lengths {
249 table.reserve_one()?;
250 }
251 if let Some(table) = &mut self.parts.raw_lengths {
252 table.push(sizes.raw)?;
253 }
254 if let Some(table) = &mut self.parts.payload_lengths {
255 table.push(sizes.payload)?;
256 }
257 if matches!(config.framing(), Framing::Fixed(_)) {
258 self.parts.last_frame_len = Some(sizes.raw);
259 }
260 self.parts.frame_count = count;
261 self.logical_len = logical;
262 self.stored_len = stored;
263 Ok(())
264 }
265
266 pub fn frame(&self, index: u64) -> Option<FrameSpec> {
268 (index < self.frame_count()).then(|| FrameSpec {
269 config: self.config(),
270 index,
271 sizes: self.sizes(index),
272 })
273 }
274
275 fn sizes(&self, index: u64) -> FrameSizes {
276 let raw = match self.config().framing() {
277 Framing::Fixed(size) if index + 1 < self.frame_count() => size,
278 Framing::Fixed(_) => self.parts.last_frame_len.unwrap(),
279 Framing::Variable(_) => self
280 .parts
281 .raw_lengths
282 .as_ref()
283 .unwrap()
284 .get(index as usize)
285 .unwrap(),
286 };
287 let payload = self
288 .parts
289 .payload_lengths
290 .as_ref()
291 .map_or(raw, |v| v.get(index as usize).unwrap());
292 FrameSizes { raw, payload }
293 }
294
295 pub fn range(&self, start: u64, end: Option<u64>) -> Result<(Range<u64>, FrameIter<'_>)> {
300 let end = end.unwrap_or(self.logical_len);
301 if start > end || end > self.logical_len {
302 return Err(Error::InvalidRange);
303 }
304 let iter = |first, stop, logical| FrameIter {
305 metadata: self,
306 next: first,
307 stop,
308 logical,
309 selection: start..end,
310 };
311 if start == end {
312 return Ok((0..0, iter(0, 0, 0)));
313 }
314 if let Framing::Fixed(size) = self.config().framing() {
315 let first = start / size;
316 let stop = (end - 1) / size + 1;
317 if self.config().compression() == Compression::None {
318 let stride = size + self.config().encryption().tag_len() as u64;
319 let physical_start = first * stride;
320 let physical_end = if stop == self.frame_count() {
321 self.stored_len
322 } else {
323 stop * stride
324 };
325 return Ok((
326 physical_start..physical_end,
327 iter(first, stop, first * size),
328 ));
329 }
330 let mut physical = 0;
331 for i in 0..first {
332 physical += self.sizes(i).payload + self.config().encryption().tag_len() as u64;
333 }
334 let physical_start = physical;
335 if stop == self.frame_count() {
336 physical = self.stored_len;
337 } else {
338 for i in first..stop {
339 physical += self.sizes(i).payload + self.config().encryption().tag_len() as u64;
340 }
341 }
342 return Ok((physical_start..physical, iter(first, stop, first * size)));
343 }
344 let mut logical = 0;
345 let mut physical = 0;
346 let mut first = 0;
347 while logical + self.sizes(first).raw <= start {
348 let sizes = self.sizes(first);
349 logical += sizes.raw;
350 physical += sizes.payload + self.config().encryption().tag_len() as u64;
351 first += 1;
352 }
353 let logical_start = logical;
354 let physical_start = physical;
355 let mut stop = first;
356 if end == self.logical_len {
357 stop = self.frame_count();
358 physical = self.stored_len;
359 } else {
360 while logical < end {
361 let sizes = self.sizes(stop);
362 logical += sizes.raw;
363 physical += sizes.payload + self.config().encryption().tag_len() as u64;
364 stop += 1;
365 }
366 }
367 Ok((physical_start..physical, iter(first, stop, logical_start)))
368 }
369}
370
371#[derive(Clone, Debug)]
373pub struct FrameIter<'a> {
374 metadata: &'a Metadata,
375 next: u64,
376 stop: u64,
377 logical: u64,
378 selection: Range<u64>,
379}
380
381impl FrameIter<'_> {
382 pub fn remaining(&self) -> u64 {
384 self.stop - self.next
385 }
386}
387
388impl Iterator for FrameIter<'_> {
389 type Item = FrameRead;
390
391 fn next(&mut self) -> Option<Self::Item> {
392 if self.next == self.stop {
393 return None;
394 }
395 let spec = self.metadata.frame(self.next).unwrap();
396 let logical_end = self.logical + spec.sizes.raw;
397 let selected = (self.selection.start.saturating_sub(self.logical) as usize)
398 ..((self.selection.end.min(logical_end) - self.logical) as usize);
399 self.logical = logical_end;
400 self.next += 1;
401 Some(FrameRead { spec, selected })
402 }
403
404 fn size_hint(&self) -> (usize, Option<usize>) {
405 match usize::try_from(self.remaining()) {
406 Ok(n) => (n, Some(n)),
407 Err(_) => (usize::MAX, None),
408 }
409 }
410}
411
412impl FusedIterator for FrameIter<'_> {}