Skip to content

Commit 23c78fa

Browse files
committed
making the QualityValue in AcceptEncoding public, so an AcceptEncoding header can be created from HeaderValue, moving the implementation details of QualityValue into a sealed mod
1 parent aa46020 commit 23c78fa

File tree

2 files changed

+121
-110
lines changed

2 files changed

+121
-110
lines changed

src/common/accept_encoding.rs

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use HeaderValue;
2323
/// * `br;q=1.0, gzip;q=0.8`
2424
///
2525
#[derive(Clone, Debug)]
26-
pub struct AcceptEncoding(QualityValue);
26+
pub struct AcceptEncoding(pub QualityValue);
2727

2828
derive_header! {
2929
AcceptEncoding(_),
@@ -87,12 +87,13 @@ impl AcceptEncoding {
8787
/// ```
8888
/// use headers::{AcceptEncoding, HeaderValue};
8989
///
90-
/// let pairs = vec![("gzip", 1.0), ("deflate", 0.8)];
91-
/// let accept_enc = AcceptEncoding::from_quality_pairs(&mut pairs.into_iter()).unwrap();
90+
/// let val = HeaderValue::from_static("deflate, gzip;q=1.0, br;q=0.8");
91+
/// let accept_enc = AcceptEncoding(val.into());
9292
/// let mut encodings = accept_enc.sorted_encodings();
9393
///
94-
/// assert_eq!(encodings.next(), Some("gzip"));
9594
/// assert_eq!(encodings.next(), Some("deflate"));
95+
/// assert_eq!(encodings.next(), Some("gzip"));
96+
/// assert_eq!(encodings.next(), Some("br"));
9697
/// assert_eq!(encodings.next(), None);
9798
/// ```
9899
pub fn sorted_encodings(&self) -> impl Iterator<Item = &str> {

src/util/quality_value.rs

Lines changed: 116 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,163 +1,173 @@
1-
use std::cmp::Ordering;
2-
use std::convert::{From, TryFrom};
1+
use self::sealed::SemiQ;
32
use std::marker::PhantomData;
4-
5-
use itertools::Itertools;
6-
use util::{FlatCsv, TryFromValues};
7-
use HeaderValue;
3+
use util::FlatCsv;
84

95
/// A CSV list that respects the Quality Values syntax defined in
106
/// [RFC7321](https://tools.ietf.org/html/rfc7231#section-5.3.1)
11-
///
7+
///
128
/// Many of the request header fields for proactive negotiation use a
139
/// common parameter, named "q" (case-insensitive), to assign a relative
1410
/// "weight" to the preference for that associated kind of content. This
1511
/// weight is referred to as a "quality value" (or "qvalue") because the
1612
/// same parameter name is often used within server configurations to
1713
/// assign a weight to the relative quality of the various
1814
/// representations that can be selected for a resource.
19-
///
15+
///
2016
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
21-
pub(crate) struct QualityValue<QualSep = SemiQ> {
17+
pub struct QualityValue<QualSep = SemiQ> {
2218
csv: FlatCsv,
2319
_marker: PhantomData<QualSep>,
2420
}
2521

26-
pub(crate) trait QualityDelimiter {
27-
const STR: &'static str;
28-
}
22+
mod sealed {
23+
use super::QualityValue;
24+
use std::cmp::Ordering;
25+
use std::convert::{From, TryFrom};
26+
use std::marker::PhantomData;
2927

30-
/// enum that represents the ';q=' delimiter
31-
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
32-
pub(crate) enum SemiQ {}
28+
use itertools::Itertools;
29+
use util::{FlatCsv, TryFromValues};
30+
use HeaderValue;
3331

34-
impl QualityDelimiter for SemiQ {
35-
const STR: &'static str = ";q=";
36-
}
32+
pub trait QualityDelimiter {
33+
const STR: &'static str;
34+
}
3735

38-
/// enum that represents the ';level=' delimiter (extremely rare)
39-
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
40-
pub(crate) enum SemiLevel {}
36+
/// enum that represents the ';q=' delimiter
37+
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
38+
pub enum SemiQ {}
4139

42-
impl QualityDelimiter for SemiLevel {
43-
const STR: &'static str = ";level=";
44-
}
40+
impl QualityDelimiter for SemiQ {
41+
const STR: &'static str = ";q=";
42+
}
4543

46-
#[derive(Clone, Debug, PartialEq, Eq)]
47-
struct QualityMeta<'a, Sep = SemiQ> {
48-
pub data: &'a str,
49-
pub quality: u16,
50-
_marker: PhantomData<Sep>,
51-
}
44+
/// enum that represents the ';level=' delimiter (extremely rare)
45+
#[derive(Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)]
46+
pub enum SemiLevel {}
5247

53-
impl<Delm: QualityDelimiter + Ord> Ord for QualityMeta<'_, Delm> {
54-
fn cmp(&self, other: &Self) -> Ordering {
55-
other.quality.cmp(&self.quality)
48+
impl QualityDelimiter for SemiLevel {
49+
const STR: &'static str = ";level=";
5650
}
57-
}
5851

59-
impl<Delm: QualityDelimiter + Ord> PartialOrd for QualityMeta<'_, Delm> {
60-
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
61-
Some(self.cmp(other))
52+
#[derive(Clone, Debug, PartialEq, Eq)]
53+
struct QualityMeta<'a, Sep = SemiQ> {
54+
pub data: &'a str,
55+
pub quality: u16,
56+
_marker: PhantomData<Sep>,
6257
}
63-
}
64-
65-
impl<'a, Delm: QualityDelimiter> TryFrom<&'a str> for QualityMeta<'a, Delm> {
66-
type Error = ::Error;
6758

68-
fn try_from(val: &'a str) -> Result<Self, ::Error> {
69-
let mut parts: Vec<&str> = val.split(Delm::STR).collect();
59+
impl<Delm: QualityDelimiter + Ord> Ord for QualityMeta<'_, Delm> {
60+
fn cmp(&self, other: &Self) -> Ordering {
61+
other.quality.cmp(&self.quality)
62+
}
63+
}
7064

71-
match (parts.pop(), parts.pop()) {
72-
(Some(qual), Some(data)) => {
73-
let parsed: f32 = qual.parse().map_err(|_| ::Error::invalid())?;
74-
let quality = (parsed * 1000_f32) as u16;
65+
impl<Delm: QualityDelimiter + Ord> PartialOrd for QualityMeta<'_, Delm> {
66+
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
67+
Some(self.cmp(other))
68+
}
69+
}
7570

76-
Ok(QualityMeta {
71+
impl<'a, Delm: QualityDelimiter> TryFrom<&'a str> for QualityMeta<'a, Delm> {
72+
type Error = ::Error;
73+
74+
fn try_from(val: &'a str) -> Result<Self, ::Error> {
75+
let mut parts: Vec<&str> = val.split(Delm::STR).collect();
76+
77+
match (parts.pop(), parts.pop()) {
78+
(Some(qual), Some(data)) => {
79+
let parsed: f32 = qual.parse().map_err(|_| ::Error::invalid())?;
80+
let quality = (parsed * 1000_f32) as u16;
81+
82+
Ok(QualityMeta {
83+
data,
84+
quality,
85+
_marker: PhantomData,
86+
})
87+
}
88+
// No deliter present, assign a quality value of 1
89+
(Some(data), None) => Ok(QualityMeta {
7790
data,
78-
quality,
91+
quality: 1000_u16,
7992
_marker: PhantomData,
80-
})
93+
}),
94+
_ => Err(::Error::invalid()),
8195
}
82-
// No deliter present, assign a quality value of 1
83-
(Some(data), None) => Ok(QualityMeta {
84-
data,
85-
quality: 1000_u16,
86-
_marker: PhantomData,
87-
}),
88-
_ => Err(::Error::invalid()),
8996
}
9097
}
91-
}
9298

