Created
August 19, 2016 00:29
-
-
Save m4rw3r/eb7a239b10ec7f73ec34d71cc6e36c24 to your computer and use it in GitHub Desktop.
impl Trait with Input trait version of the chomp example HTTP-parser
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![feature(conservative_impl_trait)] | |
#[macro_use] | |
extern crate chomp; | |
extern crate memmap; | |
use std::fs::File; | |
use std::env; | |
use chomp::types::{Input, Parser}; | |
use chomp::monad::*; | |
use chomp::parsers::*; | |
use chomp::combinators::*; | |
#[derive(Debug)] | |
struct Request<B> { | |
method: B, | |
uri: B, | |
version: B, | |
} | |
#[derive(Debug)] | |
struct Header<B> { | |
name: B, | |
value: Vec<B>, | |
} | |
fn is_token(c: u8) -> bool { | |
match c { | |
128...255 => false, | |
0...31 => false, | |
b'(' => false, | |
b')' => false, | |
b'<' => false, | |
b'>' => false, | |
b'@' => false, | |
b',' => false, | |
b';' => false, | |
b':' => false, | |
b'\\' => false, | |
b'"' => false, | |
b'/' => false, | |
b'[' => false, | |
b']' => false, | |
b'?' => false, | |
b'=' => false, | |
b'{' => false, | |
b'}' => false, | |
b' ' => false, | |
_ => true, | |
} | |
} | |
fn is_horizontal_space(c: u8) -> bool { c == b' ' || c == b'\t' } | |
fn is_space(c: u8) -> bool { c == b' ' } | |
fn is_not_space(c: u8) -> bool { c != b' ' } | |
fn is_end_of_line(c: u8) -> bool { c == b'\r' || c == b'\n' } | |
fn is_http_version(c: u8) -> bool { c >= b'0' && c <= b'9' || c == b'.' } | |
fn end_of_line<I: Input<Token=u8>>() -> impl Parser<I, Output=u8, Error=Error<u8>> { | |
parse!{(token(b'\r') <|> ret b'\0') >> token(b'\n')} | |
} | |
fn message_header_line<I: Input<Token=u8>>() -> impl Parser<I, Output=I::Buffer, Error=Error<u8>> { | |
parse!{ | |
take_while1(is_horizontal_space); | |
let line = take_till(is_end_of_line); | |
end_of_line(); | |
ret line | |
} | |
} | |
fn message_header<I: Input<Token=u8>>() -> impl Parser<I, Output=Header<I::Buffer>, Error=Error<u8>> { | |
parse!{ | |
let name = take_while1(is_token); | |
token(b':'); | |
let lines = many_from(1, message_header_line); | |
ret Header { | |
name: name, | |
value: lines, | |
} | |
} | |
} | |
fn http_version<I: Input<Token=u8>>() -> impl Parser<I, Output=I::Buffer, Error=Error<u8>> { | |
parse!{ | |
string(b"HTTP/"); | |
take_while1(is_http_version) | |
} | |
} | |
fn request_line<I: Input<Token=u8>>() -> impl Parser<I, Output=Request<I::Buffer>, Error=Error<u8>> { | |
parse!{ | |
let method = take_while1(is_token); | |
take_while1(is_space); | |
let uri = take_while1(is_not_space); | |
take_while1(is_space); | |
let version = http_version(); | |
ret Request { | |
method: method, | |
uri: uri, | |
version: version, | |
} | |
} | |
} | |
#[inline(never)] | |
fn request<I: Input<Token=u8>>() -> impl Parser<I, Output=(Request<I::Buffer>, Vec<Header<I::Buffer>>), Error=Error<u8>> | |
where I::Buffer: ::std::ops::Deref<Target=[u8]> { | |
parse!{ | |
let r = request_line(); | |
end_of_line(); | |
let h = many(message_header); | |
end_of_line(); | |
ret (r, h) | |
} | |
} | |
fn main() { | |
let contents = memmap::Mmap::open_path(env::args().nth(1).expect("File to read"), memmap::Protection::Read).expect("Failed to open file"); | |
let mut n = 0; | |
let mut data = unsafe { contents.as_slice() }; | |
loop { | |
match request().parse(data) { | |
(i, Ok(_)) => { | |
n = n + 1; | |
data = i; | |
}, | |
(_, Err(e)) => { | |
panic!("Error: {:?}", e); | |
}, | |
} | |
if data.is_empty() { | |
break; | |
} | |
} | |
println!("num: {}", n); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment