Skip to content

Instantly share code, notes, and snippets.

@m4rw3r
Created August 19, 2016 00:29
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save m4rw3r/eb7a239b10ec7f73ec34d71cc6e36c24 to your computer and use it in GitHub Desktop.
Save m4rw3r/eb7a239b10ec7f73ec34d71cc6e36c24 to your computer and use it in GitHub Desktop.
impl Trait with Input trait version of the chomp example HTTP-parser
#![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