1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
use std::ffi::OsString;
use std::fs;
use std::io::Write;
const BROTLI_QUALITY: u32 = 11;
const BROTLI_LG_WINDOW_SIZE: u32 = 20;
pub struct LazyStream {
buffer: Vec<u8>,
dump_path: Option<std::path::PathBuf>,
}
impl LazyStream {
pub fn new(dump_path: Option<std::path::PathBuf>) -> Self {
LazyStream {
dump_path,
buffer: vec![],
}
}
pub fn bytes_written(&self) -> usize {
self.buffer.len()
}
pub fn done(mut self) -> std::io::Result<Option<Vec<u8>>> {
if self.buffer.len() == 0 {
return Ok(None);
}
let mut brotli_compressed = vec![];
{
let mut brotli = brotli::CompressorWriter::new(
&mut brotli_compressed,
self.buffer.len(),
BROTLI_QUALITY,
BROTLI_LG_WINDOW_SIZE,
);
brotli.write_all(&self.buffer).unwrap();
}
if let Some(mut path) = self.dump_path.take() {
{
let dir = path.parent().unwrap();
fs::DirBuilder::new().recursive(true).create(dir)?;
}
fs::write(&path, &self.buffer)?;
let extension = match path.extension() {
None => OsString::from("bro"),
Some(ext) => {
let mut as_os_string = ext.to_os_string();
as_os_string.push(".bro");
as_os_string
}
};
path.set_extension(extension);
fs::write(path, &brotli_compressed)?;
}
Ok(Some(brotli_compressed))
}
}
impl std::io::Write for LazyStream {
fn write(&mut self, data: &[u8]) -> std::io::Result<usize> {
self.buffer.extend_from_slice(data);
Ok(data.len())
}
fn flush(&mut self) -> std::io::Result<()> {
Ok(())
}
}