1use std::borrow::Cow;
2use std::fmt;
3use bytes::Bytes;
4
5pub trait RawLike<'a> {
8 type IntoIter: Iterator<Item=&'a [u8]> + 'a;
10
11 fn len(&'a self) -> usize;
13
14 fn one(&'a self) -> Option<&'a [u8]>;
17
18 fn iter(&'a self) -> Self::IntoIter;
20}
21
22#[derive(Clone, Debug)]
24pub struct Raw(Lines);
25
26impl Raw {
27 pub fn push<V: Into<Raw>>(&mut self, val: V) {
29 let raw = val.into();
30 match raw.0 {
31 Lines::Empty => (),
32 Lines::One(one) => self.push_line(one),
33 Lines::Many(lines) => {
34 for line in lines {
35 self.push_line(line);
36 }
37 }
38 }
39 }
40
41 fn push_line(&mut self, line: Bytes) {
42 let lines = ::std::mem::replace(&mut self.0, Lines::Empty);
43 match lines {
44 Lines::Empty => {
45 self.0 = Lines::One(line);
46 }
47 Lines::One(one) => {
48 self.0 = Lines::Many(vec![one, line]);
49 }
50 Lines::Many(mut lines) => {
51 lines.push(line);
52 self.0 = Lines::Many(lines);
53 }
54 }
55 }
56}
57
58impl<'a> RawLike<'a> for Raw {
59 type IntoIter = RawLines<'a>;
60
61 #[inline]
62 fn len(&'a self) -> usize {
63 match self.0 {
64 Lines::Empty => 0,
65 Lines::One(..) => 1,
66 Lines::Many(ref lines) => lines.len()
67 }
68 }
69
70 #[inline]
71 fn one(&'a self) -> Option<&'a [u8]> {
72 match self.0 {
73 Lines::One(ref line) => Some(line.as_ref()),
74 Lines::Many(ref lines) if lines.len() == 1 => Some(lines[0].as_ref()),
75 _ => None
76 }
77 }
78
79 #[inline]
80 fn iter(&'a self) -> RawLines<'a> {
81 RawLines {
82 inner: &self.0,
83 pos: 0,
84 }
85 }
86}
87
88#[derive(Clone)]
89enum Lines {
90 Empty,
91 One(Bytes),
92 Many(Vec<Bytes>),
93}
94
95fn eq_many<A: AsRef<[u8]>, B: AsRef<[u8]>>(a: &[A], b: &[B]) -> bool {
96 if a.len() != b.len() {
97 false
98 } else {
99 for (a, b) in a.iter().zip(b.iter()) {
100 if a.as_ref() != b.as_ref() {
101 return false
102 }
103 }
104 true
105 }
106}
107
108fn eq<B: AsRef<[u8]>>(raw: &Raw, b: &[B]) -> bool {
109 match raw.0 {
110 Lines::Empty => b.is_empty(),
111 Lines::One(ref line) => eq_many(&[line], b),
112 Lines::Many(ref lines) => eq_many(lines, b)
113 }
114}
115
116impl PartialEq for Raw {
117 fn eq(&self, other: &Raw) -> bool {
118 match other.0 {
119 Lines::Empty => eq(self, &[] as &[Bytes]),
120 Lines::One(ref line) => eq(self, &[line]),
121 Lines::Many(ref lines) => eq(self, lines),
122 }
123 }
124}
125
126impl Eq for Raw {}
127
128impl PartialEq<[Vec<u8>]> for Raw {
129 fn eq(&self, bytes: &[Vec<u8>]) -> bool {
130 eq(self, bytes)
131 }
132}
133
134impl<'a> PartialEq<[&'a [u8]]> for Raw {
135 fn eq(&self, bytes: &[&[u8]]) -> bool {
136 eq(self, bytes)
137 }
138}
139
140impl PartialEq<[String]> for Raw {
141 fn eq(&self, bytes: &[String]) -> bool {
142 eq(self, bytes)
143 }
144}
145
146impl<'a> PartialEq<[&'a str]> for Raw {
147 fn eq(&self, bytes: &[&'a str]) -> bool {
148 eq(self, bytes)
149 }
150}
151
152impl PartialEq<[u8]> for Raw {
153 fn eq(&self, bytes: &[u8]) -> bool {
154 match self.0 {
155 Lines::Empty => bytes.is_empty(),
156 Lines::One(ref line) => line.as_ref() == bytes,
157 Lines::Many(..) => false
158 }
159 }
160}
161
162impl PartialEq<str> for Raw {
163 fn eq(&self, s: &str) -> bool {
164 self == s.as_bytes()
165 }
166}
167
168impl From<Vec<Vec<u8>>> for Raw {
169 #[inline]
170 fn from(val: Vec<Vec<u8>>) -> Raw {
171 Raw(Lines::Many(
172 val.into_iter()
173 .map(|vec| maybe_literal(vec.into()))
174 .collect()
175 ))
176 }
177}
178
179impl From<String> for Raw {
180 #[inline]
181 fn from(val: String) -> Raw {
182 Raw::from(val.into_bytes())
183 }
184}
185
186impl From<Vec<u8>> for Raw {
187 #[inline]
188 fn from(val: Vec<u8>) -> Raw {
189 Raw(Lines::One(maybe_literal(val.into())))
190 }
191}
192
193impl<'a> From<&'a str> for Raw {
194 fn from(val: &'a str) -> Raw {
195 Raw::from(val.as_bytes())
196 }
197}
198
199impl<'a> From<&'a [u8]> for Raw {
200 fn from(val: &'a [u8]) -> Raw {
201 Raw(Lines::One(maybe_literal(val.into())))
202 }
203}
204
205impl From<Bytes> for Raw {
206 #[inline]
207 fn from(val: Bytes) -> Raw {
208 Raw(Lines::One(val))
209 }
210}
211
212#[cfg(feature = "headers")]
213pub fn parsed(val: Bytes) -> Raw {
214 Raw(Lines::One(From::from(val)))
215}
216
217#[cfg(feature = "headers")]
218pub fn push(raw: &mut Raw, val: Bytes) {
219 raw.push_line(val);
220}
221
222#[cfg(feature = "headers")]
223pub fn new() -> Raw {
224 Raw(Lines::Empty)
225}
226
227impl fmt::Debug for Lines {
228 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
229 match *self {
230 Lines::Empty => f.pad("[]"),
231 Lines::One(ref line) => fmt::Debug::fmt(&[line], f),
232 Lines::Many(ref lines) => fmt::Debug::fmt(lines, f)
233 }
234 }
235}
236
237impl ::std::ops::Index<usize> for Raw {
238 type Output = [u8];
239
240 fn index(&self, idx: usize) -> &[u8] {
241 match self.0 {
242 Lines::Empty => panic!("index of out of bounds: {}", idx),
243 Lines::One(ref line) => if idx == 0 {
244 line.as_ref()
245 } else {
246 panic!("index out of bounds: {}", idx)
247 },
248 Lines::Many(ref lines) => lines[idx].as_ref()
249 }
250 }
251}
252
253macro_rules! literals {
254 ($($len:expr => $($value:expr),+;)+) => (
255 fn maybe_literal(s: Cow<[u8]>) -> Bytes {
256 match s.len() {
257 $($len => {
258 $(
259 if s.as_ref() == $value {
260 return Bytes::from_static($value);
261 }
262 )+
263 })+
264
265 _ => ()
266 }
267
268 Bytes::from(s.into_owned())
269 }
270
271 #[test]
272 fn test_literal_lens() {
273 $(
274 $({
275 let s = $value;
276 assert!(s.len() == $len, "{:?} has len of {}, listed as {}", s, s.len(), $len);
277 })+
278 )+
279 }
280 );
281}
282
283literals! {
284 1 => b"*", b"0";
285 3 => b"*/*";
286 4 => b"gzip";
287 5 => b"close";
288 7 => b"chunked";
289 10 => b"keep-alive";
290}
291
292impl<'a> IntoIterator for &'a Raw {
293 type IntoIter = RawLines<'a>;
294 type Item = &'a [u8];
295
296 fn into_iter(self) -> RawLines<'a> {
297 self.iter()
298 }
299}
300
301pub struct RawLines<'a> {
302 inner: &'a Lines,
303 pos: usize,
304}
305
306impl<'a> fmt::Debug for RawLines<'a> {
307 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
308 f.debug_tuple("RawLines")
309 .field(&self.inner)
310 .finish()
311 }
312}
313
314impl<'a> Iterator for RawLines<'a> {
315 type Item = &'a [u8];
316
317 #[inline]
318 fn next(&mut self) -> Option<&'a [u8]> {
319 let current_pos = self.pos;
320 self.pos += 1;
321 match *self.inner {
322 Lines::Empty => None,
323 Lines::One(ref line) => {
324 if current_pos == 0 {
325 Some(line.as_ref())
326 } else {
327 None
328 }
329 }
330 Lines::Many(ref lines) => lines.get(current_pos).map(|l| l.as_ref()),
331 }
332 }
333}