sark_http/payload/compress/inflate/
mod.rs1use std::{convert::Infallible, mem};
2
3use miniz_oxide::inflate::TINFLStatus;
4use o3::buffer::resident;
5
6use crate::payload::crc32::Hasher;
7
8mod checked;
9mod gzip;
10mod input;
11pub use checked::Checked;
12pub use gzip::Gzip;
13use input::Cursor;
14
15#[derive(Clone, Copy, Debug, Eq, PartialEq)]
16pub enum Part {
17 Header,
18 Extra,
19 Name,
20 Comment,
21 HeaderChecksum,
22 Deflate,
23 Trailer,
24}
25
26#[derive(Clone, Copy, Debug, Eq, PartialEq)]
27pub enum HeaderFault {
28 Magic { actual: [u8; 2] },
29 Method { actual: u8 },
30 Flags { actual: u8 },
31 Checksum { expected: u16, actual: u16 },
32}
33
34#[derive(Clone, Copy, Debug, Eq, PartialEq)]
35pub enum Count {
36 Exact(usize),
37 Overflow,
38}
39
40impl Count {
41 const ZERO: Self = Self::Exact(0);
42
43 fn add(self, amount: usize) -> Self {
44 match self {
45 Self::Exact(current) => match current.checked_add(amount) {
46 Some(next) => Self::Exact(next),
47 None => Self::Overflow,
48 },
49 Self::Overflow => Self::Overflow,
50 }
51 }
52}
53
54#[derive(Clone, Copy, Debug, Eq, PartialEq)]
55pub enum Error {
56 Header {
57 offset: Count,
58 cause: HeaderFault,
59 },
60 Eof {
61 part: Part,
62 offset: Count,
63 },
64 Inflate {
65 offset: Count,
66 output: usize,
67 cause: TINFLStatus,
68 },
69 Checksum {
70 expected: u32,
71 actual: u32,
72 },
73 Length {
74 expected: usize,
75 actual: usize,
76 },
77 Output {
78 capacity: usize,
79 written: usize,
80 },
81 Trailing {
82 bytes: Count,
83 },
84}
85
86pub struct Plan<'a, I>
88where
89 I: Iterator<Item = &'a [u8]>,
90{
91 segments: I,
92 input: Cursor<'a>,
93 size_hint: usize,
94}
95
96impl<'a, I: Iterator<Item = &'a [u8]>> Plan<'a, I> {
97 pub fn try_segments(segments: I, hint: usize) -> Result<Self, Failure> {
100 Self::try_header::<false, Infallible>(segments, hint, None, &mut || Ok(()))
101 .map_err(Checked::into_work)
102 }
103
104 fn try_limit(self, limit: usize) -> Result<Self, DecodeError> {
105 if self.size_hint > limit {
106 return Err(DecodeError::SizeLimit {
107 actual: self.size_hint,
108 limit,
109 });
110 }
111 Ok(self)
112 }
113
114 fn try_header<const CHECK: bool, E>(
115 mut segments: I,
116 hint: usize,
117 checksum: Option<&Hasher>,
118 check: &mut impl FnMut() -> Result<(), E>,
119 ) -> Result<Self, Checked<Failure, E>> {
120 let mut input = Cursor::new(segments.next().unwrap_or(&[]));
121 input
122 .header::<CHECK, E>(&mut segments, checksum, check)
123 .map_err(|error| error.map_work(|cause| Failure::new(cause, 0)))?;
124 Ok(Self {
125 segments,
126 input,
127 size_hint: hint,
128 })
129 }
130}
131
132#[derive(Clone, Copy, Debug, Eq, PartialEq)]
133pub struct Failure {
134 cause: Error,
135 written: usize,
136}
137
138#[derive(Clone, Copy, Debug, Eq, PartialEq)]
139pub enum DecodeError {
140 Stream(Failure),
141 SizeLimit {
142 actual: usize,
143 limit: usize,
144 },
145 Allocation {
146 requested: usize,
147 available: usize,
148 cause: resident::AllocError,
149 },
150}
151
152impl From<Failure> for DecodeError {
153 fn from(failure: Failure) -> Self {
154 Self::Stream(failure)
155 }
156}
157
158impl Failure {
159 const fn new(cause: Error, written: usize) -> Self {
160 Self { cause, written }
161 }
162
163 pub const fn error(&self) -> Error {
164 self.cause
165 }
166
167 pub const fn written(&self) -> usize {
168 self.written
169 }
170}
171
172const _: () = assert!(mem::size_of::<Count>() == 2 * mem::size_of::<usize>());
173const _: () = assert!(mem::size_of::<Error>() <= 5 * mem::size_of::<usize>());
174const _: () = assert!(mem::size_of::<Failure>() <= 6 * mem::size_of::<usize>());