quick_file_transfer/config/
compression.rs

1use std::ops::RangeInclusive;
2
3use serde::{Deserialize, Serialize};
4use strum_macros::EnumCount;
5
6use super::util::*;
7
8pub const DEFAULT_COMPRESSION_LEVEL: u8 = 6;
9
10#[derive(Debug, Subcommand, Clone, PartialEq, EnumIter, Display, Copy)]
11pub enum Compression {
12    Bzip2(Bzip2Args),
13    Gzip(GzipArgs),
14    Lz4,
15    Xz(XzArgs),
16}
17
18impl Compression {
19    /// Returns the variant as a lowercase str e.g. "bzip2"
20    pub fn variant_as_str(&self) -> &str {
21        match self {
22            Compression::Bzip2(_) => "bzip2",
23            Compression::Gzip(_) => "gzip",
24            Compression::Lz4 => "lz4",
25            Compression::Xz(_) => "xz",
26        }
27    }
28
29    /// Returns the compression format variant as [CompressionVariant]
30    pub fn variant(&self) -> CompressionVariant {
31        match self {
32            Compression::Bzip2(_) => CompressionVariant::Bzip2,
33            Compression::Gzip(_) => CompressionVariant::Gzip,
34            Compression::Lz4 => CompressionVariant::Lz4,
35            Compression::Xz(_) => CompressionVariant::Xz,
36        }
37    }
38
39    pub fn describe_str(&self) -> String {
40        match self {
41            Compression::Lz4 => self.variant_as_str().to_string(),
42            Compression::Bzip2(args) => {
43                format!("{self} lvl. {}", args.compression_level)
44            }
45            Compression::Gzip(args) => {
46                format!("{self} lvl. {}", args.compression_level)
47            }
48            Compression::Xz(args) => {
49                format!("{self} lvl. {}", args.compression_level)
50            }
51        }
52    }
53}
54
55/// This enum exists to be able to specify a variant without specifying arguments, such as with the --omit flag
56#[derive(
57    ValueEnum,
58    Debug,
59    Subcommand,
60    Clone,
61    PartialEq,
62    EnumIter,
63    Display,
64    Copy,
65    EnumCount,
66    Serialize,
67    Deserialize,
68)]
69pub enum CompressionVariant {
70    Bzip2,
71    Gzip,
72    Lz4,
73    Xz,
74}
75
76#[derive(Debug, Args, Clone, PartialEq, Copy)]
77#[command(flatten_help = true)]
78pub struct GzipArgs {
79    /// 0-9: 0=None, 1=Fast, 9=Best
80    #[arg(value_parser = clap::value_parser!(u8).range(GzipArgs::range_i64()), default_value_t = DEFAULT_COMPRESSION_LEVEL)]
81    pub compression_level: u8,
82}
83
84#[derive(Debug, Args, Clone, PartialEq, Copy)]
85#[command(flatten_help = true)]
86pub struct Bzip2Args {
87    /// 0-9: 0=None, 1=Fast, 9=Best
88    #[arg(value_parser = clap::value_parser!(u8).range(Bzip2Args::range_i64()), default_value_t = DEFAULT_COMPRESSION_LEVEL)]
89    pub compression_level: u8,
90}
91
92#[derive(Debug, Args, Clone, PartialEq, Copy)]
93#[command(flatten_help = true)]
94pub struct XzArgs {
95    /// 0-9: 0=None, 1=Fast, 6=default, 9=Best
96    #[arg(value_parser = clap::value_parser!(u8).range(XzArgs::range_i64()), default_value_t = DEFAULT_COMPRESSION_LEVEL)]
97    pub compression_level: u8,
98}
99
100impl Default for Bzip2Args {
101    fn default() -> Self {
102        Self {
103            compression_level: DEFAULT_COMPRESSION_LEVEL,
104        }
105    }
106}
107
108impl Default for GzipArgs {
109    fn default() -> Self {
110        Self {
111            compression_level: DEFAULT_COMPRESSION_LEVEL,
112        }
113    }
114}
115
116impl Default for XzArgs {
117    fn default() -> Self {
118        Self {
119            compression_level: DEFAULT_COMPRESSION_LEVEL,
120        }
121    }
122}
123
124impl From<Compression> for CompressionVariant {
125    fn from(value: Compression) -> Self {
126        match value {
127            Compression::Bzip2(_) => CompressionVariant::Bzip2,
128            Compression::Gzip(_) => CompressionVariant::Gzip,
129            Compression::Lz4 => CompressionVariant::Lz4,
130            Compression::Xz(_) => CompressionVariant::Xz,
131        }
132    }
133}
134
135impl From<&Compression> for &CompressionVariant {
136    fn from(value: &Compression) -> Self {
137        match value {
138            Compression::Bzip2(_) => &CompressionVariant::Bzip2,
139            Compression::Gzip(_) => &CompressionVariant::Gzip,
140            Compression::Lz4 => &CompressionVariant::Lz4,
141            Compression::Xz(_) => &CompressionVariant::Xz,
142        }
143    }
144}
145
146pub trait CompressionRange {
147    const DEFAULT_COMPRESSION_LEVEL: u8 = DEFAULT_COMPRESSION_LEVEL;
148    const COMPRESSION_LEVEL_RANGE: RangeInclusive<i64> = 1..=9;
149
150    #[must_use]
151    fn new(compression_level: u8) -> Self;
152    #[must_use]
153    fn range_i64() -> RangeInclusive<i64> {
154        Self::COMPRESSION_LEVEL_RANGE
155    }
156    #[must_use]
157    fn range_u8() -> RangeInclusive<u8> {
158        RangeInclusive::new(
159            *Self::range_i64().start() as u8,
160            *Self::range_i64().end() as u8,
161        )
162    }
163
164    /// Omits the provided list of compression levels and returns a list of the rest
165    #[must_use]
166    fn range_u8_with_omit(omit: &[u8]) -> Vec<u8> {
167        Self::range_u8().filter(|l| !omit.contains(l)).collect()
168    }
169}
170
171impl CompressionRange for XzArgs {
172    fn new(compression_level: u8) -> Self {
173        Self { compression_level }
174    }
175}
176
177impl CompressionRange for Bzip2Args {
178    fn new(compression_level: u8) -> Self {
179        Self { compression_level }
180    }
181}
182
183impl CompressionRange for GzipArgs {
184    fn new(compression_level: u8) -> Self {
185        Self { compression_level }
186    }
187}