Skip to main content

async_zip/spec/
compression.rs

1// Copyright (c) 2021 Harry [Majored] [hello@majored.pw]
2// MIT License (https://github.com/Majored/rs-async-zip/blob/main/LICENSE)
3
4use crate::error::{Result, ZipError};
5
6#[cfg(any(feature = "deflate", feature = "bzip2", feature = "zstd", feature = "lzma", feature = "xz"))]
7use async_compression::Level;
8
9/// A compression method supported by this crate.
10#[non_exhaustive]
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum Compression {
13    Stored,
14    #[cfg(feature = "deflate")]
15    Deflate,
16    #[cfg(feature = "deflate64")]
17    Deflate64,
18    #[cfg(feature = "bzip2")]
19    Bz,
20    #[cfg(feature = "lzma")]
21    Lzma,
22    #[cfg(feature = "zstd")]
23    Zstd,
24    #[cfg(feature = "xz")]
25    Xz,
26}
27
28impl TryFrom<u16> for Compression {
29    type Error = ZipError;
30
31    // Convert a u16 stored with little endianness into a supported compression method.
32    // https://github.com/Majored/rs-async-zip/blob/main/SPECIFICATION.md#445
33    fn try_from(value: u16) -> Result<Self> {
34        match value {
35            0 => Ok(Compression::Stored),
36            #[cfg(feature = "deflate")]
37            8 => Ok(Compression::Deflate),
38            #[cfg(feature = "deflate64")]
39            9 => Ok(Compression::Deflate64),
40            #[cfg(feature = "bzip2")]
41            12 => Ok(Compression::Bz),
42            #[cfg(feature = "lzma")]
43            14 => Ok(Compression::Lzma),
44            #[cfg(feature = "zstd")]
45            93 => Ok(Compression::Zstd),
46            #[cfg(feature = "xz")]
47            95 => Ok(Compression::Xz),
48            _ => Err(ZipError::CompressionNotSupported(value)),
49        }
50    }
51}
52
53impl From<&Compression> for u16 {
54    // Convert a supported compression method into its relevant u16 stored with little endianness.
55    // https://github.com/Majored/rs-async-zip/blob/main/SPECIFICATION.md#445
56    fn from(compression: &Compression) -> u16 {
57        match compression {
58            Compression::Stored => 0,
59            #[cfg(feature = "deflate")]
60            Compression::Deflate => 8,
61            #[cfg(feature = "deflate64")]
62            Compression::Deflate64 => 9,
63            #[cfg(feature = "bzip2")]
64            Compression::Bz => 12,
65            #[cfg(feature = "lzma")]
66            Compression::Lzma => 14,
67            #[cfg(feature = "zstd")]
68            Compression::Zstd => 93,
69            #[cfg(feature = "xz")]
70            Compression::Xz => 95,
71        }
72    }
73}
74
75impl From<Compression> for u16 {
76    fn from(compression: Compression) -> u16 {
77        (&compression).into()
78    }
79}
80
81/// Level of compression data should be compressed with for deflate.
82#[derive(Debug, Clone, Copy)]
83pub enum DeflateOption {
84    // Normal (-en) compression option was used.
85    Normal,
86
87    // Maximum (-exx/-ex) compression option was used.
88    Maximum,
89
90    // Fast (-ef) compression option was used.
91    Fast,
92
93    // Super Fast (-es) compression option was used.
94    Super,
95
96    /// Other implementation defined level.
97    Other(i32),
98}
99
100#[cfg(any(feature = "deflate", feature = "bzip2", feature = "zstd", feature = "lzma", feature = "xz"))]
101impl DeflateOption {
102    pub(crate) fn into_level(self) -> Level {
103        // FIXME: There's no clear documentation on what these specific levels defined in the ZIP specification relate
104        // to. We want to be compatible with any other library, and not specific to `async_compression`'s levels.
105        if let Self::Other(l) = self {
106            Level::Precise(l)
107        } else {
108            Level::Default
109        }
110    }
111}