lsm_tree/segment/meta/
compression.rs

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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// Copyright (c) 2024-present, fjall-rs
// This source code is licensed under both the Apache 2.0 and MIT License
// (found in the LICENSE-* files in the repository)

use crate::coding::{Decode, DecodeError, Encode, EncodeError};
use byteorder::{ReadBytesExt, WriteBytesExt};
use std::io::{Read, Write};

/// Compression algorithm to use.
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
#[allow(clippy::module_name_repetitions)]
pub enum CompressionType {
    /// No compression
    ///
    /// Not recommended.
    None,

    /// LZ4 compression
    ///
    /// Recommended for use cases with a focus
    /// on speed over compression ratio.
    #[cfg(feature = "lz4")]
    Lz4,

    /// zlib/DEFLATE compression
    ///
    /// Compression level (0-10) can be adjusted.
    ///
    /// - 0 disables compression
    /// - 1 optimizes for speed
    /// - 6 compromises between speed and space, good default
    /// - 9 optimizes for space
    /// - 10 may save even more space than 9, but the speed trade off may not be worth it
    #[cfg(feature = "miniz")]
    Miniz(u8),
}

impl Encode for CompressionType {
    fn encode_into<W: Write>(&self, writer: &mut W) -> Result<(), EncodeError> {
        match self {
            Self::None => {
                writer.write_u8(0)?;
                writer.write_u8(0)?; // NOTE: Pad to 2 bytes
            }

            #[cfg(feature = "lz4")]
            Self::Lz4 => {
                writer.write_u8(1)?;
                writer.write_u8(0)?; // NOTE: Pad to 2 bytes
            }

            #[cfg(feature = "miniz")]
            Self::Miniz(level) => {
                assert!(*level <= 10, "invalid miniz compression level");

                writer.write_u8(2)?;
                writer.write_u8(*level)?;
            }
        };

        Ok(())
    }
}

impl Decode for CompressionType {
    fn decode_from<R: Read>(reader: &mut R) -> Result<Self, DecodeError> {
        let tag = reader.read_u8()?;

        match tag {
            0 => {
                assert_eq!(0, reader.read_u8()?, "Invalid compression");
                Ok(Self::None)
            }

            #[cfg(feature = "lz4")]
            1 => {
                assert_eq!(0, reader.read_u8()?, "Invalid compression");
                Ok(Self::Lz4)
            }

            #[cfg(feature = "miniz")]
            2 => {
                let level = reader.read_u8()?;

                assert!(level <= 10, "invalid miniz compression level");

                Ok(Self::Miniz(level))
            }

            tag => Err(DecodeError::InvalidTag(("CompressionType", tag))),
        }
    }
}

impl std::fmt::Display for CompressionType {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(
            f,
            "{}",
            match self {
                Self::None => "no compression",

                #[cfg(feature = "lz4")]
                Self::Lz4 => "lz4",

                #[cfg(feature = "miniz")]
                Self::Miniz(_) => "miniz",
            }
        )
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test_log::test]
    fn compression_serialize_none() -> crate::Result<()> {
        let serialized = CompressionType::None.encode_into_vec()?;
        assert_eq!(2, serialized.len());
        Ok(())
    }

    #[cfg(feature = "lz4")]
    mod lz4 {
        use super::*;

        #[test_log::test]
        fn compression_serialize_none() -> crate::Result<()> {
            let serialized = CompressionType::Lz4.encode_into_vec()?;
            assert_eq!(2, serialized.len());
            Ok(())
        }
    }

    #[cfg(feature = "miniz")]
    mod miniz {
        use super::*;

        #[test_log::test]
        fn compression_serialize_none() -> crate::Result<()> {
            for lvl in 0..10 {
                let serialized = CompressionType::Miniz(lvl).encode_into_vec()?;
                assert_eq!(2, serialized.len());
            }
            Ok(())
        }
    }
}