#![doc(html_root_url = "https://docs.rs/typed-headers/0.1")]
extern crate base64;
extern crate bytes;
extern crate chrono;
pub extern crate http;
pub extern crate mime;
use http::header::{self, HeaderMap, HeaderName, HeaderValue};
use std::error;
use std::fmt;
use std::mem;
pub use impls::*;
mod impls;
pub mod util;
pub trait Header {
fn name() -> &'static HeaderName;
fn from_values<'a>(
values: &mut header::ValueIter<'a, HeaderValue>,
) -> Result<Option<Self>, Error>
where
Self: Sized;
fn to_values(&self, values: &mut ToValues);
}
#[derive(Debug)]
enum ErrorKind {
InvalidValue,
TooFewValues,
TooManyValues,
}
#[derive(Debug)]
pub struct Error(ErrorKind);
impl Error {
#[inline]
pub fn invalid_value() -> Error {
Error(ErrorKind::InvalidValue)
}
#[inline]
pub fn too_few_values() -> Error {
Error(ErrorKind::TooFewValues)
}
#[inline]
pub fn too_many_values() -> Error {
Error(ErrorKind::TooManyValues)
}
}
impl fmt::Display for Error {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
let s = match self.0 {
ErrorKind::InvalidValue => "invalid header value",
ErrorKind::TooFewValues => "too few header values",
ErrorKind::TooManyValues => "too many header values",
};
fmt.write_str(s)
}
}
impl error::Error for Error {
fn description(&self) -> &str {
"header error"
}
}
enum ToValuesState<'a> {
First(header::Entry<'a, HeaderValue>),
Latter(header::OccupiedEntry<'a, HeaderValue>),
Tmp,
}
pub struct ToValues<'a>(ToValuesState<'a>);
impl<'a> ToValues<'a> {
pub fn append(&mut self, value: HeaderValue) {
let entry = match mem::replace(&mut self.0, ToValuesState::Tmp) {
ToValuesState::First(header::Entry::Occupied(mut e)) => {
e.insert(value);
e
}
ToValuesState::First(header::Entry::Vacant(e)) => e.insert_entry(value),
ToValuesState::Latter(mut e) => {
e.append(value);
e
}
ToValuesState::Tmp => unreachable!(),
};
self.0 = ToValuesState::Latter(entry);
}
}
pub trait HeaderMapExt {
fn typed_get<H>(&self) -> Result<Option<H>, Error>
where
H: Header;
fn typed_insert<H>(&mut self, header: &H)
where
H: Header;
fn typed_remove<H>(&mut self) -> Result<Option<H>, Error>
where
H: Header;
}
impl HeaderMapExt for HeaderMap {
fn typed_get<H>(&self) -> Result<Option<H>, Error>
where
H: Header,
{
let mut values = self.get_all(H::name()).iter();
match H::from_values(&mut values) {
Ok(header) => match values.next() {
Some(_) => Err(Error::too_many_values()),
None => Ok(header),
},
Err(e) => Err(e),
}
}
fn typed_insert<H>(&mut self, header: &H)
where
H: Header,
{
let entry = self.entry(H::name()).unwrap();
let mut values = ToValues(ToValuesState::First(entry));
header.to_values(&mut values);
}
fn typed_remove<H>(&mut self) -> Result<Option<H>, Error>
where
H: Header,
{
match self.entry(H::name()).unwrap() {
header::Entry::Occupied(entry) => {
let r = H::from_values(&mut entry.iter());
entry.remove();
r
}
header::Entry::Vacant(_) => Ok(None),
}
}
}