axone_objectarium/
compress.rs1use std::io;
2
3use enum_iterator::Sequence;
4use lzma_rs;
5use schemars::JsonSchema;
6use serde::{Deserialize, Serialize};
7use snap;
8use thiserror::Error;
9
10#[derive(Serialize, Copy, Deserialize, Clone, Debug, PartialEq, Eq, JsonSchema, Sequence)]
13pub enum CompressionAlgorithm {
14 Passthrough,
16 Snappy,
18 Lzma,
20}
21
22impl CompressionAlgorithm {
23 pub fn compress(&self, data: &[u8]) -> Result<Vec<u8>, CompressionError> {
25 let compressor = match self {
26 CompressionAlgorithm::Passthrough => passthrough,
27 CompressionAlgorithm::Snappy => snappy_compress,
28 CompressionAlgorithm::Lzma => lzma_compress,
29 };
30 compressor(data)
31 }
32
33 pub fn decompress(&self, data: &[u8]) -> Result<Vec<u8>, CompressionError> {
36 let decompressor = match self {
37 CompressionAlgorithm::Passthrough => passthrough,
38 CompressionAlgorithm::Snappy => snappy_decompress,
39 CompressionAlgorithm::Lzma => lzma_decompress,
40 };
41 decompressor(data)
42 }
43}
44
45#[derive(Error, Debug, PartialEq, Eq)]
46pub enum CompressionError {
47 #[error("{0}")]
48 Error(String),
49}
50
51impl From<io::Error> for CompressionError {
52 fn from(err: io::Error) -> Self {
53 CompressionError::Error(err.to_string())
54 }
55}
56
57impl From<lzma_rs::error::Error> for CompressionError {
58 fn from(err: lzma_rs::error::Error) -> Self {
59 CompressionError::Error(err.to_string())
60 }
61}
62
63#[inline]
65#[allow(clippy::unnecessary_wraps)]
66fn passthrough(data: &[u8]) -> Result<Vec<u8>, CompressionError> {
67 Ok(data.to_vec())
68}
69
70#[inline]
72fn snappy_compress(data: &[u8]) -> Result<Vec<u8>, CompressionError> {
73 let mut reader = io::Cursor::new(data);
74 let mut writer = Vec::new();
75 {
76 let mut snappy_writer = snap::write::FrameEncoder::new(&mut writer);
77 io::copy(&mut reader, &mut snappy_writer)?;
78 }
79 Ok(writer)
80}
81
82#[inline]
84fn snappy_decompress(data: &[u8]) -> Result<Vec<u8>, CompressionError> {
85 let reader = io::Cursor::new(data);
86 let mut snappy_reader = snap::read::FrameDecoder::new(reader);
87 let mut writer = Vec::new();
88 io::copy(&mut snappy_reader, &mut writer)?;
89 Ok(writer)
90}
91
92#[inline]
94fn lzma_compress(data: &[u8]) -> Result<Vec<u8>, CompressionError> {
95 let mut reader = io::Cursor::new(data);
96 let mut writer = Vec::new();
97 lzma_rs::lzma_compress(&mut reader, &mut writer)?;
98 Ok(writer)
99}
100
101#[inline]
103fn lzma_decompress(data: &[u8]) -> Result<Vec<u8>, CompressionError> {
104 let mut reader = io::Cursor::new(data);
105 let mut writer = Vec::new();
106 lzma_rs::lzma_decompress(&mut reader, &mut writer)?;
107 Ok(writer)
108}
109
110#[cfg(test)]
111mod tests {
112 use super::*;
113
114 #[test]
115 fn test_from_io_decompress_error() {
116 let cases = vec![
117 (
118 std::io::Error::new(
119 std::io::ErrorKind::InvalidData,
120 "the expected decompressed size differs, actual 998, expected 1000",
121 ),
122 CompressionError::Error(
123 "the expected decompressed size differs, actual 998, expected 1000".to_string(),
124 ),
125 ),
126 (
127 std::io::Error::new(
128 std::io::ErrorKind::InvalidData,
129 lzma_rs::error::Error::IoError(std::io::Error::new(
130 std::io::ErrorKind::InvalidData,
131 "the expected decompressed size differs, actual 998, expected 1000",
132 )),
133 ),
134 CompressionError::Error(
135 "io error: the expected decompressed size differs, actual 998, expected 1000"
136 .to_string(),
137 ),
138 ),
139 ];
140
141 for (error, expected_error) in cases {
142 let compression_err = CompressionError::from(error);
143
144 assert_eq!(compression_err, expected_error);
145 }
146 }
147}