aws_smithy_compression/
lib.rs1#![cfg_attr(docsrs, feature(doc_auto_cfg))]
8#![allow(clippy::derive_partial_eq_without_eq)]
10#![warn(
11 missing_docs,
12 rustdoc::missing_crate_level_docs,
13 unreachable_pub,
14 rust_2018_idioms
15)]
16
17use aws_smithy_runtime_api::box_error::BoxError;
20use aws_smithy_types::config_bag::{Storable, StoreReplace};
21use std::io::Write;
22use std::str::FromStr;
23
24pub mod body;
25mod gzip;
26pub mod http;
27
28pub const GZIP_NAME: &str = "gzip";
31
32const MAX_MIN_COMPRESSION_SIZE_BYTES: u32 = 10_485_760;
34
35pub trait Compress: Send + Sync {
41 fn compress_bytes(&mut self, bytes: &[u8], writer: &mut dyn Write) -> Result<(), BoxError>;
45}
46
47#[derive(Debug, Clone, PartialEq, Eq)]
49#[non_exhaustive]
50pub struct CompressionOptions {
51 level: u32,
53 min_compression_size_bytes: u32,
54 enabled: bool,
55}
56
57impl Default for CompressionOptions {
58 fn default() -> Self {
59 Self {
60 level: 6,
61 min_compression_size_bytes: 10240,
62 enabled: true,
63 }
64 }
65}
66
67impl CompressionOptions {
68 pub fn level(&self) -> u32 {
70 self.level
71 }
72
73 pub fn min_compression_size_bytes(&self) -> u32 {
77 self.min_compression_size_bytes
78 }
79
80 pub fn is_enabled(&self) -> bool {
82 self.enabled
83 }
84
85 pub fn with_enabled(self, enabled: bool) -> Self {
87 Self { enabled, ..self }
88 }
89
90 pub fn with_level(self, level: u32) -> Result<Self, BoxError> {
94 Self::validate_level(level)?;
95 Ok(Self { level, ..self })
96 }
97
98 pub fn with_min_compression_size_bytes(
103 self,
104 min_compression_size_bytes: u32,
105 ) -> Result<Self, BoxError> {
106 Self::validate_min_compression_size_bytes(min_compression_size_bytes)?;
107 Ok(Self {
108 min_compression_size_bytes,
109 ..self
110 })
111 }
112
113 fn validate_level(level: u32) -> Result<(), BoxError> {
114 if level > 9 {
115 return Err(format!(
116 "compression level `{}` is invalid, valid values are 0..=9",
117 level
118 )
119 .into());
120 };
121 Ok(())
122 }
123
124 fn validate_min_compression_size_bytes(
125 min_compression_size_bytes: u32,
126 ) -> Result<(), BoxError> {
127 if min_compression_size_bytes > MAX_MIN_COMPRESSION_SIZE_BYTES {
128 return Err(format!(
129 "min compression size `{}` is invalid, valid values are 0..=10_485_760",
130 min_compression_size_bytes
131 )
132 .into());
133 };
134 Ok(())
135 }
136}
137
138impl Storable for CompressionOptions {
139 type Storer = StoreReplace<Self>;
140}
141
142#[derive(Debug, Copy, Clone, PartialEq, Eq)]
144#[non_exhaustive]
145pub enum CompressionAlgorithm {
146 Gzip,
148}
149
150impl FromStr for CompressionAlgorithm {
151 type Err = BoxError;
152
153 fn from_str(compression_algorithm: &str) -> Result<Self, Self::Err> {
160 if compression_algorithm.eq_ignore_ascii_case(GZIP_NAME) {
161 Ok(Self::Gzip)
162 } else {
163 Err(format!("unknown compression algorithm `{compression_algorithm}`").into())
164 }
165 }
166}
167
168impl CompressionAlgorithm {
169 #[cfg(feature = "http-body-0-4-x")]
170 pub fn into_impl_http_body_0_4_x(
172 self,
173 options: &CompressionOptions,
174 ) -> Box<dyn http::http_body_0_4_x::CompressRequest> {
175 match self {
176 Self::Gzip => Box::new(gzip::Gzip::from(options)),
177 }
178 }
179
180 #[cfg(feature = "http-body-1-x")]
181 pub fn into_impl_http_body_1_x(
183 self,
184 options: &CompressionOptions,
185 ) -> Box<dyn http::http_body_1_x::CompressRequest> {
186 match self {
187 Self::Gzip => Box::new(gzip::Gzip::from(options)),
188 }
189 }
190
191 pub fn as_str(&self) -> &'static str {
193 match self {
194 Self::Gzip { .. } => GZIP_NAME,
195 }
196 }
197}
198
199#[cfg(test)]
200mod tests {
201 use crate::CompressionAlgorithm;
202 use pretty_assertions::assert_eq;
203
204 #[test]
205 fn test_compression_algorithm_from_str_unknown() {
206 let error = "some unknown compression algorithm"
207 .parse::<CompressionAlgorithm>()
208 .expect_err("it should error");
209 assert_eq!(
210 "unknown compression algorithm `some unknown compression algorithm`",
211 error.to_string()
212 );
213 }
214
215 #[test]
216 fn test_compression_algorithm_from_str_gzip() {
217 let algo = "gzip".parse::<CompressionAlgorithm>().unwrap();
218 assert_eq!("gzip", algo.as_str());
219 }
220}