Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
63 commits
Select commit Hold shift + click to select a range
e9e2964
WIP
m4rw3r Mar 17, 2016
05fc3c2
Input trait: Made it possible to be even more generic over the input,…
m4rw3r Mar 17, 2016
64bec6a
Updated combinators
m4rw3r Mar 18, 2016
2d68c4f
Updated ascii and parse_only
m4rw3r Mar 18, 2016
3c041ae
Updated combinators::bounded::many
m4rw3r Mar 18, 2016
a829059
test: Tests for primitives on slice and partial slice
m4rw3r Mar 18, 2016
37479cc
updated combinators::bounded::many_till
m4rw3r Mar 18, 2016
82eeed4
combinators::bounded::many: Fixed backtracking and sep_by tests
m4rw3r Mar 18, 2016
98443f3
combinators::bounded::many_till: Added tests and fixed bugs
m4rw3r Mar 18, 2016
001e142
Updated combinators::bounded::skip_many
m4rw3r Mar 18, 2016
a8711c4
Updated combinators::matched_by
m4rw3r Mar 18, 2016
2e05b8f
Updated benchmarks
m4rw3r Mar 18, 2016
0ceda8d
Updated buffers
m4rw3r Mar 18, 2016
4e6ba8e
WIP on removing incomplete
m4rw3r Mar 20, 2016
f5f5e97
WIP
m4rw3r Mar 24, 2016
4c7c3a3
Indent, #inline and comments
m4rw3r Mar 24, 2016
46ae0aa
Moved Input and ParseResult into types module, made primitives a real…
m4rw3r Mar 24, 2016
46a972c
Fixed use statements with prelude move
m4rw3r Mar 28, 2016
f9cbedd
Added Buffer::iter
m4rw3r Mar 28, 2016
c58c51c
Input for ByteTendril
m4rw3r Mar 28, 2016
0caabd7
Replaced inner State with Result
m4rw3r Mar 28, 2016
6fb259f
Replaced Buffer::iter with Buffer::fold
m4rw3r Mar 30, 2016
94297d9
Moved traits in types to solve name resolution issues
m4rw3r Mar 30, 2016
29d2855
Input tests
m4rw3r Mar 30, 2016
8b87bda
Removed incomplete amount from streams and parse_only
m4rw3r Mar 30, 2016
8b04012
Updated rustdoc
m4rw3r Mar 30, 2016
7c5f000
Use Input::* for parse! macro
m4rw3r Mar 30, 2016
a77456a
Fixed compile tests
m4rw3r Mar 30, 2016
3289ce5
take* parsers now only require FnMut
m4rw3r Mar 31, 2016
e2a062b
Stateful: Fixed issue where incomplete was not handled correctly on s…
m4rw3r Mar 31, 2016
c6f3203
clippy
m4rw3r Mar 31, 2016
5256a50
Clippy as feature
m4rw3r Mar 31, 2016
578492d
Macros: Reversed use of Universal Function Call syntax for Input
m4rw3r Aug 16, 2016
b4c209a
Macros: Fixed syntax error caused by missing parenthesis
m4rw3r Aug 16, 2016
f6c7834
Primitives: Slight doc updates
m4rw3r Aug 16, 2016
f1696b6
Tests: Combinators
m4rw3r Aug 17, 2016
71f6ed9
Tests: parsers
m4rw3r Aug 17, 2016
af07b42
Tests: ParseResult
m4rw3r Aug 17, 2016
c9c0d54
Moved ParseResult to types
m4rw3r Aug 17, 2016
47e8512
Buffer: Followed convention for to_vec() and into_vec()
m4rw3r Aug 17, 2016
d642e76
Removed unused ParseResult constructor function
m4rw3r Aug 17, 2016
107c0cf
moved InputBuf to buffer module
m4rw3r Aug 17, 2016
4000dbf
Updated http parser bench and example to use U8Input
m4rw3r Aug 17, 2016
4ca3312
buffer: Stream now uses Input as an associated type, removed IntoStream
m4rw3r Aug 17, 2016
701ab9d
doc
m4rw3r Aug 17, 2016
b93d3b4
parse: Added parse_only_str
m4rw3r Aug 17, 2016
a7e6503
Tests: combinators
m4rw3r Aug 17, 2016
a058d69
Doc
m4rw3r Aug 17, 2016
3074472
Moved things around to satisfy Clippy lints
m4rw3r Aug 17, 2016
42dd656
Updated readme and intro docs to use new syntax
m4rw3r Aug 17, 2016
ae9b9d0
Updated changelog
m4rw3r Aug 17, 2016
21257ed
Implemented basic numbering wrapper for Input
m4rw3r Aug 18, 2016
5641525
Implemented run_parser
m4rw3r Aug 18, 2016
2b5f519
Updated changelog
m4rw3r Aug 18, 2016
f101312
Parsers: skip_while
m4rw3r Aug 28, 2016
bf5acc5
Updated bitflags and conv
m4rw3r Aug 22, 2016
a882292
Updated minimum stable rust version to 1.6.0
m4rw3r Aug 31, 2016
8bbbb83
Increased minimum verison requirement due to bitflags crate
m4rw3r Aug 31, 2016
5e4fbd1
bench: Fixed compiler warning
m4rw3r Aug 31, 2016
08704f3
combinators::bounded::many_till: Fixed bug for exact number of iterat…
m4rw3r Aug 31, 2016
b23d182
combinators::bounded: More tests for edge-cases
m4rw3r Aug 31, 2016
de60bd7
combinators::bounded: Defined behavior for Range when start == end an…
m4rw3r Aug 31, 2016
f037f09
Changelog: Added bugfixes
m4rw3r Aug 31, 2016
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ rust:
- stable
- beta
- nightly
# Minimum supported version (bitflags fails on 1.1):
- 1.2.0
# Minimum supported version (bitflags fails on 1.7 due to op_assign_traits not being stable):
- 1.8.0

