puzzlefs_lib/
compression.rs1use std::io;
2use std::io::Seek;
3
4mod noop;
5pub use noop::Noop;
6
7mod zstd_seekable_wrapper;
8pub use zstd_seekable_wrapper::*;
9
10pub trait Compressor: io::Write {
11 fn end(self: Box<Self>) -> io::Result<()>;
13}
14
15pub trait Decompressor: io::Read + io::Seek {
16 fn get_uncompressed_length(&mut self) -> io::Result<u64>;
17}
18
19pub trait Compression {
20 fn compress<'a, W: std::io::Write + 'a>(dest: W) -> io::Result<Box<dyn Compressor + 'a>>;
21 fn decompress<'a, R: std::io::Read + Seek + 'a>(
22 source: R,
23 ) -> io::Result<Box<dyn Decompressor + 'a>>;
24 fn append_extension(media_type: &str) -> String;
25}
26
27#[cfg(test)]
28mod tests {
29 use super::*;
30 use tempfile::NamedTempFile;
31
32 pub const TRUTH: &str = "meshuggah rocks";
33
34 pub fn compress_decompress<C: Compression>() -> anyhow::Result<()> {
35 let f = NamedTempFile::new()?;
36 let mut compressed = C::compress(f.reopen()?)?;
37 compressed.write_all(TRUTH.as_bytes())?;
38 compressed.end()?;
39
40 let mut buf = vec![0_u8; TRUTH.len()];
41 let n = C::decompress(f.reopen()?)?.read(&mut buf)?;
42 assert_eq!(n, TRUTH.len());
43
44 assert_eq!(TRUTH.as_bytes(), buf);
45 Ok(())
46 }
47
48 pub fn compression_is_seekable<C: Compression>() -> anyhow::Result<()> {
49 let f = NamedTempFile::new()?;
50 let mut compressed = C::compress(f.reopen()?)?;
51 compressed.write_all(TRUTH.as_bytes())?;
52 compressed.end()?;
53
54 let mut buf = vec![0_u8; 1024];
55 let mut decompressor = C::decompress(f.reopen()?)?;
56 decompressor.seek(io::SeekFrom::Start("meshuggah ".len() as u64))?;
57 let n = decompressor.read(&mut buf)?;
58 assert_eq!(n, 5);
59
60 assert_eq!("rocks".as_bytes(), &buf[0..5]);
61 Ok(())
62 }
63}