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).saturating_add(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)]
69#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
70pub struct MetadataParts {
71 pub version: u8,
73 pub config: Config,
75 pub frame_count: u64,
77 pub last_frame_len: Option<u64>,
79 pub raw_lengths: Option<Lengths>,
81 pub payload_lengths: Option<Lengths>,
83}
84
85#[derive(Clone, Debug, Eq, PartialEq)]
88pub struct Metadata {
89 parts: MetadataParts,
90 logical_len: u64,
91 stored_len: u64,
92}
93
94#[cfg(feature = "serde")]
95impl serde::Serialize for Metadata {
96 fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
97 where
98 S: serde::Serializer,
99 {
100 serde::Serialize::serialize(&self.parts, serializer)
101 }
102}
103
104#[cfg(feature = "serde")]
105impl<'de> serde::Deserialize<'de> for Metadata {
106 fn deserialize<D>(deserializer: D) -> std::result::Result<Self, D::Error>
107 where
108 D: serde::Deserializer<'de>,
109 {
110 let parts = <MetadataParts as serde::Deserialize>::deserialize(deserializer)?;
111 Self::from_parts(parts).map_err(serde::de::Error::custom)
112 }
113}
114
115impl Metadata {
116 pub fn new(config: Config) -> Self {
118 let table = || Lengths::for_config(config);
119 Self {
120 parts: MetadataParts {
121 version: FORMAT_VERSION,
122 config,
123 frame_count: 0,
124 last_frame_len: None,
125 raw_lengths: matches!(config.framing(), Framing::Variable(_)).then(table),
126 payload_lengths: (config.compression() != Compression::None).then(table),
127 },
128 logical_len: 0,
129 stored_len: 0,
130 }
131 }
132
133 pub fn from_parts(parts: MetadataParts) -> Result<Self> {
136 if parts.version != FORMAT_VERSION {
137 return Err(Error::UnsupportedVersion);
138 }
139 let config = parts.config;
140 let count = parts.frame_count;
141 if count > config.max_frames() {
142 return Err(Error::UsageLimit);
143 }
144 let width = Lengths::new(config.max_frame_len())?.width();
145 let check_table = |table: &Option<Lengths>, required: bool| -> Result<()> {
146 match (table, required) {
147 (None, false) => Ok(()),
148 (Some(table), true) if table.len() as u64 == count && table.width() == width => {
149 Ok(())
150 }
151 _ => Err(Error::InvalidMetadata),
152 }
153 };
154 check_table(
155 &parts.raw_lengths,
156 matches!(config.framing(), Framing::Variable(_)),
157 )?;
158 check_table(
159 &parts.payload_lengths,
160 config.compression() != Compression::None,
161 )?;
162 match (config.framing(), count, parts.last_frame_len) {
163 (Framing::Fixed(max), 1.., Some(last)) if last > 0 && last <= max => {}
164 (Framing::Fixed(_), 0, None) | (Framing::Variable(_), _, None) => {}
165 _ => return Err(Error::InvalidMetadata),
166 }
167 let mut result = Self {
168 parts,
169 logical_len: 0,
170 stored_len: 0,
171 };
172 if let Framing::Fixed(size) = config.framing() {
173 if config.compression() == Compression::None {
174 let logical = if count == 0 {
175 0
176 } else {
177 let last = result.parts.last_frame_len.ok_or(Error::InvalidMetadata)?;
178 count
179 .checked_sub(1)
180 .ok_or(Error::InvalidMetadata)?
181 .checked_mul(size)
182 .and_then(|n| n.checked_add(last))
183 .ok_or(Error::Overflow)?
184 };
185 result.logical_len = logical;
186 result.stored_len = count
187 .checked_mul(config.encryption().tag_len() as u64)
188 .and_then(|tags| logical.checked_add(tags))
189 .ok_or(Error::Overflow)?;
190 return Ok(result);
191 }
192 }
193 for i in 0..count {
194 let table_index = usize::try_from(i).map_err(|_| Error::InvalidMetadata)?;
195 let raw = match config.framing() {
196 Framing::Fixed(size) if i.checked_add(1).is_some_and(|next| next < count) => size,
197 Framing::Fixed(_) => result.parts.last_frame_len.ok_or(Error::InvalidMetadata)?,
198 Framing::Variable(_) => result
199 .parts
200 .raw_lengths
201 .as_ref()
202 .ok_or(Error::InvalidMetadata)?
203 .get(table_index)
204 .ok_or(Error::InvalidMetadata)?,
205 };
206 let payload = match &result.parts.payload_lengths {
207 Some(table) => table.get(table_index).ok_or(Error::InvalidMetadata)?,
208 None => raw,
209 };
210 config.validate_frame(i, raw, payload)?;
211 result.logical_len = result.logical_len.checked_add(raw).ok_or(Error::Overflow)?;
212 result.stored_len = result
213 .stored_len
214 .checked_add(payload)
215 .and_then(|n| n.checked_add(config.encryption().tag_len() as u64))
216 .ok_or(Error::Overflow)?;
217 }
218 Ok(result)
219 }
220
221 pub fn parts(&self) -> &MetadataParts {
223 &self.parts
224 }
225 pub fn into_parts(self) -> MetadataParts {
227 self.parts
228 }
229 pub fn config(&self) -> Config {
231 self.parts.config
232 }
233 pub fn frame_count(&self) -> u64 {
235 self.parts.frame_count
236 }
237 pub fn logical_len(&self) -> u64 {
239 self.logical_len
240 }
241 pub fn stored_len(&self) -> u64 {
243 self.stored_len
244 }
245 pub fn last_frame_len(&self) -> Option<u64> {
247 self.frame_count()
248 .checked_sub(1)
249 .and_then(|index| self.sizes(index))
250 .map(|sizes| sizes.raw)
251 }
252
253 pub fn push(&mut self, sizes: FrameSizes) -> Result<()> {
256 let config = self.config();
257 config.validate_frame(self.frame_count(), sizes.raw, sizes.payload)?;
258 if let Framing::Fixed(size) = config.framing() {
259 if self.parts.last_frame_len.is_some_and(|last| last != size) {
260 return Err(Error::FrameAfterFinal);
261 }
262 }
263 let count = self.frame_count().checked_add(1).ok_or(Error::Overflow)?;
264 let logical = self
265 .logical_len
266 .checked_add(sizes.raw)
267 .ok_or(Error::Overflow)?;
268 let stored = self
269 .stored_len
270 .checked_add(sizes.payload)
271 .and_then(|n| n.checked_add(config.encryption().tag_len() as u64))
272 .ok_or(Error::Overflow)?;
273 if let Some(table) = &mut self.parts.raw_lengths {
275 table.reserve_one()?;
276 }
277 if let Some(table) = &mut self.parts.payload_lengths {
278 table.reserve_one()?;
279 }
280 if let Some(table) = &mut self.parts.raw_lengths {
281 table.push(sizes.raw)?;
282 }
283 if let Some(table) = &mut self.parts.payload_lengths {
284 table.push(sizes.payload)?;
285 }
286 if matches!(config.framing(), Framing::Fixed(_)) {
287 self.parts.last_frame_len = Some(sizes.raw);
288 }
289 self.parts.frame_count = count;
290 self.logical_len = logical;
291 self.stored_len = stored;
292 Ok(())
293 }
294
295 pub fn frame(&self, index: u64) -> Option<FrameSpec> {
297 if index >= self.frame_count() {
298 return None;
299 }
300 Some(FrameSpec {
301 config: self.config(),
302 index,
303 sizes: self.sizes(index)?,
304 })
305 }
306
307 fn sizes(&self, index: u64) -> Option<FrameSizes> {
308 let table_index = usize::try_from(index).ok()?;
309 let raw = match self.config().framing() {
310 Framing::Fixed(size)
311 if index
312 .checked_add(1)
313 .is_some_and(|next| next < self.frame_count()) =>
314 {
315 size
316 }
317 Framing::Fixed(_) => self.parts.last_frame_len?,
318 Framing::Variable(_) => self
319 .parts
320 .raw_lengths
321 .as_ref()
322 .and_then(|table| table.get(table_index))?,
323 };
324 let payload = match &self.parts.payload_lengths {
325 Some(table) => table.get(table_index)?,
326 None => raw,
327 };
328 Some(FrameSizes { raw, payload })
329 }
330
331 pub fn range(&self, start: u64, end: Option<u64>) -> Result<(Range<u64>, FrameIter<'_>)> {
336 let end = end.unwrap_or(self.logical_len);
337 if start > end || end > self.logical_len {
338 return Err(Error::InvalidRange);
339 }
340 let iter = |first, stop, logical| FrameIter {
341 metadata: self,
342 next: first,
343 stop,
344 logical,
345 selection: start..end,
346 };
347 if start == end {
348 return Ok((0..0, iter(0, 0, 0)));
349 }
350 if let Framing::Fixed(size) = self.config().framing() {
351 let first = start.checked_div(size).ok_or(Error::InvalidMetadata)?;
352 let last = end.checked_sub(1).ok_or(Error::InvalidRange)?;
353 let last_frame = last.checked_div(size).ok_or(Error::InvalidMetadata)?;
354 let stop = last_frame.checked_add(1).ok_or(Error::Overflow)?;
355 if self.config().compression() == Compression::None {
356 let stride = size
357 .checked_add(self.config().encryption().tag_len() as u64)
358 .ok_or(Error::Overflow)?;
359 let physical_start = first.checked_mul(stride).ok_or(Error::Overflow)?;
360 let physical_end = if stop == self.frame_count() {
361 self.stored_len
362 } else {
363 stop.checked_mul(stride).ok_or(Error::Overflow)?
364 };
365 let logical_start = first.checked_mul(size).ok_or(Error::Overflow)?;
366 return Ok((
367 physical_start..physical_end,
368 iter(first, stop, logical_start),
369 ));
370 }
371 let mut physical: u64 = 0;
372 for i in 0..first {
373 let sizes = self.sizes(i).ok_or(Error::InvalidMetadata)?;
374 physical = physical
375 .checked_add(sizes.payload)
376 .and_then(|value| {
377 value.checked_add(self.config().encryption().tag_len() as u64)
378 })
379 .ok_or(Error::Overflow)?;
380 }
381 let physical_start = physical;
382 if stop == self.frame_count() {
383 physical = self.stored_len;
384 } else {
385 for i in first..stop {
386 let sizes = self.sizes(i).ok_or(Error::InvalidMetadata)?;
387 physical = physical
388 .checked_add(sizes.payload)
389 .and_then(|value| {
390 value.checked_add(self.config().encryption().tag_len() as u64)
391 })
392 .ok_or(Error::Overflow)?;
393 }
394 }
395 let logical_start = first.checked_mul(size).ok_or(Error::Overflow)?;
396 return Ok((physical_start..physical, iter(first, stop, logical_start)));
397 }
398 let mut logical: u64 = 0;
399 let mut physical: u64 = 0;
400 let mut first = 0;
401 loop {
402 let sizes = self.sizes(first).ok_or(Error::InvalidMetadata)?;
403 let next_logical = logical.checked_add(sizes.raw).ok_or(Error::Overflow)?;
404 if next_logical > start {
405 break;
406 }
407 logical = next_logical;
408 physical = physical
409 .checked_add(sizes.payload)
410 .and_then(|value| value.checked_add(self.config().encryption().tag_len() as u64))
411 .ok_or(Error::Overflow)?;
412 first = first.checked_add(1).ok_or(Error::Overflow)?;
413 }
414 let logical_start = logical;
415 let physical_start = physical;
416 let mut stop = first;
417 if end == self.logical_len {
418 stop = self.frame_count();
419 physical = self.stored_len;
420 } else {
421 while logical < end {
422 let sizes = self.sizes(stop).ok_or(Error::InvalidMetadata)?;
423 logical = logical.checked_add(sizes.raw).ok_or(Error::Overflow)?;
424 physical = physical
425 .checked_add(sizes.payload)
426 .and_then(|value| {
427 value.checked_add(self.config().encryption().tag_len() as u64)
428 })
429 .ok_or(Error::Overflow)?;
430 stop = stop.checked_add(1).ok_or(Error::Overflow)?;
431 }
432 }
433 Ok((physical_start..physical, iter(first, stop, logical_start)))
434 }
435}
436
437#[derive(Clone, Debug)]
439pub struct FrameIter<'a> {
440 metadata: &'a Metadata,
441 next: u64,
442 stop: u64,
443 logical: u64,
444 selection: Range<u64>,
445}
446
447impl FrameIter<'_> {
448 pub fn remaining(&self) -> u64 {
450 self.stop.saturating_sub(self.next)
451 }
452}
453
454impl Iterator for FrameIter<'_> {
455 type Item = FrameRead;
456
457 fn next(&mut self) -> Option<Self::Item> {
458 if self.next == self.stop {
459 return None;
460 }
461 let spec = self.metadata.frame(self.next)?;
462 let logical_end = self.logical.checked_add(spec.sizes.raw)?;
463 let selected_end = self
464 .selection
465 .end
466 .min(logical_end)
467 .checked_sub(self.logical)?;
468 let selected =
469 (self.selection.start.saturating_sub(self.logical) as usize)..(selected_end as usize);
470 self.logical = logical_end;
471 self.next = self.next.checked_add(1)?;
472 Some(FrameRead { spec, selected })
473 }
474
475 fn size_hint(&self) -> (usize, Option<usize>) {
476 match usize::try_from(self.remaining()) {
477 Ok(n) => (n, Some(n)),
478 Err(_) => (usize::MAX, None),
479 }
480 }
481}
482
483impl FusedIterator for FrameIter<'_> {}