Skip to content

Commit c32a9eb

Browse files
committed
WIP(decompress-plz): state machine
1 parent bb64b03 commit c32a9eb

File tree

4 files changed

+133
-32
lines changed

4 files changed

+133
-32
lines changed
Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
use brotli::Decompressor;
22
use header_plz::body_headers::{content_encoding::ContentEncoding, encoding_info::EncodingInfo};
33

4-
mod magic_bytes;
5-
use thiserror::Error;
4+
pub mod magic_bytes;
65

76
pub mod multi;
87
pub mod single;

decompression-plz/src/dstruct.rs

Lines changed: 38 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
1-
use bytes::BytesMut;
1+
use bytes::{BufMut, BytesMut};
22
use header_plz::body_headers::{content_encoding::ContentEncoding, encoding_info::EncodingInfo};
33

4+
use crate::decompression::{
5+
magic_bytes::is_compressed,
6+
multi::{decompress_multi, error::MultiDecompressError},
7+
};
8+
49
#[cfg_attr(test, derive(PartialEq))]
510
pub struct DecompressionStruct<'a> {
611
pub main: BytesMut,
@@ -23,4 +28,36 @@ impl<'a> DecompressionStruct<'a> {
2328
buf,
2429
}
2530
}
31+
32+
pub fn last_encoding(&self) -> &ContentEncoding {
33+
self.encoding_info
34+
.last()
35+
.unwrap()
36+
.encodings()
37+
.last()
38+
.unwrap()
39+
}
40+
41+
pub fn extra(&self) -> &[u8] {
42+
self.extra.as_ref().unwrap().as_ref()
43+
}
44+
45+
pub fn is_extra_compressed(&self) -> bool {
46+
let last_encoding = self.last_encoding();
47+
is_compressed(self.extra(), last_encoding)
48+
}
49+
50+
pub fn try_decompress_extra(&mut self) -> Result<BytesMut, MultiDecompressError> {
51+
let mut writer = self.buf.writer();
52+
decompress_multi(
53+
self.extra.as_ref().unwrap().as_ref(),
54+
&mut writer,
55+
&self.encoding_info,
56+
)
57+
}
58+
59+
pub fn try_decompress_main(&mut self) -> Result<BytesMut, MultiDecompressError> {
60+
let mut writer = self.buf.writer();
61+
decompress_multi(self.main.as_ref(), &mut writer, &self.encoding_info)
62+
}
2663
}

decompression-plz/src/lib.rs

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ pub mod tests {
2222
compress_zstd(&gzip_compressed)
2323
}
2424

