Repository: Marwes/combine (language: rust)

Issue:
The `unexpected` parser should return arbitrary types
Instead of just `()`


Discussion / hints:

Fix patch:
diff --git a/.travis.yml b/.travis.yml
index 23e390e2..a0de29da 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -13,12 +13,13 @@ rust:
 - nightly
 - beta
 - stable
+- 1.20.0
 before_script:
 - |
   pip install 'travis-cargo<0.2' --user &&
   export PATH=$HOME/.local/bin:$PATH
 script:
-- travis_wait 30 ./travis.sh
+- ./travis.sh
 - travis-cargo --only stable doc
 after_success: |
     if [[ "$TRAVIS_RUST_VERSION" == stable ]]; then
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dff08146..30a8631a 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,34 @@
+<a name="3.0.0-beta.1"></a>
+## v3.0.0-beta.1 (2018-02-02)
+
+
+#### Features
+
+*   Encode parsers as resumable state machines [342fc47](https://github.com/Marwes/combine/commit/342fc4770ee9dc62df51683ccca2e612d6e1ea33)
+*   Add the unexpected_any parser ([979e0d7e](https://github.com/Marwes/combine/commit/979e0d7e4ac63c41712352bc87b51001aa067879), closes [#126](https://github.com/Marwes/combine/issues/126))
+*   Don't have the error type be generic for uncons* ([df3e84f0](https://github.com/Marwes/combine/commit/df3e84f0275352fba44672b2701d452f6bb55596))
+*   Add a alias which helps to refer to the StreamError type ([95eb70cb](https://github.com/Marwes/combine/commit/95eb70cb025aec89925e3f1992a6d1b266328eb2))
+*   Add memchr optimized take_until_byte parsers ([30cc7d1d](https://github.com/Marwes/combine/commit/30cc7d1d39e754d2c2e8491eb2123dacec5d30f3))
+*   Add the `then_partial` parser ([5d402f6b](https://github.com/Marwes/combine/commit/5d402f6be0c1be4d69159d4df1d1d4589f5cd66e))
+*   Don't require `Clone` for `Stream` ([3fc0b540](https://github.com/Marwes/combine/commit/3fc0b540521aff959ce62628df1ac7554a9df861), breaks [#](https://github.com/Marwes/combine/issues/))
+
+#### Breaking Changes
+
+*   Don't require `Clone` for `Stream` ([3fc0b540](https://github.com/Marwes/combine/commit/3fc0b540521aff959ce62628df1ac7554a9df861), breaks [#](https://github.com/Marwes/combine/issues/))
+
+#### Bug Fixes
+
+*   Allow `parser!` to be used within functions ([916bb824](https://github.com/Marwes/combine/commit/916bb824741f054ed2f0686dcce316d0a770d9db))
+*   Allow multiple unnamed public parsers to be in the same scope ([c04e2247](https://github.com/Marwes/combine/commit/c04e2247ab04f098ef0eae887c7a7739d99212fc))
+*   Return the correct distance for slices with larger than 1 byte items ([6b3c661a](https://github.com/Marwes/combine/commit/6b3c661af23fd221d2b28c37ed207d37409c2491))
+*   Don't add extra expected errors when erroring in the middle of a sequence ([44eac24d](https://github.com/Marwes/combine/commit/44eac24d46f265a1b3a94d5587d4f200ebebc18f))
+
+#### Performance
+
+*   Avoid cloning input in satisfy ([9aeaefa9](https://github.com/Marwes/combine/commit/9aeaefa95f97bd8b9d186923e16cd8def98d8e81))
+
+
+
 <a name="3.0.0-alpha.4"></a>
 ## v3.0.0-alpha.4 (2017-10-11)
 
diff --git a/Cargo.toml b/Cargo.toml
index 96c08c52..7cd5dc2c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 
 name = "combine"
-version = "3.0.0-alpha.5"
+version = "3.0.0-beta.1"
 authors = ["Markus Westerlind <marwes91@gmail.com>"]
 
 description = "Fast parser combinators on arbitrary streams with zero-copy support."
@@ -60,7 +60,25 @@ name = "mp4"
 harness = false
 required-features = ["mp4"]
 
+[[example]]
+name = "async"
+required-features = ["std"]
+
+[[example]]
+name = "date"
+
+[[example]]
+name = "number"
+
+[[example]]
+name = "readme"
+
+[[example]]
+name = "ini"
+
 [package.metadata.docs.rs]
 features = ["doc"]
 
 [profile.bench]
+lto = true
+codegen-units = 1
diff --git a/benches/http.rs b/benches/http.rs
index 8b7ce778..e1c9c093 100644
--- a/benches/http.rs
+++ b/benches/http.rs
@@ -8,7 +8,6 @@ use bencher::{black_box, Bencher};
 use std::fmt;
 
 use combine::{many, token, ParseError, Parser, RangeStream, many1};
-use combine::error::UnexpectedParse;
 use combine::range::{range, take_while1};
 use combine::stream::easy;
 
@@ -141,7 +140,7 @@ where
     b.iter(|| {
         let mut buf = black_box(buffer.clone());
 
-        while buf.clone().uncons::<UnexpectedParse>().is_ok() {
+        while buf.clone().uncons().is_ok() {
             match parse_http_request(buf) {
                 Ok(((_, _), b)) => {
                     buf = b;
diff --git a/examples/tokio.rs b/examples/async.rs
similarity index 85%
rename from examples/tokio.rs
rename to examples/async.rs
index 3ef11c36..4b32bf23 100644
--- a/examples/tokio.rs
+++ b/examples/async.rs
@@ -17,8 +17,8 @@ use bytes::BytesMut;
 
 use tokio_io::codec::Decoder;
 
-use combine::error::ParseError;
-use combine::stream::{PartialStream, RangeStream};
+use combine::error::StreamError;
+use combine::stream::{PartialStream, RangeStream, StreamErrorFor};
 use combine::combinator::{any_partial_state, AnyPartialState};
 use combine::parser::range::{range, recognize, take};
 use combine::{skip_many, skip_many1};
@@ -49,17 +49,17 @@ impl LanguageServerDecoder {
 parser! {
     type PartialState = AnyPartialState;
     fn decode_parser['a, I](content_length_parses: Rc<Cell<i32>>)(I) -> Vec<u8>
-    where [ I: RangeStream<Item = u8, Range = &'a [u8], Error = easy::ParseError<I>>,
-            I::Error: ParseError<u8, &'a [u8], I::Position, StreamError = easy::Error<u8, &'a [u8]>>,
-        ]
+    where [ I: RangeStream<Item = u8, Range = &'a [u8]>, ]
     {
         let content_length =
             range(&b"Content-Length: "[..])
                 .with(
                     recognize(skip_many1(digit()))
-                        .and_then(|digits: &[u8]| unsafe {
-                            str::from_utf8_unchecked(digits).parse::<usize>()
-                        })
+                        .and_then(|digits: &[u8]|
+                            str::from_utf8(digits).unwrap().parse::<usize>()
+                                // Convert the error from `.parse` into an error combine understands
+                                .map_err(StreamErrorFor::<I>::other)
+                        )
                 )
                 .map(|x| {
                     content_length_parses.set(content_length_parses.get() + 1);
@@ -69,8 +69,8 @@ parser! {
             skip_many(range(&b"\r\n"[..])),
             content_length,
             range(&b"\r\n\r\n"[..]).map(|_| ()),
-        ).map(|t| t.1)
-            .then_partial(|&mut message_length| take(message_length).map(|bytes: &[u8]| bytes.to_owned())))
+        )
+            .then_partial(|&mut (_, message_length, _)| take(message_length).map(|bytes: &[u8]| bytes.to_owned())))
     }
 }
 
@@ -136,6 +136,8 @@ fn main() {
         PartialOp::Limited(3),
     ];
     let ref mut reader = Cursor::new(input.as_bytes());
+    // Using the `partial_io` crate we emulate the partial reads that would happen when reading
+    // asynchronously from an io device.
     let partial_reader = PartialAsyncRead::new(reader, seq);
 
     let decoder = LanguageServerDecoder::new();
diff --git a/examples/number.rs b/examples/number.rs
new file mode 100644
index 00000000..bd372912
--- /dev/null
+++ b/examples/number.rs
@@ -0,0 +1,22 @@
+extern crate combine;
+
+use combine::parser::range::recognize;
+use combine::parser::repeat::{skip_many, skip_many1};
+use combine::parser::choice::optional;
+use combine::parser::item::item;
+use combine::parser::byte::digit;
+use combine::error::UnexpectedParse;
+use combine::Parser;
+
+fn main() {
+    let mut parser = recognize((
+        skip_many1(digit()),
+        optional((item(b'.'), skip_many(digit()))),
+    )).and_then(|bs: &[u8]| {
+        let s = unsafe { ::std::str::from_utf8_unchecked(bs) };
+        s.parse::<f64>().map_err(|_| UnexpectedParse::Unexpected)
+    });
+    let result = parser.parse(&b"123.45"[..]);
+    assert_eq!(result, Ok((123.45, &b""[..])));
+    println!("{:?}", result);
+}
diff --git a/src/error.rs b/src/error.rs
index 3ccc5093..865ff3a4 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -203,7 +203,9 @@ pub type ParseResult<O, I> = Result<(O, Consumed<()>), Consumed<Tracked<<I as St
 pub type ParseResult2<O, E> = Result<(O, Consumed<()>), Consumed<Tracked<E>>>;
 
 /// `StreamError` represents a single error returned from a `Stream` or a `Parser`.
-/// Usually this is composed into a `ParseError`
+///
+/// Usually multiple instances of `StreamError` is composed into a `ParseError` to build the final
+/// error value.
 pub trait StreamError<Item, Range>: Sized + PartialEq {
     fn unexpected_token(token: Item) -> Self;
     fn unexpected_range(token: Range) -> Self;
@@ -265,6 +267,11 @@ pub trait StreamError<Item, Range>: Sized + PartialEq {
         Self::unexpected_static_message("end of input")
     }
 
+    /// Converts `self` into a different `StreamError` type.
+    ///
+    /// This should aim to preserve as much information as possible into the returned `T` value but
+    /// if `Self` ignores some information passed to it using one of the constructors that
+    /// information is naturally lost.
     fn into_other<T>(self) -> T
     where
         T: StreamError<Item, Range>;
@@ -272,7 +279,8 @@ pub trait StreamError<Item, Range>: Sized + PartialEq {
 
 /// Trait which defines a combine parse error.
 ///
-/// A parse error is composed of one or more `StreamError`s
+/// A parse error is composed of zero or more `StreamError` instances which gets added to it as
+/// errors are encountered during parsing.
 pub trait ParseError<Item, Range, Position>: Sized + PartialEq {
     type StreamError: StreamError<Item, Range>;
 
diff --git a/src/lib.rs b/src/lib.rs
index ab10b4a0..7b004aa8 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -741,7 +741,7 @@ mod std_tests {
         I::Position: Default,
     {
         let before = input.checkpoint();
-        match input.uncons::<Error<_, _>>() {
+        match input.uncons() {
             Ok(c) => if c.is_alphanumeric() {
                 input.reset(before);
                 let e = Error::Unexpected(c.into());
@@ -788,7 +788,7 @@ mod std_tests {
     fn iterator() {
         let result = parser(integer)
             .parse(State::new(IteratorStream::new("123".chars())))
-            .map(|(i, mut input)| (i, input.uncons::<Error<_, _>>().is_err()));
+            .map(|(i, mut input)| (i, input.uncons().is_err()));
         assert_eq!(result, Ok((123i64, true)));
     }
 
diff --git a/src/parser/byte.rs b/src/parser/byte.rs
index 39644398..7e2c2f2f 100644
--- a/src/parser/byte.rs
+++ b/src/parser/byte.rs
@@ -9,7 +9,7 @@ use Parser;
 use parser::ParseMode;
 use combinator::{satisfy, skip_many, token, tokens, Expected, Satisfy, SkipMany, Token};
 use parser::sequence::With;
-use error::{ConsumedResult, Info, ParseError, StreamError, Tracked, UnexpectedParse};
+use error::{ConsumedResult, Info, ParseError, StreamError, Tracked};
 use stream::{uncons_range, FullRangeStream, RangeStream, Stream, StreamOnce};
 
 use error::FastResult::*;
@@ -414,7 +414,7 @@ where
         }
         None => {
             *offset = bytes.len();
-            let _ = input.uncons_range::<UnexpectedParse>(bytes.len());
+            let _ = input.uncons_range(bytes.len());
             let err = I::Error::from_error(input.position(), StreamError::end_of_input());
             if !input.is_partial() && bytes.is_empty() {
                 EmptyErr(err.into())
diff --git a/src/parser/combinator.rs b/src/parser/combinator.rs
index 9236a5c0..12189d30 100644
--- a/src/parser/combinator.rs
+++ b/src/parser/combinator.rs
@@ -661,7 +661,7 @@ where
 ///
 /// assert_eq!(
 ///     example().easy_parse("ab"),
-///     Ok((('a', 'b'), "")),
+///     Ok((('a', 'b'), ""))
 /// );
 ///
 /// # }
diff --git a/src/parser/error.rs b/src/parser/error.rs
index c33ecdb4..f57955bd 100644
--- a/src/parser/error.rs
+++ b/src/parser/error.rs
@@ -9,18 +9,18 @@ use error::{ConsumedResult, Info, ParseError, StreamError, Tracked};
 use error::FastResult::*;
 
 #[derive(Clone)]
-pub struct Unexpected<I>(Info<I::Item, I::Range>, PhantomData<fn(I) -> I>)
+pub struct Unexpected<I, T>(Info<I::Item, I::Range>, PhantomData<fn(I) -> (I, T)>)
 where
     I: Stream;
-impl<I> Parser for Unexpected<I>
+impl<I, T> Parser for Unexpected<I, T>
 where
     I: Stream,
 {
     type Input = I;
-    type Output = ();
+    type Output = T;
     type PartialState = ();
     #[inline]
-    fn parse_lazy(&mut self, input: &mut Self::Input) -> ConsumedResult<(), I> {
+    fn parse_lazy(&mut self, input: &mut Self::Input) -> ConsumedResult<T, I> {
         EmptyErr(<Self::Input as StreamOnce>::Error::empty(input.position()).into())
     }
     fn add_error(&mut self, errors: &mut Tracked<<Self::Input as StreamOnce>::Error>) {
@@ -30,6 +30,8 @@ where
 /// Always fails with `message` as an unexpected error.
 /// Never consumes any input.
 ///
+/// Has `()` the output type
+///
 /// ```
 /// # extern crate combine;
 /// # use combine::*;
@@ -48,7 +50,40 @@ where
 /// # }
 /// ```
 #[inline(always)]
-pub fn unexpected<I, S>(message: S) -> Unexpected<I>
+pub fn unexpected<I, S>(message: S) -> Unexpected<I, ()>
+where
+    I: Stream,
+    S: Into<Info<I::Item, I::Range>>,
+{
+    unexpected_any(message)
+}
+
+/// Always fails with `message` as an unexpected error.
+/// Never consumes any input.
+///
+/// May have anything as the output type but must be used such that the output type can inferred.
+/// The `unexpected` parser can be used if the output type does not matter
+///
+/// ```
+/// # extern crate combine;
+/// # use combine::*;
+/// # use combine::parser::error::unexpected_any;
+/// # use combine::error::StreamError;
+/// # fn main() {
+/// let result = token('b').or(unexpected_any("token"))
+///     .easy_parse("a");
+/// assert!(result.is_err());
+/// assert!(
+///     result.err()
+///         .unwrap()
+///         .errors
+///         .iter()
+///         .any(|m| *m == StreamError::unexpected("token".into()))
+/// );
+/// # }
+/// ```
+#[inline(always)]
+pub fn unexpected_any<I, S, T>(message: S) -> Unexpected<I, T>
 where
     I: Stream,
     S: Into<Info<I::Item, I::Range>>,
diff --git a/src/parser/function.rs b/src/parser/function.rs
index e29e6f37..2910d614 100644
--- a/src/parser/function.rs
+++ b/src/parser/function.rs
@@ -88,7 +88,7 @@ where
     }
 }
 
-#[derive(Copy, Clone)]
+#[derive(Copy)]
 pub struct EnvParser<E, I, T>
 where
     I: Stream,
@@ -97,6 +97,19 @@ where
     parser: fn(E, &mut I) -> ParseResult<T, I>,
 }
 
+impl<E, I, T> Clone for EnvParser<E, I, T>
+where
+    I: Stream,
+    E: Clone,
+{
+    fn clone(&self) -> Self {
+        EnvParser {
+            env: self.env.clone(),
+            parser: self.parser,
+        }
+    }
+}
+
 impl<E, I, O> Parser for EnvParser<E, I, O>
 where
     E: Clone,
diff --git a/src/parser/item.rs b/src/parser/item.rs
index 80708d0c..89301f52 100644
--- a/src/parser/item.rs
+++ b/src/parser/item.rs
@@ -4,7 +4,7 @@ use lib::marker::PhantomData;
 
 use Parser;
 use stream::{uncons, Stream, StreamOnce};
-use error::{ConsumedResult, Info, ParseError, StreamError, Tracked, UnexpectedParse};
+use error::{ConsumedResult, Info, ParseError, StreamError, Tracked};
 
 use error::FastResult::*;
 
@@ -543,8 +543,8 @@ where
     #[inline]
     fn parse_lazy(&mut self, input: &mut Self::Input) -> ConsumedResult<(), I> {
         let before = input.checkpoint();
-        match input.uncons::<UnexpectedParse>() {
-            Err(ref err) if *err == UnexpectedParse::Eoi => EmptyOk(()),
+        match input.uncons() {
+            Err(ref err) if *err == StreamError::end_of_input() => EmptyOk(()),
             _ => {
                 input.reset(before);
                 EmptyErr(<Self::Input as StreamOnce>::Error::empty(input.position()).into())
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
index 1310799f..aaf3cded 100644
--- a/src/parser/mod.rs
+++ b/src/parser/mod.rs
@@ -6,7 +6,7 @@ use either::Either;
 
 use ErrorOffset;
 use stream::{Resetable, Stream, StreamOnce};
-use error::{ConsumedResult, FastResult, Info, ParseError, ParseResult, Tracked, UnexpectedParse};
+use error::{ConsumedResult, FastResult, Info, ParseError, ParseResult, Tracked};
 use error::FastResult::*;
 use combinator::{and_then, expected, flat_map, map, message, then, then_partial, AndThen,
                  Expected, FlatMap, Iter, Map, Message, Then, ThenPartial};
@@ -194,7 +194,7 @@ pub trait Parser {
         let mut result = self.parse_first(input, &mut state);
         if let FastResult::EmptyErr(ref mut error) = result {
             input.reset(before.clone());
-            if let Ok(t) = input.uncons::<UnexpectedParse>() {
+            if let Ok(t) = input.uncons() {
                 input.reset(before);
                 error.error.add_unexpected(Info::Token(t));
             }
@@ -213,7 +213,7 @@ pub trait Parser {
         let mut result = self.parse_partial(input, state);
         if let FastResult::EmptyErr(ref mut error) = result {
             input.reset(before.clone());
-            if let Ok(t) = input.uncons::<UnexpectedParse>() {
+            if let Ok(t) = input.uncons() {
                 input.reset(before);
                 error.error.add_unexpected(Info::Token(t));
             }
@@ -965,7 +965,7 @@ pub trait ParseMode: Copy {
         let mut result = parser.parse_mode_impl(self, input, state);
         if let FastResult::EmptyErr(ref mut error) = result {
             input.reset(before.clone());
-            if let Ok(t) = input.uncons::<UnexpectedParse>() {
+            if let Ok(t) = input.uncons() {
                 input.reset(before);
                 error.error.add_unexpected(Info::Token(t));
             }
diff --git a/src/parser/range.rs b/src/parser/range.rs
index b8dd9510..a58d1888 100644
--- a/src/parser/range.rs
+++ b/src/parser/range.rs
@@ -5,7 +5,7 @@ use lib::marker::PhantomData;
 use Parser;
 use stream::{uncons_range, uncons_while, wrap_stream_error, RangeStream, RangeStreamOnce,
              Resetable, StreamOnce};
-use error::{ConsumedResult, Info, ParseError, Tracked, UnexpectedParse};
+use error::{ConsumedResult, Info, ParseError, Tracked};
 use error::FastResult::*;
 use parser::ParseMode;
 
@@ -92,7 +92,7 @@ where
         }
         result
     } else {
-        if let Err(_) = input.uncons_range::<UnexpectedParse>(*distance_state) {
+        if let Err(_) = input.uncons_range(*distance_state) {
             panic!("recognize errored when restoring the input stream to its expected state");
         }
 
@@ -137,7 +137,7 @@ where
         let (ref mut distance_state, ref mut child_state) = *state;
 
         let before = input.checkpoint();
-        if let Err(_) = input.uncons_range::<UnexpectedParse>(*distance_state) {
+        if let Err(_) = input.uncons_range(*distance_state) {
             panic!("recognize errored when restoring the input stream to its expected state");
         }
 
@@ -403,7 +403,7 @@ where
                 Ok(xs) => {
                     if xs == self.0 {
                         input.reset(before);
-                        if let Ok(consumed) = input.uncons_range::<UnexpectedParse>(*to_consume) {
+                        if let Ok(consumed) = input.uncons_range(*to_consume) {
                             if *to_consume == 0 {
                                 return EmptyOk(consumed);
                             } else {
@@ -418,7 +418,7 @@ where
                     } else {
                         input.reset(look_ahead_input);
                         *to_consume += 1;
-                        if input.uncons::<UnexpectedParse>().is_err() {
+                        if input.uncons().is_err() {
                             unreachable!();
                         }
                     }
diff --git a/src/parser/sequence.rs b/src/parser/sequence.rs
index 324fbb67..2cd17818 100644
--- a/src/parser/sequence.rs
+++ b/src/parser/sequence.rs
@@ -3,7 +3,7 @@ use lib::marker::PhantomData;
 
 use {ErrorOffset, Parser, Stream, StreamOnce};
 use parser::ParseMode;
-use error::{ConsumedResult, ParseError, StreamError, Tracked, UnexpectedParse};
+use error::{ConsumedResult, ParseError, StreamError, Tracked};
 use error::FastResult::*;
 use combinator::{ignore, Ignore};
 
@@ -78,7 +78,7 @@ macro_rules! tuple_parser {
             {
                 err.offset = ErrorOffset(offset);
                 if first_empty_parser != 0 {
-                    if let Ok(t) = input.uncons::<UnexpectedParse>() {
+                    if let Ok(t) = input.uncons() {
                         err.error.add(StreamError::unexpected_token(t));
                     }
                     dispatch_on!(0, |i, mut p| {
diff --git a/src/stream/buffered.rs b/src/stream/buffered.rs
index 0652a46e..c74dfa5b 100644
--- a/src/stream/buffered.rs
+++ b/src/stream/buffered.rs
@@ -1,8 +1,27 @@
 use std::collections::VecDeque;
 
 use error::StreamError;
-use stream::{Positioned, Resetable, StreamOnce};
+use stream::{Positioned, Resetable, StreamErrorFor, StreamOnce};
 
+/// `Stream` which buffers items from an instance of `StreamOnce` into a ring buffer.
+/// Instancs of `StreamOnce` which is not able to implement `Resetable` (such as `ReadStream`) may
+/// use this as a way to implement `Resetable` and become a full `Stream` instance.
+///
+/// The drawback is that the buffer only stores a limited number of items which limits how many
+/// tokens that can be reset and replayed. If a `BufferedStream` is reset past this limit an error
+/// will be returned when `uncons` is next called.
+///
+/// NOTE: If this stream is used in conjunction with an error enhancing stream such as
+/// `easy::Stream` (also via the `easy_parser` method) it is recommended that the `BufferedStream`
+/// instance wraps the `easy::Stream` instance instead of the other way around.
+///
+/// ```ignore
+/// // DO
+/// BufferedStream::new(easy::Stream(..), ..)
+/// // DONT
+/// easy::Stream(BufferedStream::new(.., ..))
+/// parser.easy_parse(BufferedStream::new(..));
+/// ```
 #[derive(Debug, PartialEq)]
 pub struct BufferedStream<I>
 where
@@ -78,10 +97,7 @@ where
     type Error = I::Error;
 
     #[inline]
-    fn uncons<E>(&mut self) -> Result<I::Item, E>
-    where
-        E: StreamError<Self::Item, Self::Range>,
-    {
+    fn uncons(&mut self) -> Result<I::Item, StreamErrorFor<Self>> {
         if self.offset >= self.buffer_offset {
             let position = self.iter.position();
             let item = try!(self.iter.uncons());
diff --git a/src/stream/easy.rs b/src/stream/easy.rs
index bcfce91d..0bcdf8d8 100644
--- a/src/stream/easy.rs
+++ b/src/stream/easy.rs
@@ -68,11 +68,11 @@
 //!     });
 //!     assert_eq!(
 //!         parser().easy_parse(input).map_err(|err| err.map_position(|p| p.translate_position(input))),
-//!         expected_error,
+//!         expected_error
 //!     );
 //!     assert_eq!(
 //!         parser2().easy_parse(input).map_err(|err| err.map_position(|p| p.translate_position(input))),
-//!         expected_error,
+//!         expected_error
 //!     );
 //! }
 //!
@@ -84,7 +84,8 @@ use std::error::Error as StdError;
 use std::fmt;
 
 use error::{Info as PrimitiveInfo, StreamError, Tracked};
-use stream::{FullRangeStream, Positioned, RangeStream, RangeStreamOnce, Resetable, StreamOnce};
+use stream::{FullRangeStream, Positioned, RangeStream, RangeStreamOnce, Resetable, StreamErrorFor,
+             StreamOnce};
 
 /// Enum holding error information. Variants are defined for `Stream::Item` and `Stream::Range` as
 /// well as string variants holding easy descriptions.
@@ -457,7 +458,7 @@ impl<T: PartialEq, R: PartialEq> PartialEq for Error<T, R> {
     }
 }
 
-impl<E, T, R> From<E> for Error<T, R>
+impl<T, R, E> From<E> for Error<T, R>
 where
     E: StdError + 'static + Send + Sync,
 {
@@ -747,11 +748,8 @@ where
     type Error = ParseError<S>;
 
     #[inline]
-    fn uncons<E>(&mut self) -> Result<Self::Item, E>
-    where
-        E: StreamError<Self::Item, Self::Range>,
-    {
-        self.0.uncons()
+    fn uncons(&mut self) -> Result<Self::Item, StreamErrorFor<Self>> {
+        self.0.uncons().map_err(StreamError::into_other)
     }
 
     fn is_partial(&self) -> bool {
@@ -764,20 +762,16 @@ where
     S: RangeStream,
 {
     #[inline]
-    fn uncons_range<E>(&mut self, size: usize) -> Result<Self::Range, E>
-    where
-        E: StreamError<Self::Item, Self::Range>,
-    {
-        self.0.uncons_range(size)
+    fn uncons_range(&mut self, size: usize) -> Result<Self::Range, StreamErrorFor<Self>> {
+        self.0.uncons_range(size).map_err(StreamError::into_other)
     }
 
     #[inline]
-    fn uncons_while<E, F>(&mut self, f: F) -> Result<Self::Range, E>
+    fn uncons_while<F>(&mut self, f: F) -> Result<Self::Range, StreamErrorFor<Self>>
     where
         F: FnMut(Self::Item) -> bool,
-        E: StreamError<Self::Item, Self::Range>,
     {
-        self.0.uncons_while(f)
+        self.0.uncons_while(f).map_err(StreamError::into_other)
     }
 
     #[inline]
diff --git a/src/stream/mod.rs b/src/stream/mod.rs
index ecdbb2d7..ed12e48e 100644
--- a/src/stream/mod.rs
+++ b/src/stream/mod.rs
@@ -17,12 +17,11 @@ use lib::fmt;
 use std::io::{Bytes, Read};
 
 #[cfg(feature = "std")]
-use stream::easy::Error;
+use stream::easy::Errors;
 
 use Parser;
 
-use error::{ConsumedResult, ParseError, StreamError, StringStreamError, UnexpectedParse,
-            CHAR_BOUNDARY_ERROR_MESSAGE};
+use error::{ConsumedResult, ParseError, StreamError, StringStreamError, UnexpectedParse};
 use error::FastResult::*;
 
 #[doc(hidden)]
@@ -107,10 +106,7 @@ pub trait StreamOnce {
     type Error: ParseError<Self::Item, Self::Range, Self::Position>;
     /// Takes a stream and removes its first item, yielding the item and the rest of the elements.
     /// Returns `Err` if no element could be retrieved.
-
-    fn uncons<E>(&mut self) -> Result<Self::Item, E>
-    where
-        E: StreamError<Self::Item, Self::Range>;
+    fn uncons(&mut self) -> Result<Self::Item, StreamErrorFor<Self>>;
 
     /// Returns `true` if this stream only contains partial input.
     ///
@@ -157,16 +153,13 @@ where
 pub trait RangeStreamOnce: StreamOnce + Resetable {
     /// Takes `size` elements from the stream.
     /// Fails if the length of the stream is less than `size`.
-    fn uncons_range<E>(&mut self, size: usize) -> Result<Self::Range, E>
-    where
-        E: StreamError<Self::Item, Self::Range>;
+    fn uncons_range(&mut self, size: usize) -> Result<Self::Range, StreamErrorFor<Self>>;
 
     /// Takes items from stream, testing each one with `predicate`.
     /// returns the range of items which passed `predicate`.
-    fn uncons_while<E, F>(&mut self, f: F) -> Result<Self::Range, E>
+    fn uncons_while<F>(&mut self, f: F) -> Result<Self::Range, StreamErrorFor<Self>>
     where
-        F: FnMut(Self::Item) -> bool,
-        E: StreamError<Self::Item, Self::Range>;
+        F: FnMut(Self::Item) -> bool;
 
     /// Returns the distance between `self` and `end`. The returned `usize` must be so that
     ///
@@ -231,7 +224,7 @@ where
     I: ?Sized + Stream,
 {
     let before = input.checkpoint();
-    let x = input.uncons::<UnexpectedParse>() == Err(UnexpectedParse::Eoi);
+    let x = input.uncons() == Err(StreamError::end_of_input());
     input.reset(before);
     x
 }
@@ -278,10 +271,9 @@ pub trait Range {
 
 impl<'a> RangeStreamOnce for &'a str {
     #[inline]
-    fn uncons_while<E, F>(&mut self, mut f: F) -> Result<&'a str, E>
+    fn uncons_while<F>(&mut self, mut f: F) -> Result<&'a str, StreamErrorFor<Self>>
     where
         F: FnMut(Self::Item) -> bool,
-        E: StreamError<Self::Item, Self::Range>,
     {
         let mut chars = self.chars();
         while let Some(c) = chars.next() {
@@ -298,10 +290,7 @@ impl<'a> RangeStreamOnce for &'a str {
     }
 
     #[inline]
-    fn uncons_range<E>(&mut self, size: usize) -> Result<&'a str, E>
-    where
-        E: StreamError<Self::Item, Self::Range>,
-    {
+    fn uncons_range(&mut self, size: usize) -> Result<&'a str, StreamErrorFor<Self>> {
         fn is_char_boundary(s: &str, index: usize) -> bool {
             if index == s.len() {
                 return true;
@@ -317,10 +306,10 @@ impl<'a> RangeStreamOnce for &'a str {
                 *self = remaining;
                 Ok(result)
             } else {
-                Err(E::message_static_message(CHAR_BOUNDARY_ERROR_MESSAGE))
+                Err(StringStreamError::CharacterBoundary)
             }
         } else {
-            Err(E::end_of_input())
+            Err(StringStreamError::Eoi)
         }
     }
 
@@ -355,24 +344,20 @@ where
     T: Clone + PartialEq,
 {
     #[inline]
-    fn uncons_range<E>(&mut self, size: usize) -> Result<&'a [T], E>
-    where
-        E: StreamError<Self::Item, Self::Range>,
-    {
+    fn uncons_range(&mut self, size: usize) -> Result<&'a [T], StreamErrorFor<Self>> {
         if size <= self.len() {
             let (result, remaining) = self.split_at(size);
             *self = remaining;
             Ok(result)
         } else {
-            Err(E::end_of_input())
+            Err(UnexpectedParse::Eoi)
         }
     }
 
     #[inline]
-    fn uncons_while<E, F>(&mut self, mut f: F) -> Result<&'a [T], E>
+    fn uncons_while<F>(&mut self, mut f: F) -> Result<&'a [T], StreamErrorFor<Self>>
     where
         F: FnMut(Self::Item) -> bool,
-        E: StreamError<Self::Item, Self::Range>,
     {
         let len = self.iter().take_while(|c| f((**c).clone())).count();
         let (result, remaining) = self.split_at(len);
@@ -409,17 +394,14 @@ impl<'a> StreamOnce for &'a str {
     type Error = StringStreamError;
 
     #[inline]
-    fn uncons<E>(&mut self) -> Result<char, E>
-    where
-        E: StreamError<Self::Item, Self::Range>,
-    {
+    fn uncons(&mut self) -> Result<char, StreamErrorFor<Self>> {
         let mut chars = self.chars();
         match chars.next() {
             Some(c) => {
                 *self = chars.as_str();
                 Ok(c)
             }
-            None => Err(E::end_of_input()),
+            None => Err(StringStreamError::Eoi),
         }
     }
 }
@@ -444,16 +426,13 @@ where
     type Error = UnexpectedParse;
 
     #[inline]
-    fn uncons<E>(&mut self) -> Result<T, E>
-    where
-        E: StreamError<Self::Item, Self::Range>,
-    {
+    fn uncons(&mut self) -> Result<T, StreamErrorFor<Self>> {
         match self.split_first() {
             Some((first, rest)) => {
                 *self = rest;
                 Ok(first.clone())
             }
-            None => Err(E::end_of_input()),
+            None => Err(UnexpectedParse::Eoi),
         }
     }
 }
@@ -499,10 +478,7 @@ where
     type Error = S::Error;
 
     #[inline(always)]
-    fn uncons<E>(&mut self) -> Result<S::Item, E>
-    where
-        E: StreamError<Self::Item, Self::Range>,
-    {
+    fn uncons(&mut self) -> Result<S::Item, StreamErrorFor<Self>> {
         self.0.uncons()
     }
 
@@ -516,18 +492,14 @@ where
     S: RangeStreamOnce,
 {
     #[inline(always)]
-    fn uncons_range<E>(&mut self, size: usize) -> Result<Self::Range, E>
-    where
-        E: StreamError<Self::Item, Self::Range>,
-    {
+    fn uncons_range(&mut self, size: usize) -> Result<Self::Range, StreamErrorFor<Self>> {
         self.0.uncons_range(size)
     }
 
     #[inline(always)]
-    fn uncons_while<E, F>(&mut self, f: F) -> Result<Self::Range, E>
+    fn uncons_while<F>(&mut self, f: F) -> Result<Self::Range, StreamErrorFor<Self>>
     where
         F: FnMut(Self::Item) -> bool,
-        E: StreamError<Self::Item, Self::Range>,
     {
         self.0.uncons_while(f)
     }
@@ -578,16 +550,13 @@ where
     type Error = UnexpectedParse;
 
     #[inline]
-    fn uncons<E>(&mut self) -> Result<&'a T, E>
-    where
-        E: StreamError<Self::Item, Self::Range>,
-    {
+    fn uncons(&mut self) -> Result<&'a T, StreamErrorFor<Self>> {
         match self.0.split_first() {
             Some((first, rest)) => {
                 self.0 = rest;
                 Ok(first)
             }
-            None => Err(E::end_of_input()),
+            None => Err(UnexpectedParse::Eoi),
         }
     }
 }
@@ -597,24 +566,20 @@ where
     T: PartialEq + 'a,
 {
     #[inline]
-    fn uncons_range<E>(&mut self, size: usize) -> Result<&'a [T], E>
-    where
-        E: StreamError<Self::Item, Self::Range>,
-    {
+    fn uncons_range(&mut self, size: usize) -> Result<&'a [T], StreamErrorFor<Self>> {
         if size <= self.0.len() {
             let (range, rest) = self.0.split_at(size);
             self.0 = rest;
             Ok(range)
         } else {
-            Err(E::end_of_input())
+            Err(UnexpectedParse::Eoi)
         }
     }
 
     #[inline]
-    fn uncons_while<E, F>(&mut self, mut f: F) -> Result<&'a [T], E>
+    fn uncons_while<F>(&mut self, mut f: F) -> Result<&'a [T], StreamErrorFor<Self>>
     where
         F: FnMut(Self::Item) -> bool,
-        E: StreamError<Self::Item, Self::Range>,
     {
         let len = self.0.iter().take_while(|c| f(*c)).count();
         let (range, rest) = self.0.split_at(len);
@@ -677,13 +642,10 @@ where
     type Error = UnexpectedParse;
 
     #[inline]
-    fn uncons<E>(&mut self) -> Result<I::Item, E>
-    where
-        E: StreamError<Self::Item, Self::Range>,
-    {
+    fn uncons(&mut self) -> Result<I::Item, StreamErrorFor<Self>> {
         match self.next() {
             Some(x) => Ok(x),
-            None => Err(E::end_of_input()),
+            None => Err(UnexpectedParse::Eoi),
         }
     }
 }
@@ -697,18 +659,15 @@ pub struct ReadStream<R> {
 impl<R: Read> StreamOnce for ReadStream<R> {
     type Item = u8;
     type Range = u8;
-    type Position = ();
-    type Error = Error<u8, u8>;
+    type Position = usize;
+    type Error = Errors<u8, u8, usize>;
 
     #[inline]
-    fn uncons<E>(&mut self) -> Result<u8, E>
-    where
-        E: StreamError<Self::Item, Self::Range>,
-    {
+    fn uncons(&mut self) -> Result<u8, StreamErrorFor<Self>> {
         match self.bytes.next() {
             Some(Ok(b)) => Ok(b),
-            Some(Err(err)) => Err(E::other(err)),
-            None => Err(E::end_of_input()),
+            Some(Err(err)) => Err(StreamErrorFor::<Self>::other(err)),
+            None => Err(StreamErrorFor::<Self>::end_of_input()),
         }
     }
 }
@@ -781,17 +740,24 @@ impl PointerOffset {
     }
 }
 
+/// Decodes `input` using `parser`.
+///
+/// Return `Ok(Some(item), consumed_data)` if there was enough data to finish parsing using
+/// `parser`.
+/// Returns `Ok(None, consumed_data)` if `input` did not contain enough data to finish parsing
+/// using `parser`.
+///
+/// See `examples/async.rs` for example usage in a `tokio_io::codec::Decoder`
 pub fn decode<P>(
     mut parser: P,
-    src: P::Input,
+    mut input: P::Input,
     partial_state: &mut P::PartialState,
 ) -> Result<(Option<P::Output>, usize), <P::Input as StreamOnce>::Error>
 where
     P: Parser,
     P::Input: RangeStream,
 {
-    let start = src.checkpoint();
-    let mut input = src;
+    let start = input.checkpoint();
     match parser.parse_with_state(&mut input, partial_state) {
         Ok(message) => Ok((Some(message), input.distance(&start))),
         Err(err) => {
@@ -810,14 +776,11 @@ mod tests {
     #[test]
     #[inline]
     fn uncons_range_at_end() {
-        assert_eq!("".uncons_range::<UnexpectedParse>(0), Ok(""));
-        assert_eq!("123".uncons_range::<UnexpectedParse>(3), Ok("123"));
-        assert_eq!((&[1][..]).uncons_range::<UnexpectedParse>(1), Ok(&[1][..]));
+        assert_eq!("".uncons_range(0), Ok(""));
+        assert_eq!("123".uncons_range(3), Ok("123"));
+        assert_eq!((&[1][..]).uncons_range(1), Ok(&[1][..]));
         let s: &[u8] = &[];
-        assert_eq!(
-            SliceStream(s).uncons_range::<UnexpectedParse>(0),
-            Ok(&[][..])
-        );
+        assert_eq!(SliceStream(s).uncons_range(0), Ok(&[][..]));
     }
 
     #[test]
@@ -827,10 +790,10 @@ mod tests {
         let before = input.checkpoint();
         assert_eq!(input.distance(&before), 0);
 
-        input.uncons::<UnexpectedParse>().unwrap();
+        input.uncons().unwrap();
         assert_eq!(input.distance(&before), 1);
 
-        input.uncons::<UnexpectedParse>().unwrap();
+        input.uncons().unwrap();
         assert_eq!(input.distance(&before), 2);
 
         input.reset(before.clone());
diff --git a/src/stream/state.rs b/src/stream/state.rs
index b4416390..4fada08e 100644
--- a/src/stream/state.rs
+++ b/src/stream/state.rs
@@ -2,7 +2,7 @@ use lib::fmt;
 
 use error::{ParseError, StreamError};
 use stream::{FullRangeStream, IteratorStream, Positioned, RangeStreamOnce, Resetable, SliceStream,
-             StreamOnce};
+             StreamErrorFor, StreamOnce};
 
 #[cfg(feature = "std")]
 use stream::ReadStream;
@@ -130,10 +130,7 @@ where
     type Error = I::Error;
 
     #[inline]
-    fn uncons<E>(&mut self) -> Result<I::Item, E>
-    where
-        E: StreamError<I::Item, I::Range>,
-    {
+    fn uncons(&mut self) -> Result<I::Item, StreamErrorFor<Self>> {
         self.input.uncons().map(|c| {
             self.positioner.update(&c);
             c
@@ -251,10 +248,7 @@ where
     I::Position: Clone + Ord,
 {
     #[inline]
-    fn uncons_range<E>(&mut self, size: usize) -> Result<I::Range, E>
-    where
-        E: StreamError<I::Item, I::Range>,
-    {
+    fn uncons_range(&mut self, size: usize) -> Result<I::Range, StreamErrorFor<Self>> {
         self.input.uncons_range(size).map(|range| {
             self.positioner.update_range(&range);
             range
@@ -262,10 +256,9 @@ where
     }
 
     #[inline]
-    fn uncons_while<E, F>(&mut self, mut predicate: F) -> Result<I::Range, E>
+    fn uncons_while<F>(&mut self, mut predicate: F) -> Result<I::Range, StreamErrorFor<Self>>
     where
         F: FnMut(I::Item) -> bool,
-        E: StreamError<I::Item, I::Range>,
     {
         let positioner = &mut self.positioner;
         self.input.uncons_while(|t| {


Test patch:
diff --git a/tests/async.rs b/tests/async.rs
index 6dd33ba4..a864340e 100644
--- a/tests/async.rs
+++ b/tests/async.rs
@@ -215,7 +215,7 @@ quickcheck! {
         assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
         assert_eq!(
             result.unwrap(),
-            ["a", "abcd", "", ":?a", "abcdefghij"],
+            ["a", "abcd", "", ":?a", "abcdefghij"]
         );
     }
 
@@ -233,7 +233,7 @@ quickcheck! {
         assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
         assert_eq!(
             result.unwrap(),
-            ["1", "abcd", "123", "abc", "1232751"],
+            ["1", "abcd", "123", "abc", "1232751"]
         );
     }
 
@@ -257,7 +257,7 @@ quickcheck! {
         assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
         assert_eq!(
             result.unwrap(),
-            ["1.0", "123.123", "17824", "3.14", "1.", "2"],
+            ["1.0", "123.123", "17824", "3.14", "1.", "2"]
         );
     }
 
@@ -282,7 +282,7 @@ quickcheck! {
         assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
         assert_eq!(
             result.unwrap(),
-            ["1.0", "123.123", "17824", "3.14", "1.", "2"],
+            ["1.0", "123.123", "17824", "3.14", "1.", "2"]
         );
     }
 
@@ -308,7 +308,7 @@ quickcheck! {
         assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
         assert_eq!(
             result.unwrap(),
-            ["1.0", "123.123", "17824", "3.14", "", "2"],
+            ["1.0", "123.123", "17824", "3.14", "", "2"]
         );
 
         assert_eq!(counter.get(), 26);
@@ -336,7 +336,7 @@ quickcheck! {
         assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
         assert_eq!(
             result.unwrap(),
-            ["1.0", "123.123", "17824", "3.14", "1.", "2"],
+            ["1.0", "123.123", "17824", "3.14", "1.", "2"]
         );
 
         assert_eq!(counter.get(), 28);
@@ -360,5 +360,5 @@ fn inner_no_partial_test() {
     let result = run_decoder(input, seq, TestParser::default());
 
     assert!(result.as_ref().is_ok(), "{}", result.unwrap_err());
-    assert_eq!(result.unwrap(), ["1", "abcd", "123", "abc", "1232751"],);
+    assert_eq!(result.unwrap(), ["1", "abcd", "123", "abc", "1232751"]);
 }
diff --git a/tests/buffered_stream.rs b/tests/buffered_stream.rs
index 71f4857b..0e7d0ff9 100644
--- a/tests/buffered_stream.rs
+++ b/tests/buffered_stream.rs
@@ -2,7 +2,7 @@
 extern crate combine;
 use combine::stream::IteratorStream;
 use combine::stream::buffered::BufferedStream;
-use combine::stream::easy::Error;
+use combine::stream::easy::{self, Error};
 use combine::parser::char::{char, digit, spaces, string};
 use combine::{choice, many, sep_by, try, Parser, Positioned, many1};
 use combine::stream::state::State;
@@ -46,7 +46,7 @@ fn shared_stream_insufficent_backtrack() {
     let text = "apple,apple,ananas,orangeblah";
     let mut iter = text.chars();
     // Iterator that can't be cloned
-    let stream = BufferedStream::new(State::new(IteratorStream::new(&mut iter)), 1);
+    let stream = BufferedStream::new(easy::Stream(State::new(IteratorStream::new(&mut iter))), 1);
 
     let value: &mut Parser<Input = _, Output = _, PartialState = _> = &mut choice([
         try(string("apple")),
@@ -54,14 +54,17 @@ fn shared_stream_insufficent_backtrack() {
         try(string("ananas")),
     ]);
     let mut parser = sep_by(value, char(','));
-    let result: Result<Vec<&str>, _> = parser.easy_parse(stream).map(|t| t.0);
+    let result: Result<Vec<&str>, _> = parser.parse(stream).map(|t| t.0);
     assert!(result.is_err());
     assert!(
         result
+            .as_ref()
             .unwrap_err()
             .errors
             .iter()
-            .any(|err| *err == Error::Message("Backtracked to far".into()))
+            .any(|err| *err == Error::Message("Backtracked to far".into())),
+        "{}",
+        result.unwrap_err()
     );
 }