aws_smithy_compression/
lib.rs1#![cfg_attr(docsrs, feature(doc_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(
116 format!("compression level `{level}` is invalid, valid values are 0..=9").into(),
117 );
118 };
119 Ok(())
120 }
121
122 fn validate_min_compression_size_bytes(
123 min_compression_size_bytes: u32,
124 ) -> Result<(), BoxError> {
125 if min_compression_size_bytes > MAX_MIN_COMPRESSION_SIZE_BYTES {
126 return Err(format!(
127 "min compression size `{min_compression_size_bytes}` is invalid, valid values are 0..=10_485_760"
128 )
129 .into());
130 };
131 Ok(())
132 }
133}
134
135impl Storable for CompressionOptions {
136 type Storer = StoreReplace<Self>;
137}
138
139#[derive(Debug, Copy, Clone, PartialEq, Eq)]
141#[non_exhaustive]
142pub enum CompressionAlgorithm {
143 Gzip,
145}
146
147impl FromStr for CompressionAlgorithm {
148 type Err = BoxError;
149
150 fn from_str(compression_algorithm: &str) -> Result<Self, Self::Err> {
157 if compression_algorithm.eq_ignore_ascii_case(GZIP_NAME) {
158 Ok(Self::Gzip)
159 } else {
160 Err(format!("unknown compression algorithm `{compression_algorithm}`").into())
161 }
162 }
163}
164
165impl CompressionAlgorithm {
166 #[cfg(feature = "http-body-0-4-x")]
167 pub fn into_impl_http_body_0_4_x(
169 self,
170 options: &CompressionOptions,
171 ) -> Box<dyn http::http_body_0_4_x::CompressRequest> {
172 match self {
173 Self::Gzip => Box::new(gzip::Gzip::from(options)),
174 }
175 }
176
177 #[cfg(feature = "http-body-1-x")]
178 pub fn into_impl_http_body_1_x(
180 self,
181 options: &CompressionOptions,
182 ) -> Box<dyn http::http_body_1_x::CompressRequest> {
183 match self {
184 Self::Gzip => Box::new(gzip::Gzip::from(options)),
185 }
186 }
187
188 pub fn as_str(&self) -> &'static str {
190 match self {
191 Self::Gzip { .. } => GZIP_NAME,
192 }
193 }
194}
195
196#[cfg(test)]
197mod tests {
198 use crate::CompressionAlgorithm;
199 use pretty_assertions::assert_eq;
200
201 #[test]
202 fn test_compression_algorithm_from_str_unknown() {
203 let error = "some unknown compression algorithm"
204 .parse::<CompressionAlgorithm>()
205 .expect_err("it should error");
206 assert_eq!(
207 "unknown compression algorithm `some unknown compression algorithm`",
208 error.to_string()
209 );
210 }
211
212 #[test]
213 fn test_compression_algorithm_from_str_gzip() {
214 let algo = "gzip".parse::<CompressionAlgorithm>().unwrap();
215 assert_eq!("gzip", algo.as_str());
216 }
217}