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::Input;
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 input: Input<'a, I>,
92 size_hint: usize,
93}
94
95impl<'a, I: Iterator<Item = &'a [u8]>> Plan<'a, I> {
96 pub fn try_segments(segments: I, hint: usize) -> Result<Self, Failure> {
99 Self::try_header::<false, Infallible>(segments, hint, None, &mut || Ok(()))
100 .map_err(Checked::into_work)
101 }
102
103 fn try_limit(self, limit: usize) -> Result<Self, DecodeError> {
104 if self.size_hint > limit {
105 return Err(DecodeError::SizeLimit {
106 actual: self.size_hint,
107 limit,
108 });
109 }
110 Ok(self)
111 }
112
113 fn try_header<const CHECK: bool, E>(
114 segments: I,
115 hint: usize,
116 checksum: Option<&Hasher>,
117 check: &mut impl FnMut() -> Result<(), E>,
118 ) -> Result<Self, Checked<Failure, E>> {
119 let mut input = Input::new(segments);
120 input
121 .header::<CHECK, E>(checksum, check)
122 .map_err(|error| error.map_work(|cause| Failure::new(cause, 0)))?;
123 Ok(Self {
124 input,
125 size_hint: hint,
126 })
127 }
128}
129
130#[derive(Clone, Copy, Debug, Eq, PartialEq)]
131pub struct Failure {
132 cause: Error,
133 written: usize,
134}
135
136#[derive(Clone, Copy, Debug, Eq, PartialEq)]
137pub enum DecodeError {
138 Stream(Failure),
139 SizeLimit {
140 actual: usize,
141 limit: usize,
142 },
143 Allocation {
144 requested: usize,
145 available: usize,
146 cause: resident::AllocError,
147 },
148}
149
150impl From<Failure> for DecodeError {
151 fn from(failure: Failure) -> Self {
152 Self::Stream(failure)
153 }
154}
155
156impl Failure {
157 const fn new(cause: Error, written: usize) -> Self {
158 Self { cause, written }
159 }
160
161 pub const fn error(&self) -> Error {
162 self.cause
163 }
164
165 pub const fn written(&self) -> usize {
166 self.written
167 }
168}
169
170const _: () = assert!(mem::size_of::<Count>() == 2 * mem::size_of::<usize>());
171const _: () = assert!(mem::size_of::<Error>() <= 5 * mem::size_of::<usize>());
172const _: () = assert!(mem::size_of::<Failure>() <= 6 * mem::size_of::<usize>());