25-
pub fn all_encoding_info() -> Vec<EncodingInfo> {
25+
pub fn all_encoding_info_multi_header() -> Vec<EncodingInfo> {
2626
vec![
2727
EncodingInfo::new(0, vec![ContentEncoding::Brotli]),
2828
EncodingInfo::new(1, vec![ContentEncoding::Deflate]),
@@ -32,6 +32,19 @@ pub mod tests {
3232
]
3333
}
3434

35+
pub fn all_encoding_info_single_header() -> Vec<EncodingInfo> {
36+
vec![EncodingInfo::new(
37+
0,
38+
vec![
39+
ContentEncoding::Brotli,
40+
ContentEncoding::Deflate,
41+
ContentEncoding::Gzip,
42+
ContentEncoding::Zstd,
43+
ContentEncoding::Identity,
44+
],
45+
)]
46+
}
47+
3548
pub fn compress_brotli(data: &[u8]) -> Vec<u8> {
3649
let mut compressed = Vec::new();
3750
{

decompression-plz/src/state.rs

Lines changed: 80 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
use crate::{
2-
decompression::multi::{decompress_multi, error::MultiDecompressError},
2+
decompression::{
3+
magic_bytes::is_compressed,
4+
multi::{decompress_multi, error::MultiDecompressError},
5+
},
36
dstruct::DecompressionStruct,
47
error::DecompressErrorStruct,
58
};
@@ -55,25 +58,33 @@ use header_plz::body_headers::{content_encoding::ContentEncoding, encoding_info:
5558
pub enum State<'a> {
5659
// Main
5760
MainOnly(DecompressionStruct<'a>),
58-
EndMainOnly(BytesMut),
61+
EndMainOnlyDecompressed(BytesMut),
5962
// Main + Extra
60-
Extra(DecompressionStruct<'a>),
61-
ExtraDecompressedMain(DecompressionStruct<'a>),
62-
MainPlusExtra(DecompressionStruct<'a>),
63+
ExtraTryDecompress(DecompressionStruct<'a>),
64+
MainPlusExtraTryDecompress(DecompressionStruct<'a>),
65+
ExtraDecompressedMainTryDecompress(DecompressionStruct<'a>, BytesMut),
66+
ExtraNoDecompressMainTryDecompress(DecompressionStruct<'a>),
6367
EndMainOnyDecompressed(DecompressionStruct<'a>),
64-
EndMainPlusExtra(DecompressionStruct<'a>),
68+
EndMainPlusExtraDecompressed(BytesMut),
69+
EndExtraMainDecompressedSeparate(BytesMut, BytesMut),
6570
}
6671

6772
impl std::fmt::Debug for State<'_> {
6873
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6974
match self {
7075
State::MainOnly(_) => write!(f, "MainOnly"),
71-
State::EndMainOnly(_) => write!(f, "EndMainOnly"),
72-
State::Extra(_) => write!(f, "Extra"),
73-
State::ExtraDecompressedMain(_) => write!(f, "ExtraDecompressedMain"),
74-
State::MainPlusExtra(_) => write!(f, "MainPlusExtra"),
76+
State::EndMainOnlyDecompressed(_) => write!(f, "EndMainOnly"),
77+
State::ExtraTryDecompress(_) => write!(f, "Extra"),
78+
State::ExtraDecompressedMainTryDecompress(..) => {
79+
write!(f, "ExtraDecompressedMainTryDecompress")
80+
}
81+
State::ExtraNoDecompressMainTryDecompress(_) => write!(f, "MainPlusExtra"),
7582
State::EndMainOnyDecompressed(_) => write!(f, "EndMainOnyDecompressed"),
76-
State::EndMainPlusExtra(_) => write!(f, "EndMainPlusExtra"),
83+
State::EndMainPlusExtraDecompressed(_) => write!(f, "EndMainPlusExtra"),
84+
State::MainPlusExtraTryDecompress(_) => write!(f, "ExtraPlainMainTryDecompress"),
85+
State::EndExtraMainDecompressedSeparate(..) => {
86+
write!(f, "EndExtraMainDecompressedSeparate")
87+
}
7788
}
7889
}
7990
}
@@ -87,33 +98,47 @@ impl<'a> State<'a> {
8798
) -> Self {
8899
let dstruct = DecompressionStruct::new(main, extra, encodings, buf);
89100
if dstruct.extra.is_some() {
90-
Self::Extra(dstruct)
101+
Self::ExtraTryDecompress(dstruct)
91102
} else {
92103
Self::MainOnly(dstruct)
93104
}
94105
}
95106

96107
fn try_next(self) -> Result<Self, MultiDecompressError> {
97108
match self {
98-
// Main only
99-
State::MainOnly(dstruct) => {
100-
let mut writer = dstruct.buf.writer();
101-
let result = decompress_multi(&dstruct.main, &mut writer, &dstruct.encoding_info)?;
102-
Ok(State::EndMainOnly(result))
109+
State::MainOnly(mut dstruct) => {
110+
let result = dstruct.try_decompress_main()?;
111+
Ok(State::EndMainOnlyDecompressed(result))
103112
}
104-
State::EndMainOnly(_) | State::EndMainPlusExtra(_) => {
105-
panic!("already ended")
113+
State::ExtraTryDecompress(mut dstruct) => match dstruct.is_extra_compressed() {
114+
true => match dstruct.try_decompress_extra() {
115+
Ok(extra_decompressed) => Ok(State::ExtraDecompressedMainTryDecompress(
116+
dstruct,
117+
extra_decompressed,
118+
)),
119+
Err(_) => Ok(State::ExtraNoDecompressMainTryDecompress(dstruct)),
120+
},
121+
false => Ok(State::MainPlusExtraTryDecompress(dstruct)),
122+
},
123+
State::ExtraDecompressedMainTryDecompress(mut dstruct, extra) => {
124+
let result = dstruct.try_decompress_main()?;
125+
Ok(State::EndMainPlusExtraDecompressed(result))
106126
}
107-
//
108-
State::Extra(decompression_struct) => todo!(),
109-
State::ExtraDecompressedMain(decompression_struct) => todo!(),
110-
State::MainPlusExtra(decompression_struct) => todo!(),
127+
State::ExtraNoDecompressMainTryDecompress(decompression_struct) => todo!(),
128+
State::MainPlusExtraTryDecompress(decompression_struct) => todo!(),
111129
State::EndMainOnyDecompressed(decompression_struct) => todo!(),
130+
State::EndMainOnlyDecompressed(_)
131+
| State::EndMainPlusExtraDecompressed(_)
132+
| State::EndExtraMainDecompressedSeparate(..) => {
133+
panic!("already ended")
134+
}
112135
}
113136
}
114137

115138
fn ended(&self) -> bool {
116-
matches!(self, Self::EndMainOnly(_)) || matches!(self, Self::EndMainOnyDecompressed(_))
139+
matches!(self, Self::EndMainOnlyDecompressed(_))
140+
|| matches!(self, Self::EndExtraMainDecompressedSeparate(..))
141+
|| matches!(self, Self::EndMainPlusExtraDecompressed(_))
117142
}
118143
}
119144

@@ -133,14 +158,41 @@ mod tests {
133158

134159
use crate::tests::*;
135160

136-
#[test]
137-
fn test_state_main_only_single() {
161+
fn test_all_compression(einfo: Vec<EncodingInfo>) {
138162
let compressed = all_compressed_data();
139163
let input = BytesMut::from(&compressed[..]);
140-
let einfo = all_encoding_info();
141164
let mut buf = BytesMut::new();
142165
let state = State::start(input, None, &einfo, &mut buf);
143166
let result = runner(state).unwrap();
144-
assert_eq!(result, State::EndMainOnly("hello world".into()));
167+
assert_eq!(result, State::EndMainOnlyDecompressed("hello world".into()));
168+
}
169+
170+
// ----- Main
171+
#[test]
172+
fn test_state_main_only_single_header() {
173+
let einfo = all_encoding_info_single_header();
174+
test_all_compression(einfo);
175+
}
176+
177+
#[test]
178+
fn test_state_main_only_multi_header() {
179+
let einfo = all_encoding_info_multi_header();
180+
test_all_compression(einfo);
181+
}
182+
183+
// ----- Main + Extra
184+
#[test]
185+
fn test_state_main_extra_compressed_together_single_header() {
186+
let einfo = all_encoding_info_single_header();
187+
let compressed = all_compressed_data();
188+
let main = BytesMut::from(&compressed[..compressed.len() / 2]);
189+
let extra = BytesMut::from(&compressed[compressed.len() / 2..]);
190+
let mut buf = BytesMut::new();
191+
let state = State::start(main, Some(extra), &einfo, &mut buf);
192+
let result = runner(state).unwrap();
193+
assert_eq!(
194+
result,
195+
State::EndMainPlusExtraDecompressed("hello world".into())
196+
);
145197
}
146198
}

0 commit comments

Comments
 (0)