# necessary for `travis-cargo coveralls --no-sudo`
addons:
Expand Down
55 changes: 54 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,29 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Added

- `prelude` module containing basic types, parsers and combinators.

This is supposed to be the equivalent of Attoparsec's main package.

- `run_parser` which executes a parser on any given `Input` type.

- `buffer::InputBuf` which contains a slice and an incomplete flag, much as the old `Input` struct.

- `Input<Token=T, Buffer=&[T]>` implementation for `&[T]` where `T: Copy + PartialEq`.

- `Input<Token=char, Buffer=&str>` implementation for `&str`.

- `types::Buffer` trait which is implemented for all buffers providing common logic to perform the
final parsing on a buffer without knowing the exact buffer implementation.

- `types::U8Input` trait alias for `Input<Token=u8>`.

- `primitives::Primitives` trait providing access to the primitive methods of the `Input` trait.

This is used for building fundamental parsers/combinators.

- `ParseResult::inspect` allowing code to observe the success value.

- `chomp::Error` now includes a backtrace in `test` and `debug` build profiles thanks to the
[debugtrace crate](https://github.com/m4rw3r/debugtrace_rs). Backtraces can also be activated
permanently using the `backtrace` feature but this will incur the significant cost of allocating
Expand All @@ -17,6 +40,27 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Changes

- **Backwards-incompatible:** `Input` is now a trait with associated types `Token` and `Buffer`.

This removes all incomplete logic from the parsers themselves and moves it into the `InputBuf`
type. This `InputBuf` is used if a partial buffer is in memory. It also allows the parsers to
operate directly on slices or use more effective means of storing buffers depending on the
`Input` implementation.

To upgrade you replace the previous concrete `Input` type with a generic, use its associated
type if required, and refer to the `Buffer` associated type to allow for zero-copy parsing::

-fn http_version(i: Input<u8>) -> U8Result<&[u8]>;
+fn http_version<I: Input<Token=u8>>(i: I) -> SimpleResult<I, I::Buffer>;

The associated types can be restricted if requried:

fn request<I: U8Input>(i: I) -> SimpleResult<I, (Request<I::Buffer>, Vec<Header<I::Buffer>>)>
where I::Buffer: ::std::ops::Deref<Target=[u8]>;

- **Backwards-incompatible:** Moved types into a more logical module structure, prelude now
exists as a `prelude` module.

- **Backwards-incompatible:** `chomp::Error` is no longer an enum, this is to facillitate the
support of backtraces while keeping code compatible between the different build profiles.

Expand All @@ -26,10 +70,19 @@ This project adheres to [Semantic Versioning](http://semver.org/).

### Removed

- `Input::incomplete`
- `Input::new`
- `ParseResult::expect`
- `ParseResult::unwrap`
- `ParseResult::unwrap_err`
- `ParseResult::unwrap`
- `buffer::IntoStream`
- `primitives::InputClone`
- `primitives::State`

## Bugfixes

- `combinators::bounded` now have a defined behavior when a `Range<usize>` has `start == end`: They will parse exactly `start` times. This also fixed a few overflows and unreachable code being reachable.
- `combinators::bounded::many_till` got fixed for an overflow happening when `0: usize` was used to limit the number of iterations.

## [0.2.6] - 2016-07-07

Expand Down
6 changes: 4 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,15 @@ include = [
]

[dependencies]
bitflags = "0.5.0"
conv = { version = "0.3", default-features = false, features = ["std"] }
bitflags = "0.7.0"
conv = { version = "0.3.3", default-features = false, features = ["std"] }
debugtrace = { version = "0.1.0" }
tendril = { version = "0.2.2", optional = true }

# Technically a dev-dependency, but dev-dependencies are not allowed to be optional,
# compiletest_rs fails to compile on stable and beta
compiletest_rs = { version = "0.2.1", optional = true }
clippy = { version = ">0.0.1", optional = true }

[features]
# Feature for running extra (compiletime fail) tests on nightly
Expand Down
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,14 +47,14 @@ fn f() -> (u8, u8, u8) {
A Chomp parser with a similar structure looks like this:

```rust
fn f(i: Input<u8>) -> U8Result<(u8, u8, u8)> {
fn f<I: U8Input>(i: I) -> SimpleResult<I, (u8, u8, u8)> {
parse!{i;
let a = read_digit();
let b = read_digit();
string(b"missiles");
ret (a, b, a + b);
let a = digit();
let b = digit();
string(b"missiles");
ret (a, b, a + b)
}
}
}
```

And to implement `read_digit` we can utilize the `map` function to manipulate any success value while preserving any error or incomplete state:
Expand All @@ -68,7 +68,7 @@ fn read_digit() -> u8 {
}

// Chomp, error handling built in, and we make sure we only get a number:
fn read_digit(i: Input<u8>) -> U8Result<u8> {
fn read_digit<I: U8Input>(i: I) -> SimpleResult<I, u8> {
satisfy(i, |c| b'0' <= c && c <= b'9').map(|c| c - b'0')
}
```
Expand Down
67 changes: 53 additions & 14 deletions benches/combinators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,83 +7,122 @@ use test::Bencher;

use std::iter;

use chomp::*;
use chomp::buffer::{Stream, IntoStream};
use chomp::prelude::*;
use chomp::buffer::InputBuf;

#[bench]
fn count_vec_1k(b: &mut Bencher) {
let data = iter::repeat(b'a').take(1024).collect::<Vec<u8>>();

fn count_vec<I: Copy>(i: Input<I>) -> ParseResult<I, Vec<I>, Error<I>> {
fn count_vec<I: Input>(i: I) -> ParseResult<I, Vec<I::Token>, Error<I::Token>> {
count(i, 1024, any)
}

b.iter(|| {
data.into_stream().parse(count_vec)
parse_only(count_vec, &data)
})
}

#[bench]
fn count_vec_10k(b: &mut Bencher) {
let data = iter::repeat(b'a').take(10024).collect::<Vec<u8>>();

fn count_vec<I: Copy>(i: Input<I>) -> ParseResult<I, Vec<I>, Error<I>> {
fn count_vec<I: Input>(i: I) -> ParseResult<I, Vec<I::Token>, Error<I::Token>> {
count(i, 10024, any)
}

b.iter(|| {
data.into_stream().parse(count_vec)
parse_only(count_vec, &data)
})
}

#[bench]
fn many_vec_1k(b: &mut Bencher) {
let data = iter::repeat(b'a').take(1024).collect::<Vec<u8>>();

fn many_vec<I: Copy>(i: Input<I>) -> ParseResult<I, Vec<I>, Error<I>> {
fn many_vec<I: Input>(i: I) -> ParseResult<I, Vec<I::Token>, Error<I::Token>> {
many(i, any)
}

b.iter(|| {
data.into_stream().parse(many_vec)
parse_only(many_vec, &data)
})
}

#[bench]
fn many_vec_10k(b: &mut Bencher) {
let data = iter::repeat(b'a').take(10024).collect::<Vec<u8>>();

fn many_vec<I: Copy>(i: Input<I>) -> ParseResult<I, Vec<I>, Error<I>> {
fn many_vec<I: Input>(i: I) -> ParseResult<I, Vec<I::Token>, Error<I::Token>> {
many(i, any)
}

b.iter(|| {
data.into_stream().parse(many_vec)
parse_only(many_vec, &data)
})
}

#[bench]
fn many1_vec_1k(b: &mut Bencher) {
let data = iter::repeat(b'a').take(1024).collect::<Vec<u8>>();

fn many1_vec<I: Copy>(i: Input<I>) -> ParseResult<I, Vec<I>, Error<I>> {
fn many1_vec<I: Input>(i: I) -> ParseResult<I, Vec<I::Token>, Error<I::Token>> {
many1(i, any)
}

b.iter(|| {
data.into_stream().parse(many1_vec)
parse_only(many1_vec, &data)
})
}

#[bench]
fn many1_vec_10k(b: &mut Bencher) {
let data = iter::repeat(b'a').take(10024).collect::<Vec<u8>>();

fn many1_vec<I: Copy>(i: Input<I>) -> ParseResult<I, Vec<I>, Error<I>> {
fn many1_vec<I: Input>(i: I) -> ParseResult<I, Vec<I::Token>, Error<I::Token>> {
many1(i, any)
}

b.iter(|| {
data.into_stream().parse(many1_vec)
parse_only(many1_vec, &data)
})
}

#[bench]
fn count_vec_10k_maybe_incomplete(b: &mut Bencher) {
let data = iter::repeat(b'a').take(10024).collect::<Vec<u8>>();

fn count_vec<I: Input>(i: I) -> ParseResult<I, Vec<I::Token>, Error<I::Token>> {
count(i, 10024, any)
}

b.iter(|| {
count_vec(InputBuf::new(&data))
})
}

#[bench]
fn many_vec_10k_maybe_incomplete(b: &mut Bencher) {
let data = iter::repeat(b'a').take(10024).collect::<Vec<u8>>();

fn many_vec<I: Input>(i: I) -> ParseResult<I, Vec<I::Token>, Error<I::Token>> {
many(i, any)
}

b.iter(|| {
many_vec(InputBuf::new(&data))
})
}

#[bench]
fn many1_vec_10k_maybe_incomplete(b: &mut Bencher) {
let data = iter::repeat(b'a').take(10024).collect::<Vec<u8>>();

fn many1_vec<I: Input>(i: I) -> ParseResult<I, Vec<I::Token>, Error<I::Token>> {
many1(i, any)
}

b.iter(|| {
many1_vec(InputBuf::new(&data))
})
}
46 changes: 22 additions & 24 deletions benches/http_bench.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,20 +4,19 @@ extern crate test;
extern crate chomp;

use test::Bencher;
use chomp::*;
use chomp::buffer::{Stream, IntoStream};
use chomp::prelude::*;

#[derive(Debug)]
struct Request<'a> {
method: &'a [u8],
uri: &'a [u8],
version: &'a [u8],
struct Request<B> {
method: B,
uri: B,
version: B,
}

#[derive(Debug)]
struct Header<'a> {
name: &'a [u8],
value: Vec<&'a [u8]>,
struct Header<B> {
name: B,
value: Vec<B>,
}

fn is_token(c: u8) -> bool {
Expand Down Expand Up @@ -52,22 +51,18 @@ 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<u8>) -> U8Result<u8> {
or(i, |i| parse!{i;
token(b'\r');
token(b'\n');
ret b'\r'},
|i| token(i, b'\n'))
fn end_of_line<I: U8Input>(i: I) -> SimpleResult<I, u8> {
parse!{i; (token(b'\r') <|> ret b'\0') >> token(b'\n')}
}

fn http_version(i: Input<u8>) -> U8Result<&[u8]> {
fn http_version<I: U8Input>(i: I) -> SimpleResult<I, I::Buffer> {
parse!{i;
string(b"HTTP/");
take_while1(is_http_version)
}
}

fn request_line(i: Input<u8>) -> U8Result<Request> {
fn request_line<I: U8Input>(i: I) -> SimpleResult<I, Request<I::Buffer>> {
parse!{i;
let method = take_while1(is_token);
take_while1(is_space);
Expand All @@ -83,7 +78,7 @@ fn request_line(i: Input<u8>) -> U8Result<Request> {
}
}

fn message_header_line(i: Input<u8>) -> U8Result<&[u8]> {
fn message_header_line<I: U8Input>(i: I) -> SimpleResult<I, I::Buffer> {
parse!{i;
take_while1(is_horizontal_space);
let line = take_till(is_end_of_line);
Expand All @@ -93,7 +88,7 @@ fn message_header_line(i: Input<u8>) -> U8Result<&[u8]> {
}
}

fn message_header(i: Input<u8>) -> U8Result<Header> {
fn message_header<I: U8Input>(i: I) -> SimpleResult<I, Header<I::Buffer>> {
parse!{i;
let name = take_while1(is_token);
token(b':');
Expand All @@ -106,7 +101,8 @@ fn message_header(i: Input<u8>) -> U8Result<Header> {
}
}

fn request(i: Input<u8>) -> U8Result<(Request, Vec<Header>)> {
#[inline(never)]
fn request<I: U8Input>(i: I) -> SimpleResult<I, (Request<I::Buffer>, Vec<Header<I::Buffer>>)> {
parse!{i;
let r = request_line();
end_of_line();
Expand All @@ -130,7 +126,7 @@ Connection: keep-alive\r
\r";

b.iter(|| {
data.into_stream().parse(request)
parse_only(request, data)
})
}

Expand All @@ -142,7 +138,7 @@ Host: localhost\r
\r";

b.iter(|| {
data.into_stream().parse(request)
parse_only(request, data)
})
}

Expand All @@ -161,7 +157,7 @@ Cookie: azk=ue1-5eb08aeed9a7401c9195cb933eb7c966\r
\r";

b.iter(|| {
data.into_stream().parse(request)
parse_only(request, data)
})
}

Expand All @@ -170,6 +166,8 @@ fn multiple_requests(b: &mut Bencher) {
let data = include_bytes!("./data/http-requests.txt");

b.iter(|| {
data.into_stream().parse::<_, Vec<_>, _>(parser!{many(request)})
let r: Result<Vec<_>, _> = parse_only(parser!{many(request)}, data);

r
})
}
Loading