1#![doc(html_root_url = "https://docs.rs/typed-headers/0.1")]
9
10extern crate base64;
11extern crate bytes;
12extern crate chrono;
13
14pub extern crate http;
15pub extern crate mime;
16
17use http::header::{self, HeaderMap, HeaderName, HeaderValue};
18use std::error;
19use std::fmt;
20use std::mem;
21
22pub use impls::*;
23
24mod impls;
25pub mod util;
26
27pub trait Header {
28 fn name() -> &'static HeaderName;
34
35 fn from_values<'a>(
43 values: &mut header::ValueIter<'a, HeaderValue>,
44 ) -> Result<Option<Self>, Error>
45 where
46 Self: Sized;
47
48 fn to_values(&self, values: &mut ToValues);
56}
57
58#[derive(Debug)]
59enum ErrorKind {
60 InvalidValue,
61 TooFewValues,
62 TooManyValues,
63}
64
65#[derive(Debug)]
67pub struct Error(ErrorKind);
68
69impl Error {
70 #[inline]
71 pub fn invalid_value() -> Error {
72 Error(ErrorKind::InvalidValue)
73 }
74
75 #[inline]
76 pub fn too_few_values() -> Error {
77 Error(ErrorKind::TooFewValues)
78 }
79
80 #[inline]
81 pub fn too_many_values() -> Error {
82 Error(ErrorKind::TooManyValues)
83 }
84}
85
86impl fmt::Display for Error {
87 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
88 let s = match self.0 {
89 ErrorKind::InvalidValue => "invalid header value",
90 ErrorKind::TooFewValues => "too few header values",
91 ErrorKind::TooManyValues => "too many header values",
92 };
93 fmt.write_str(s)
94 }
95}
96
97impl error::Error for Error {
98 fn description(&self) -> &str {
99 "header error"
100 }
101}
102
103enum ToValuesState<'a> {
104 First(header::Entry<'a, HeaderValue>),
105 Latter(header::OccupiedEntry<'a, HeaderValue>),
106 Tmp,
107}
108
109pub struct ToValues<'a>(ToValuesState<'a>);
110
111impl<'a> ToValues<'a> {
112 pub fn append(&mut self, value: HeaderValue) {
113 let entry = match mem::replace(&mut self.0, ToValuesState::Tmp) {
114 ToValuesState::First(header::Entry::Occupied(mut e)) => {
115 e.insert(value);
116 e
117 }
118 ToValuesState::First(header::Entry::Vacant(e)) => e.insert_entry(value),
119 ToValuesState::Latter(mut e) => {
120 e.append(value);
121 e
122 }
123 ToValuesState::Tmp => unreachable!(),
124 };
125 self.0 = ToValuesState::Latter(entry);
126 }
127}
128
129pub trait HeaderMapExt {
131 fn typed_get<H>(&self) -> Result<Option<H>, Error>
133 where
134 H: Header;
135
136 fn typed_insert<H>(&mut self, header: &H)
140 where
141 H: Header;
142
143 fn typed_remove<H>(&mut self) -> Result<Option<H>, Error>
147 where
148 H: Header;
149}
150
151impl HeaderMapExt for HeaderMap {
152 fn typed_get<H>(&self) -> Result<Option<H>, Error>
153 where
154 H: Header,
155 {
156 let mut values = self.get_all(H::name()).iter();
157 match H::from_values(&mut values) {
158 Ok(header) => match values.next() {
159 Some(_) => Err(Error::too_many_values()),
160 None => Ok(header),
161 },
162 Err(e) => Err(e),
163 }
164 }
165
166 fn typed_insert<H>(&mut self, header: &H)
167 where
168 H: Header,
169 {
170 let entry = self.entry(H::name());
171 let mut values = ToValues(ToValuesState::First(entry));
172 header.to_values(&mut values);
173 }
174
175 fn typed_remove<H>(&mut self) -> Result<Option<H>, Error>
176 where
177 H: Header,
178 {
179 match self.entry(H::name()) {
180 header::Entry::Occupied(entry) => {
181 let r = H::from_values(&mut entry.iter());
182 entry.remove();
183 r
184 }
185 header::Entry::Vacant(_) => Ok(None),
186 }
187 }
188}