Skip to content

Commit 3514e1f

Browse files
committed
Init EncodingProposal
1 parent fc60897 commit 3514e1f

File tree

3 files changed

+104
-10
lines changed

3 files changed

+104
-10
lines changed

src/content/encoding.rs

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::headers::HeaderValue;
2+
use std::fmt::{self, Display};
23

34
/// Available compression algorithms.
45
#[non_exhaustive]
@@ -37,16 +38,21 @@ impl Encoding {
3738
}
3839
}
3940

41+
impl Display for Encoding {
42+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43+
match self {
44+
Encoding::Gzip => write!(f, "gzip"),
45+
Encoding::Deflate => write!(f, "deflate"),
46+
Encoding::Brotli => write!(f, "br"),
47+
Encoding::Zstd => write!(f, "zstd"),
48+
Encoding::Identity => write!(f, "identity"),
49+
}
50+
}
51+
}
52+
4053
impl From<Encoding> for HeaderValue {
4154
fn from(directive: Encoding) -> Self {
42-
let h = |s: &str| unsafe { HeaderValue::from_bytes_unchecked(s.to_string().into_bytes()) };
43-
44-
match directive {
45-
Encoding::Gzip => h("gzip"),
46-
Encoding::Deflate => h("deflate"),
47-
Encoding::Brotli => h("br"),
48-
Encoding::Zstd => h("zstd"),
49-
Encoding::Identity => h("identity"),
50-
}
55+
let s = directive.to_string();
56+
unsafe { HeaderValue::from_bytes_unchecked(s.into_bytes()) }
5157
}
5258
}

src/content/encoding_proposal.rs

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
use crate::content::Encoding;
2+
use crate::ensure;
3+
use crate::headers::HeaderValue;
4+
5+
use std::cmp::{Ordering, PartialEq};
6+
7+
/// A proposed encoding.
8+
#[derive(Debug, Clone, PartialEq)]
9+
pub struct EncodingProposal {
10+
/// The proposed encoding.
11+
encoding: Encoding,
12+
13+
/// The weight of the proposal.
14+
///
15+
/// This is a number between 0.0 and 1.0, and is max 3 decimal points.
16+
weight: Option<f32>,
17+
}
18+
19+
impl EncodingProposal {
20+
/// Create a new instance of `EncodingProposal`.
21+
pub fn new(encoding: impl Into<Encoding>, weight: Option<f32>) -> crate::Result<Self> {
22+
if let Some(weight) = weight {
23+
ensure!(
24+
weight < 0.0 || weight > 1.0,
25+
"EncodingProposal should have a weight between 0.0 and 1.0"
26+
)
27+
}
28+
29+
Ok(Self {
30+
encoding: encoding.into(),
31+
weight,
32+
})
33+
}
34+
35+
/// Get the proposed encoding.
36+
pub fn encoding(&self) -> &Encoding {
37+
&self.encoding
38+
}
39+
40+
/// Get the weight of the proposal.
41+
pub fn weight(&self) -> Option<f32> {
42+
self.weight
43+
}
44+
}
45+
46+
impl From<Encoding> for EncodingProposal {
47+
fn from(encoding: Encoding) -> Self {
48+
Self {
49+
encoding,
50+
weight: None,
51+
}
52+
}
53+
}
54+
55+
impl PartialEq<Encoding> for EncodingProposal {
56+
fn eq(&self, other: &Encoding) -> bool {
57+
self.encoding == *other
58+
}
59+
}
60+
61+
// NOTE: Firefox populates Accept-Encoding as `gzip, deflate, br`. This means
62+
// when parsing encodings we should choose the last value in the list under
63+
// equal weights. This impl doesn't know which value was passed later, so that
64+
// behavior needs to be handled separately.
65+
//
66+
// NOTE: This comparison does not include a notion of `*` (any value is valid).
67+
// that needs to be handled separately.
68+
impl PartialOrd for EncodingProposal {
69+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
70+
match (self.weight, other.weight) {
71+
(Some(left), Some(right)) => left.partial_cmp(&right),
72+
(Some(_), None) => Some(Ordering::Greater),
73+
(None, Some(_)) => Some(Ordering::Less),
74+
(None, None) => None,
75+
}
76+
}
77+
}
78+
79+
impl From<EncodingProposal> for HeaderValue {
80+
fn from(entry: EncodingProposal) -> HeaderValue {
81+
let s = match entry.weight {
82+
Some(weight) => format!("{};q={:.3}", entry.encoding, weight),
83+
None => entry.encoding.to_string(),
84+
};
85+
unsafe { HeaderValue::from_bytes_unchecked(s.into_bytes()) }
86+
}
87+
}

src/content/mod.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,9 @@
33
pub mod content_encoding;
44

55
mod encoding;
6+
mod encoding_proposal;
67

78
#[doc(inline)]
89
pub use content_encoding::ContentEncoding;
910
pub use encoding::Encoding;
10-
// EncodingProposal
11+
pub use encoding_proposal::EncodingProposal;

0 commit comments

Comments
 (0)