93-
impl<Delm: QualityDelimiter + Ord> QualityValue<Delm> {
94-
pub(crate) fn iter(&self) -> impl Iterator<Item = &str> {
95-
self.csv
96-
.iter()
97-
.map(|v| QualityMeta::<Delm>::try_from(v).unwrap())
98-
.into_iter()
99-
.sorted()
100-
.map(|pair| pair.data)
101-
.into_iter()
99+
impl<Delm: QualityDelimiter + Ord> QualityValue<Delm> {
100+
pub(crate) fn iter(&self) -> impl Iterator<Item = &str> {
101+
self.csv
102+
.iter()
103+
.map(|v| QualityMeta::<Delm>::try_from(v).unwrap())
104+
.into_iter()
105+
.sorted()
106+
.map(|pair| pair.data)
107+
.into_iter()
108+
}
102109
}
103-
}
104110

105-
impl<Delm: QualityDelimiter> From<FlatCsv> for QualityValue<Delm> {
106-
fn from(csv: FlatCsv) -> Self {
107-
QualityValue {
108-
csv,
109-
_marker: PhantomData,
111+
impl<Delm: QualityDelimiter> From<FlatCsv> for QualityValue<Delm> {
112+
fn from(csv: FlatCsv) -> Self {
113+
QualityValue {
114+
csv,
115+
_marker: PhantomData,
116+
}
110117
}
111118
}
112-
}
113119

114-
impl<Delm: QualityDelimiter, F: Into<f32>> TryFrom<(&str, F)> for QualityValue<Delm> {
115-
type Error = ::Error;
120+
impl<Delm: QualityDelimiter, F: Into<f32>> TryFrom<(&str, F)> for QualityValue<Delm> {
121+
type Error = ::Error;
116122

117-
fn try_from(pair: (&str, F)) -> Result<Self, ::Error> {
118-
let value = HeaderValue::try_from(format!("{}{}{}", pair.0, Delm::STR, pair.1.into()))
119-
.map_err(|_e| ::Error::invalid())?;
120-
Ok(QualityValue {
121-
csv: value.into(),
122-
_marker: PhantomData,
123-
})
123+
fn try_from(pair: (&str, F)) -> Result<Self, ::Error> {
124+
let value = HeaderValue::try_from(format!("{}{}{}", pair.0, Delm::STR, pair.1.into()))
125+
.map_err(|_e| ::Error::invalid())?;
126+
Ok(QualityValue {
127+
csv: value.into(),
128+
_marker: PhantomData,
129+
})
130+
}
124131
}
125-
}
126132

127-
impl<Delm> From<HeaderValue> for QualityValue<Delm> {
128-
fn from(value: HeaderValue) -> Self {
129-
QualityValue {
130-
csv: value.into(),
131-
_marker: PhantomData,
133+
impl<Delm> From<HeaderValue> for QualityValue<Delm> {
134+
fn from(value: HeaderValue) -> Self {
135+
QualityValue {
136+
csv: value.into(),
137+
_marker: PhantomData,
138+
}
132139
}
133140
}
134-
}
135141

136-
impl<'a, Delm> From<&'a QualityValue<Delm>> for HeaderValue {
137-
fn from(qual: &'a QualityValue<Delm>) -> HeaderValue {
138-
qual.csv.value.clone()
142+
impl<'a, Delm> From<&'a QualityValue<Delm>> for HeaderValue {
143+
fn from(qual: &'a QualityValue<Delm>) -> HeaderValue {
144+
qual.csv.value.clone()
145+
}
139146
}
140-
}
141147

142-
impl<Delm> From<QualityValue<Delm>> for HeaderValue {
143-
fn from(qual: QualityValue<Delm>) -> HeaderValue {
144-
qual.csv.value
148+
impl<Delm> From<QualityValue<Delm>> for HeaderValue {
149+
fn from(qual: QualityValue<Delm>) -> HeaderValue {
150+
qual.csv.value
151+
}
145152
}
146-
}
147153

148-
impl<Delm: QualityDelimiter> TryFromValues for QualityValue<Delm> {
149-
fn try_from_values<'i, I>(values: &mut I) -> Result<Self, ::Error>
150-
where
151-
I: Iterator<Item = &'i HeaderValue>,
152-
{
153-
let flat: FlatCsv = values.collect();
154-
Ok(QualityValue::from(flat))
154+
impl<Delm: QualityDelimiter> TryFromValues for QualityValue<Delm> {
155+
fn try_from_values<'i, I>(values: &mut I) -> Result<Self, ::Error>
156+
where
157+
I: Iterator<Item = &'i HeaderValue>,
158+
{
159+
let flat: FlatCsv = values.collect();
160+
Ok(QualityValue::from(flat))
161+
}
155162
}
156163
}
157164

158165
#[cfg(test)]
159166
mod tests {
160-
use super::*;
167+
use super::{
168+
sealed::{SemiLevel, SemiQ},
169+
QualityValue,
170+
};
161171
use HeaderValue;
162172

163173
#[test]

0 commit comments

Comments
 (0)