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}