Skip to main content

compression/
lib.rs

1#![cfg_attr(docsrs, feature(doc_cfg))]
2#![allow(
3    clippy::doc_markdown,
4    clippy::missing_const_for_fn,
5    clippy::missing_errors_doc,
6    clippy::module_name_repetitions,
7    clippy::must_use_candidate,
8    clippy::use_self
9)]
10#![doc = include_str!("../README.md")]
11
12#[cfg(not(target_os = "macos"))]
13compile_error!("compression only supports macOS");
14
15mod error;
16mod ffi;
17mod stream;
18
19pub use error::{CompressionError, Result};
20pub use stream::{Decoder, Encoder};
21
22#[derive(Clone, Copy, Debug, Eq, PartialEq, Hash)]
23pub enum Algorithm {
24    Lz4,
25    Zlib,
26    Lzma,
27    Brotli,
28    Lzfse,
29}
30
31impl Algorithm {
32    pub const ALL: [Self; 5] = [Self::Lz4, Self::Zlib, Self::Lzma, Self::Brotli, Self::Lzfse];
33
34    fn as_ffi(self) -> ffi::compression_algorithm {
35        match self {
36            Self::Lz4 => ffi::COMPRESSION_LZ4,
37            Self::Zlib => ffi::COMPRESSION_ZLIB,
38            Self::Lzma => ffi::COMPRESSION_LZMA,
39            Self::Brotli => ffi::COMPRESSION_BROTLI,
40            Self::Lzfse => ffi::COMPRESSION_LZFSE,
41        }
42    }
43}
44
45pub fn compression_encode_scratch_buffer_size(algorithm: Algorithm) -> usize {
46    unsafe { ffi::compression_encode_scratch_buffer_size(algorithm.as_ffi()) }
47}
48
49pub fn compression_decode_scratch_buffer_size(algorithm: Algorithm) -> usize {
50    unsafe { ffi::compression_decode_scratch_buffer_size(algorithm.as_ffi()) }
51}
52
53pub fn compression_encode_buffer(
54    dst: &mut [u8],
55    src: &[u8],
56    algorithm: Algorithm,
57) -> Result<usize> {
58    let written = unsafe {
59        ffi::compression_encode_buffer(
60            dst.as_mut_ptr(),
61            dst.len(),
62            src.as_ptr(),
63            src.len(),
64            std::ptr::null_mut(),
65            algorithm.as_ffi(),
66        )
67    };
68
69    if src.is_empty() || written > 0 {
70        Ok(written)
71    } else {
72        Err(CompressionError::BufferOperationFailed {
73            operation: "compression_encode_buffer",
74            algorithm,
75            input_len: src.len(),
76            output_capacity: dst.len(),
77        })
78    }
79}
80
81pub fn compression_decode_buffer(
82    dst: &mut [u8],
83    src: &[u8],
84    algorithm: Algorithm,
85) -> Result<usize> {
86    let written = unsafe {
87        ffi::compression_decode_buffer(
88            dst.as_mut_ptr(),
89            dst.len(),
90            src.as_ptr(),
91            src.len(),
92            std::ptr::null_mut(),
93            algorithm.as_ffi(),
94        )
95    };
96
97    if src.is_empty() || written > 0 {
98        Ok(written)
99    } else {
100        Err(CompressionError::BufferOperationFailed {
101            operation: "compression_decode_buffer",
102            algorithm,
103            input_len: src.len(),
104            output_capacity: dst.len(),
105        })
106    }
107}
108
109pub fn compress(input: &[u8], algorithm: Algorithm) -> Result<Vec<u8>> {
110    let mut encoder = Encoder::new(algorithm)?;
111    let mut output = encoder.process(input)?;
112    output.extend(encoder.finish()?);
113    Ok(output)
114}
115
116pub fn decompress(input: &[u8], algorithm: Algorithm) -> Result<Vec<u8>> {
117    let mut decoder = Decoder::new(algorithm)?;
118    let mut output = decoder.process(input)?;
119    output.extend(decoder.finish()?);
120    Ok(output)
121}