use headers::{Error, Header};
use hyper::header::{ACCEPT, HeaderName, HeaderValue};
use super::QualityValue;
#[derive(Clone, Debug)]
pub(crate) struct Accept(QualityValue);
impl Header for Accept {
fn name() -> &'static HeaderName {
&ACCEPT
}
fn decode<'i, I>(values: &mut I) -> Result<Self, Error>
where
I: Iterator<Item = &'i HeaderValue>,
{
QualityValue::try_from_values(values).map(Self)
}
fn encode<E: Extend<HeaderValue>>(&self, values: &mut E) {
values.extend(std::iter::once((&self.0).into()))
}
}
impl Accept {
pub(crate) fn accepts(&self, media_type: &str) -> bool {
self.0
.iter()
.any(|value| value.eq_ignore_ascii_case(media_type))
}
pub(crate) fn accepts_markdown(&self) -> bool {
self.accepts("text/markdown")
}
pub(crate) fn preferred_media_type<'a>(&self, candidates: &[&'a str]) -> Option<&'a str> {
self.0.iter().find_map(|value| {
candidates
.iter()
.find(|candidate| value.eq_ignore_ascii_case(candidate))
.copied()
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn accepts_markdown_explicit() {
let val = HeaderValue::from_static("text/markdown");
let accept = Accept(val.into());
assert!(accept.accepts_markdown());
}
#[test]
fn accepts_markdown_with_quality() {
let val = HeaderValue::from_static("text/html, text/markdown;q=0.9");
let accept = Accept(val.into());
assert!(accept.accepts_markdown());
}
#[test]
fn does_not_accept_markdown_wildcard() {
let val = HeaderValue::from_static("text/*");
let accept = Accept(val.into());
assert!(!accept.accepts_markdown());
}
#[test]
fn does_not_accept_markdown_any() {
let val = HeaderValue::from_static("*/*");
let accept = Accept(val.into());
assert!(!accept.accepts_markdown());
}
#[test]
fn does_not_accept_markdown_html() {
let val = HeaderValue::from_static("text/html, application/json");
let accept = Accept(val.into());
assert!(!accept.accepts_markdown());
}
#[test]
fn preferred_media_type_json_first() {
let val = HeaderValue::from_static("application/json, text/html");
let accept = Accept(val.into());
assert_eq!(
accept.preferred_media_type(&["application/json", "text/html"]),
Some("application/json")
);
}
#[test]
fn preferred_media_type_html_first() {
let val = HeaderValue::from_static("text/html, application/json");
let accept = Accept(val.into());
assert_eq!(
accept.preferred_media_type(&["application/json", "text/html"]),
Some("text/html")
);
}
#[test]
fn preferred_media_type_respects_q_values() {
let val = HeaderValue::from_static("text/html;q=0.8, application/json;q=0.9");
let accept = Accept(val.into());
assert_eq!(
accept.preferred_media_type(&["application/json", "text/html"]),
Some("application/json")
);
}
#[test]
fn preferred_media_type_none_when_absent() {
let val = HeaderValue::from_static("text/plain, */*");
let accept = Accept(val.into());
assert_eq!(
accept.preferred_media_type(&["application/json", "text/html"]),
None
);
}
#[test]
fn preferred_media_type_case_insensitive() {
let val = HeaderValue::from_static("Application/JSON");
let accept = Accept(val.into());
assert_eq!(
accept.preferred_media_type(&["application/json"]),
Some("application/json")
);
}
}