1use std::{iter::FusedIterator, ops::Range};
2
3use crate::{
4 Compression, Config, Error, FORMAT_VERSION, Framing, Lengths, METADATA_SCHEMA_VERSION, Result,
5};
6
7#[derive(Clone, Copy, Debug, Eq, PartialEq)]
9pub struct FrameSizes {
10 pub(crate) raw: u64,
11 pub(crate) payload: u64,
12}
13
14impl FrameSizes {
15 pub fn new(raw: u64, payload: u64) -> Result<Self> {
17 if raw == 0 || payload == 0 || payload > raw {
18 return Err(Error::InvalidMetadata);
19 }
20 Ok(Self { raw, payload })
21 }
22 pub const fn raw_len(self) -> u64 {
24 self.raw
25 }
26 pub const fn payload_len(self) -> u64 {
28 self.payload
29 }
30}
31
32#[derive(Clone, Debug, Eq, PartialEq)]
34pub struct FrameSpec {
35 pub(crate) config: Config,
36 pub(crate) index: u64,
37 pub(crate) sizes: FrameSizes,
38}
39
40impl FrameSpec {
41 pub const fn index(&self) -> u64 {
43 self.index
44 }
45 pub fn raw_len(&self) -> usize {
47 self.sizes.raw as usize
48 }
49 pub fn stored_len(&self) -> usize {
51 (self.sizes.payload as usize).saturating_add(self.config.encryption().tag_len())
52 }
53 pub fn payload_len(&self) -> usize {
55 self.sizes.payload as usize
56 }
57}
58
59#[derive(Clone, Debug, Eq, PartialEq)]
61pub struct FrameRead {
62 pub spec: FrameSpec,
64 pub selected: Range<usize>,
66}
67
68#[derive(Clone, Debug, Eq, PartialEq)]
71#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
72pub struct MetadataParts {
73 #[cfg_attr(
75 feature = "serde",
76 serde(deserialize_with = "deserialize_schema_version")
77 )]
78 pub schema_version: u16,
79 pub version: u8,
81 pub config: Config,
83 pub frame_count: u64,
85 pub last_frame_len: Option<u64>,
87 pub raw_lengths: Option<Lengths>,
89 pub payload_lengths: Option<Lengths>,
91}
92
93#[cfg(feature = "serde")]
94fn deserialize_schema_version<'de, D>(deserializer: D) -> std::result::Result<u16, D::Error>
95where
96 D: serde::Deserializer<'de>,
97{
98 let version = <u16 as serde::Deserialize>::deserialize(deserializer)?;
99 if version != METADATA_SCHEMA_VERSION {
100 return Err(serde::de::Error::custom(Error::UnsupportedSchemaVersion));
101 }
102 Ok(version)
103}
104
105#[derive(Clone, Debug, Eq, PartialEq)]
108pub struct Metadata {
109 parts: MetadataParts,
110 logical_len: u64,
111 stored_len: u64,
112}
113
114#[cfg(feature = "serde")]
115impl serde::Serialize for Metadata {
116 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
117 where
118 S: serde::Serializer,
119 {
120 serde::Serialize::serialize(&self.parts, serializer)
121 }
122}
123
124#[cfg(feature = "serde")]
125impl<'de> serde::Deserialize<'de> for Metadata {
126 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
127 where
128 D: serde::Deserializer<'de>,
129 {
130 let parts = <MetadataParts as serde::Deserialize>::deserialize(deserializer)?;
131 Self::from_parts(parts).map_err(serde::de::Error::custom)
132 }
133}
134
135impl Metadata {
136 pub fn new(config: Config) -> Self {
138 let table = || Lengths::for_config(&config);
139 let raw_lengths = matches!(config.framing(), Framing::Variable(_)).then(table);
140 let payload_lengths = (config.compression() != Compression::None).then(table);
141 Self {
142 parts: MetadataParts {
143 schema_version: METADATA_SCHEMA_VERSION,
144 version: FORMAT_VERSION,
145 config,
146 frame_count: 0,
147 last_frame_len: None,
148 raw_lengths,
149 payload_lengths,
150 },
151 logical_len: 0,
152 stored_len: 0,
153 }
154 }
155
156 pub fn from_parts(parts: MetadataParts) -> Result<Self> {
159 if parts.schema_version != METADATA_SCHEMA_VERSION {
160 return Err(Error::UnsupportedSchemaVersion);
161 }
162 if parts.version != FORMAT_VERSION {
163 return Err(Error::UnsupportedVersion);
164 }
165 let config = parts.config.clone();
166 let count = parts.frame_count;
167 if count > config.max_frames() {
168 return Err(Error::UsageLimit);
169 }
170 let width = Lengths::new(config.max_frame_len())?.width();
171 let check_table = |table: &Option<Lengths>, required: bool| -> Result<()> {
172 match (table, required) {
173 (None, false) => Ok(()),
174 (Some(table), true) if table.len() as u64 == count && table.width() == width => {
175 Ok(())
176 }
177 _ => Err(Error::InvalidMetadata),
178 }
179 };
180 check_table(
181 &parts.raw_lengths,
182 matches!(config.framing(), Framing::Variable(_)),
183 )?;
184 check_table(
185 &parts.payload_lengths,
186 config.compression() != Compression::None,
187 )?;
188 match (config.framing(), count, parts.last_frame_len) {
189 (Framing::Fixed(max), 1.., Some(last)) if last > 0 && last <= max => {}
190 (Framing::Fixed(_), 0, None) | (Framing::Variable(_), _, None) => {}
191 _ => return Err(Error::InvalidMetadata),
192 }
193 let mut result = Self {
194 parts,
195 logical_len: 0,
196 stored_len: 0,
197 };
198 if let Framing::Fixed(size) = config.framing() {
199 if config.compression() == Compression::None {
200 let logical = if count == 0 {
201 0
202 } else {
203 let last = result.parts.last_frame_len.ok_or(Error::InvalidMetadata)?;
204 count
205 .checked_sub(1)
206 .ok_or(Error::InvalidMetadata)?
207 .checked_mul(size)
208 .and_then(|n| n.checked_add(last))
209 .ok_or(Error::Overflow)?
210 };
211 result.logical_len = logical;
212 result.stored_len = count
213 .checked_mul(config.encryption().tag_len() as u64)
214 .and_then(|tags| logical.checked_add(tags))
215 .ok_or(Error::Overflow)?;
216 return Ok(result);
217 }
218 }
219 for i in 0..count {
220 let table_index = usize::try_from(i).map_err(|_| Error::InvalidMetadata)?;
221 let raw = match config.framing() {
222 Framing::Fixed(size) if i.checked_add(1).is_some_and(|next| next < count) => size,
223 Framing::Fixed(_) => result.parts.last_frame_len.ok_or(Error::InvalidMetadata)?,
224 Framing::Variable(_) => result
225 .parts
226 .raw_lengths
227 .as_ref()
228 .ok_or(Error::InvalidMetadata)?
229 .get(table_index)
230 .ok_or(Error::InvalidMetadata)?,
231 };
232 let payload = match &result.parts.payload_lengths {
233 Some(table) => table.get(table_index).ok_or(Error::InvalidMetadata)?,
234 None => raw,
235 };
236 config.validate_frame(i, raw, payload)?;
237 result.logical_len = result.logical_len.checked_add(raw).ok_or(Error::Overflow)?;
238 result.stored_len = result
239 .stored_len
240 .checked_add(payload)
241 .and_then(|n| n.checked_add(config.encryption().tag_len() as u64))
242 .ok_or(Error::Overflow)?;
243 }
244 Ok(result)
245 }
246
247 pub fn parts(&self) -> &MetadataParts {
249 &self.parts
250 }
251 pub fn into_parts(self) -> MetadataParts {
253 self.parts
254 }
255 pub fn config(&self) -> &Config {
257 &self.parts.config
258 }
259 pub fn frame_count(&self) -> u64 {
261 self.parts.frame_count
262 }
263 pub fn logical_len(&self) -> u64 {
265 self.logical_len
266 }
267 pub fn stored_len(&self) -> u64 {
269 self.stored_len
270 }
271 pub fn last_frame_len(&self) -> Option<u64> {
273 self.frame_count()
274 .checked_sub(1)
275 .and_then(|index| self.sizes(index))
276 .map(|sizes| sizes.raw)
277 }
278
279 pub fn push(&mut self, sizes: FrameSizes) -> Result<()> {
282 let config = self.config().clone();
283 config.validate_frame(self.frame_count(), sizes.raw, sizes.payload)?;
284 if let Framing::Fixed(size) = config.framing() {
285 if self.parts.last_frame_len.is_some_and(|last| last != size) {
286 return Err(Error::FrameAfterFinal);
287 }
288 }
289 let count = self.frame_count().checked_add(1).ok_or(Error::Overflow)?;
290 let logical = self
291 .logical_len
292 .checked_add(sizes.raw)
293 .ok_or(Error::Overflow)?;
294 let stored = self
295 .stored_len
296 .checked_add(sizes.payload)
297 .and_then(|n| n.checked_add(config.encryption().tag_len() as u64))
298 .ok_or(Error::Overflow)?;
299 if let Some(table) = &mut self.parts.raw_lengths {
301 table.reserve_one()?;
302 }
303 if let Some(table) = &mut self.parts.payload_lengths {
304 table.reserve_one()?;
305 }
306 if let Some(table) = &mut self.parts.raw_lengths {
307 table.push(sizes.raw)?;
308 }
309 if let Some(table) = &mut self.parts.payload_lengths {
310 table.push(sizes.payload)?;
311 }
312 if matches!(config.framing(), Framing::Fixed(_)) {
313 self.parts.last_frame_len = Some(sizes.raw);
314 }
315 self.parts.frame_count = count;
316 self.logical_len = logical;
317 self.stored_len = stored;
318 Ok(())
319 }
320
321 pub fn frame(&self, index: u64) -> Option<FrameSpec> {
323 if index >= self.frame_count() {
324 return None;
325 }
326 Some(FrameSpec {
327 config: self.config().clone(),
328 index,
329 sizes: self.sizes(index)?,
330 })
331 }
332
333 fn sizes(&self, index: u64) -> Option<FrameSizes> {
334 let table_index = usize::try_from(index).ok()?;
335 let raw = match self.config().framing() {
336 Framing::Fixed(size)
337 if index
338 .checked_add(1)
339 .is_some_and(|next| next < self.frame_count()) =>
340 {
341 size
342 }
343 Framing::Fixed(_) => self.parts.last_frame_len?,
344 Framing::Variable(_) => self
345 .parts
346 .raw_lengths
347 .as_ref()
348 .and_then(|table| table.get(table_index))?,
349 };
350 let payload = match &self.parts.payload_lengths {
351 Some(table) => table.get(table_index)?,
352 None => raw,
353 };
354 Some(FrameSizes { raw, payload })
355 }
356
357 pub fn range(&self, start: u64, end: Option<u64>) -> Result<(Range<u64>, FrameIter<'_>)> {
362 let end = end.unwrap_or(self.logical_len);
363 if start > end || end > self.logical_len {
364 return Err(Error::InvalidRange);
365 }
366 let iter = |first, stop, logical| FrameIter {
367 metadata: self,
368 next: first,
369 stop,
370 logical,
371 selection: start..end,
372 };
373 if start == end {
374 return Ok((0..0, iter(0, 0, 0)));
375 }
376 if let Framing::Fixed(size) = self.config().framing() {
377 let first = start.checked_div(size).ok_or(Error::InvalidMetadata)?;
378 let last = end.checked_sub(1).ok_or(Error::InvalidRange)?;
379 let last_frame = last.checked_div(size).ok_or(Error::InvalidMetadata)?;
380 let stop = last_frame.checked_add(1).ok_or(Error::Overflow)?;
381 if self.config().compression() == Compression::None {
382 let stride = size
383 .checked_add(self.config().encryption().tag_len() as u64)
384 .ok_or(Error::Overflow)?;
385 let physical_start = first.checked_mul(stride).ok_or(Error::Overflow)?;
386 let physical_end = if stop == self.frame_count() {
387 self.stored_len
388 } else {
389 stop.checked_mul(stride).ok_or(Error::Overflow)?
390 };
391 let logical_start = first.checked_mul(size).ok_or(Error::Overflow)?;
392 return Ok((
393 physical_start..physical_end,
394 iter(first, stop, logical_start),
395 ));
396 }
397 let mut physical: u64 = 0;
398 for i in 0..first {
399 let sizes = self.sizes(i).ok_or(Error::InvalidMetadata)?;
400 physical = physical
401 .checked_add(sizes.payload)
402 .and_then(|value| {
403 value.checked_add(self.config().encryption().tag_len() as u64)
404 })
405 .ok_or(Error::Overflow)?;
406 }
407 let physical_start = physical;
408 if stop == self.frame_count() {
409 physical = self.stored_len;
410 } else {
411 for i in first..stop {
412 let sizes = self.sizes(i).ok_or(Error::InvalidMetadata)?;
413 physical = physical
414 .checked_add(sizes.payload)
415 .and_then(|value| {
416 value.checked_add(self.config().encryption().tag_len() as u64)
417 })
418 .ok_or(Error::Overflow)?;
419 }
420 }
421 let logical_start = first.checked_mul(size).ok_or(Error::Overflow)?;
422 return Ok((physical_start..physical, iter(first, stop, logical_start)));
423 }
424 let mut logical: u64 = 0;
425 let mut physical: u64 = 0;
426 let mut first = 0;
427 loop {
428 let sizes = self.sizes(first).ok_or(Error::InvalidMetadata)?;
429 let next_logical = logical.checked_add(sizes.raw).ok_or(Error::Overflow)?;
430 if next_logical > start {
431 break;
432 }
433 logical = next_logical;
434 physical = physical
435 .checked_add(sizes.payload)
436 .and_then(|value| value.checked_add(self.config().encryption().tag_len() as u64))
437 .ok_or(Error::Overflow)?;
438 first = first.checked_add(1).ok_or(Error::Overflow)?;
439 }
440 let logical_start = logical;
441 let physical_start = physical;
442 let mut stop = first;
443 if end == self.logical_len {
444 stop = self.frame_count();
445 physical = self.stored_len;
446 } else {
447 while logical < end {
448 let sizes = self.sizes(stop).ok_or(Error::InvalidMetadata)?;
449 logical = logical.checked_add(sizes.raw).ok_or(Error::Overflow)?;
450 physical = physical
451 .checked_add(sizes.payload)
452 .and_then(|value| {
453 value.checked_add(self.config().encryption().tag_len() as u64)
454 })
455 .ok_or(Error::Overflow)?;
456 stop = stop.checked_add(1).ok_or(Error::Overflow)?;
457 }
458 }
459 Ok((physical_start..physical, iter(first, stop, logical_start)))
460 }
461}
462
463#[derive(Clone, Debug)]
465pub struct FrameIter<'a> {
466 metadata: &'a Metadata,
467 next: u64,
468 stop: u64,
469 logical: u64,
470 selection: Range<u64>,
471}
472
473impl FrameIter<'_> {
474 pub fn remaining(&self) -> u64 {
476 self.stop.saturating_sub(self.next)
477 }
478}
479
480impl Iterator for FrameIter<'_> {
481 type Item = FrameRead;
482
483 fn next(&mut self) -> Option<Self::Item> {
484 if self.next == self.stop {
485 return None;
486 }
487 let spec = self.metadata.frame(self.next)?;
488 let logical_end = self.logical.checked_add(spec.sizes.raw)?;
489 let selected_end = self
490 .selection
491 .end
492 .min(logical_end)
493 .checked_sub(self.logical)?;
494 let selected =
495 (self.selection.start.saturating_sub(self.logical) as usize)..(selected_end as usize);
496 self.logical = logical_end;
497 self.next = self.next.checked_add(1)?;
498 Some(FrameRead { spec, selected })
499 }
500
501 fn size_hint(&self) -> (usize, Option<usize>) {
502 match usize::try_from(self.remaining()) {
503 Ok(n) => (n, Some(n)),
504 Err(_) => (usize::MAX, None),
505 }
506 }
507}
508
509impl FusedIterator for FrameIter<'_> {}