lsm_tree/segment/meta/
compression.rs

1// Copyright (c) 2024-present, fjall-rs
2// This source code is licensed under both the Apache 2.0 and MIT License
3// (found in the LICENSE-* files in the repository)
4
5use crate::coding::{Decode, DecodeError, Encode, EncodeError};
6use byteorder::{ReadBytesExt, WriteBytesExt};
7use std::io::{Read, Write};
8
9/// Compression algorithm to use.
10#[derive(Copy, Clone, Debug, Eq, PartialEq)]
11#[allow(clippy::module_name_repetitions)]
12pub enum CompressionType {
13    /// No compression
14    ///
15    /// Not recommended.
16    None,
17
18    /// LZ4 compression
19    ///
20    /// Recommended for use cases with a focus
21    /// on speed over compression ratio.
22    #[cfg(feature = "lz4")]
23    Lz4,
24
25    /// zlib/DEFLATE compression
26    ///
27    /// Compression level (0-10) can be adjusted.
28    ///
29    /// - 0 disables compression
30    /// - 1 optimizes for speed
31    /// - 6 compromises between speed and space, good default
32    /// - 9 optimizes for space
33    /// - 10 may save even more space than 9, but the speed trade off may not be worth it
34    #[cfg(feature = "miniz")]
35    Miniz(u8),
36}
37
38impl Encode for CompressionType {
39    fn encode_into<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
40        match self {
41            Self::None => {
42                writer.write_u8(0)?;
43                writer.write_u8(0)?; // NOTE: Pad to 2 bytes
44            }
45
46            #[cfg(feature = "lz4")]
47            Self::Lz4 => {
48                writer.write_u8(1)?;
49                writer.write_u8(0)?; // NOTE: Pad to 2 bytes
50            }
51
52            #[cfg(feature = "miniz")]
53            Self::Miniz(level) => {
54                assert!(*level <= 10, "invalid miniz compression level");
55
56                writer.write_u8(2)?;
57                writer.write_u8(*level)?;
58            }
59        }
60
61        Ok(())
62    }
63}
64
65impl Decode for CompressionType {
66    fn decode_from<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
67        let tag = reader.read_u8()?;
68
69        match tag {
70            0 => {
71                assert_eq!(0, reader.read_u8()?, "Invalid compression");
72                Ok(Self::None)
73            }
74
75            #[cfg(feature = "lz4")]
76            1 => {
77                assert_eq!(0, reader.read_u8()?, "Invalid compression");
78                Ok(Self::Lz4)
79            }
80
81            #[cfg(feature = "miniz")]
82            2 => {
83                let level = reader.read_u8()?;
84
85                assert!(level <= 10, "invalid miniz compression level");
86
87                Ok(Self::Miniz(level))
88            }
89
90            tag => Err(DecodeError::InvalidTag(("CompressionType", tag))),
91        }
92    }
93}
94
95impl std::fmt::Display for CompressionType {
96    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
97        write!(
98            f,
99            "{}",
100            match self {
101                Self::None => "no compression",
102
103                #[cfg(feature = "lz4")]
104                Self::Lz4 => "lz4",
105
106                #[cfg(feature = "miniz")]
107                Self::Miniz(_) => "miniz",
108            }
109        )
110    }
111}
112
113#[cfg(test)]
114mod tests {
115    use super::*;
116    use test_log::test;
117
118    #[test]
119    fn compression_serialize_none() {
120        let serialized = CompressionType::None.encode_into_vec();
121        assert_eq!(2, serialized.len());
122    }
123
124    #[cfg(feature = "lz4")]
125    mod lz4 {
126        use super::*;
127        use test_log::test;
128
129        #[test]
130        fn compression_serialize_none() {
131            let serialized = CompressionType::Lz4.encode_into_vec();
132            assert_eq!(2, serialized.len());
133        }
134    }
135
136    #[cfg(feature = "miniz")]
137    mod miniz {
138        use super::*;
139        use test_log::test;
140
141        #[test]
142        fn compression_serialize_none() {
143            for lvl in 0..10 {
144                let serialized = CompressionType::Miniz(lvl).encode_into_vec();
145                assert_eq!(2, serialized.len());
146            }
147        }
148    }
149}