use core::fmt;
use std::slice::Iter;
pub const ACCEPT_ENCODING: &str = "Accept-Encoding";
pub const AUTHORIZATION: &str = "Authorization";
pub const COOKIE: &str = "Cookie";
pub const CONTENT_ENCODING: &str = "Content-Encoding";
pub const CONTENT_TYPE: &str = "Content-Type";
pub const EXPECT: &str = "Expect";
pub const LOCATION: &str = "Location";
pub const SET_COOKIE: &str = "Set-Cookie";
pub const USER_AGENT: &str = "User-Agent";
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Header {
pub name: String,
pub value: String,
}
impl fmt::Display for Header {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}: {}", self.name, self.value)
}
}
impl Header {
pub fn new(name: &str, value: &str) -> Self {
Header {
name: name.to_string(),
value: value.to_string(),
}
}
pub fn name_eq(&self, name: &str) -> bool {
self.name.to_lowercase() == name.to_lowercase()
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct HeaderVec {
headers: Vec<Header>,
}
impl HeaderVec {
pub fn new() -> Self {
HeaderVec::default()
}
pub fn get(&self, name: &str) -> Option<&Header> {
self.headers.iter().find(|h| h.name_eq(name))
}
pub fn get_all(&self, name: &str) -> Vec<&Header> {
self.headers.iter().filter(|h| h.name_eq(name)).collect()
}
pub fn contains_key(&self, name: &str) -> bool {
self.headers.iter().any(|h| h.name_eq(name))
}
pub fn retain<F>(&mut self, mut f: F)
where
F: FnMut(&Header) -> bool,
{
self.headers.retain(|h| f(h));
}
pub fn iter(&self) -> impl Iterator<Item = &Header> {
self.headers.iter()
}
pub fn len(&self) -> usize {
self.headers.len()
}
pub fn is_empty(&self) -> bool {
self.headers.len() == 0
}
pub fn push(&mut self, header: Header) {
self.headers.push(header);
}
pub fn values(&self, name: &str) -> Vec<&str> {
self.get_all(name)
.iter()
.map(|h| h.value.as_str())
.collect::<Vec<_>>()
}
}
impl<'a> IntoIterator for &'a HeaderVec {
type Item = &'a Header;
type IntoIter = Iter<'a, Header>;
fn into_iter(self) -> Self::IntoIter {
self.headers.iter()
}
}
impl<'a> Extend<&'a Header> for HeaderVec {
fn extend<T: IntoIterator<Item = &'a Header>>(&mut self, iter: T) {
self.headers.extend(iter.into_iter().cloned());
}
}
#[cfg(test)]
mod tests {
use crate::http::Header;
use crate::http::header::HeaderVec;
#[test]
fn test_simple_header_map() {
let mut headers = HeaderVec::new();
headers.push(Header::new("foo", "xxx"));
headers.push(Header::new("bar", "yyy0"));
headers.push(Header::new("bar", "yyy1"));
headers.push(Header::new("bar", "yyy2"));
headers.push(Header::new("baz", "zzz"));
assert_eq!(headers.len(), 5);
assert!(!headers.is_empty());
assert_eq!(headers.get("foo"), Some(&Header::new("foo", "xxx")));
assert_eq!(headers.get("FOO"), Some(&Header::new("foo", "xxx")));
assert_eq!(headers.get("bar"), Some(&Header::new("bar", "yyy0")));
assert_eq!(headers.get("qux"), None);
assert_eq!(
headers.get_all("bar"),
vec![
&Header::new("bar", "yyy0"),
&Header::new("bar", "yyy1"),
&Header::new("bar", "yyy2"),
]
);
assert_eq!(headers.get_all("BAZ"), vec![&Header::new("baz", "zzz")]);
assert_eq!(headers.get_all("qux"), Vec::<&Header>::new());
assert!(headers.contains_key("FOO"));
assert!(!headers.contains_key("fuu"));
headers.retain(|h| h.name_eq("Bar"));
assert_eq!(headers.len(), 3);
}
#[test]
fn test_iter() {
let data = [("foo", "xxx"), ("bar", "yyy0"), ("baz", "yyy1")];
let mut headers = HeaderVec::new();
data.iter()
.for_each(|(name, value)| headers.push(Header::new(name, value)));
for (i, h) in headers.iter().enumerate() {
assert_eq!(h.name, data[i].0);
assert_eq!(h.value, data[i].1);
}
for (i, h) in (&headers).into_iter().enumerate() {
assert_eq!(h.name, data[i].0);
assert_eq!(h.value, data[i].1);
}
}
}