Repository: Marwes/combine (language: rust)

Issue:
take_until with tuple parser
I'm new to parser combinator so pardon if this is a naive question.
This works as expected:
`println!("{:?}", take_until::<String, _>(try(string("ab"))).easy_parse(r#"aaab"#)); // Ok(("aa", "ab"))`
But this behaves surprisingly:
`println!("{:?}", take_until::<String, _>(try((char('a'), char('b')))).easy_parse(r#"aaab"#)); // Ok(("aaa", "b"))`

I want to use tuple because the closing string is calculated at runtime. For example, to parse the closing "quote" of Rust raw string, I count the number of # in `r#"`, but
`take_until::<String, _>(try((char('"'), count_min_max::<String, _>(1, 1, char('#'))))).easy_parse("aa\"ab\"#")`
gives `aa\"ab\"` instead of `aa\"ab`


Discussion / hints:

Fix patch:
diff --git a/Cargo.toml b/Cargo.toml
index 041ac134..426d2ecc 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -35,6 +35,7 @@ lazy_static = "1.0"
 
 futures = "0.1"
 tokio-io = "0.1"
+tokio-codec = "0.1"
 partial-io = { version = "0.3", features = ["tokio", "quickcheck"] }
 bytes = "0.4"
 quickcheck = "0.6"
diff --git a/examples/async.rs b/examples/async.rs
index 1c7d287f..5e9c8e2d 100644
--- a/examples/async.rs
+++ b/examples/async.rs
@@ -5,6 +5,7 @@ extern crate combine;
 
 extern crate futures;
 extern crate partial_io;
+extern crate tokio_codec;
 extern crate tokio_io;
 
 use std::cell::Cell;
@@ -22,7 +23,7 @@ use combine::parser::byte::digit;
 use combine::parser::range::{range, recognize, take};
 use combine::stream::easy;
 use combine::stream::{PartialStream, RangeStream, StreamErrorFor};
-use combine::{skip_many, skip_many1, Parser};
+use combine::{skip_many, Parser, skip_many1};
 
 pub struct LanguageServerDecoder {
     state: AnyPartialState,
@@ -98,12 +99,11 @@ impl Decoder for LanguageServerDecoder {
             // Since err contains references into `src` we must replace these before
             // we can return an error or call `split_to` to remove the input we
             // just consumed
-            let err =
-                err.map_range(|r| {
-                    str::from_utf8(r)
-                        .ok()
-                        .map_or_else(|| format!("{:?}", r), |s| s.to_string())
-                }).map_position(|p| p.translate_position(&src[..]));
+            let err = err.map_range(|r| {
+                str::from_utf8(r)
+                    .ok()
+                    .map_or_else(|| format!("{:?}", r), |s| s.to_string())
+            }).map_position(|p| p.translate_position(&src[..]));
             format!("{}\nIn input: `{}`", err, str::from_utf8(src).unwrap())
         })?;
 
@@ -141,7 +141,7 @@ impl Decoder for LanguageServerDecoder {
 fn main() {
     use futures::{Future, Stream};
     use partial_io::{PartialAsyncRead, PartialOp};
-    use tokio_io::codec::FramedRead;
+    use tokio_codec::FramedRead;
 
     let input = "Content-Length: 6\r\n\
                  \r\n\
diff --git a/src/parser/choice.rs b/src/parser/choice.rs
index 0b9cab03..807d53b1 100644
--- a/src/parser/choice.rs
+++ b/src/parser/choice.rs
@@ -585,6 +585,31 @@ where
 /// If you are looking to chain 3 or more parsers using `or` you may consider using the
 /// [`choice!`] macro instead, which can be clearer and may result in a faster parser.
 ///
+/// ```
+/// # extern crate combine;
+/// # use combine::*;
+/// # use combine::parser::choice::or;
+/// # use combine::parser::char::{digit, string};
+/// # fn main() {
+/// let mut parser = or(
+///     string("let"),
+///     or(digit().map(|_| "digit"), string("led")),
+/// );
+/// assert_eq!(parser.parse("let"), Ok(("let", "")));
+/// assert_eq!(parser.parse("1"), Ok(("digit", "")));
+/// assert!(parser.parse("led").is_err());
+///
+/// let mut parser2 = or(string("two"), string("three"));
+/// // Fails as the parser for "two" consumes the first 't' before failing
+/// assert!(parser2.parse("three").is_err());
+///
+/// // Use 'try' to make failing parsers always act as if they have not consumed any input
+/// let mut parser3 = or(try(string("two")), try(string("three")));
+/// assert_eq!(parser3.parse("three"), Ok(("three", "")));
+/// # }
+/// ```
+///
+/// [`choice!`]: ../macro.choice.html
 /// [`p1.or(p2)`]: ../parser/trait.Parser.html#method.or
 #[inline(always)]
 pub fn or<P1, P2>(p1: P1, p2: P2) -> Or<P1, P2>
diff --git a/src/parser/repeat.rs b/src/parser/repeat.rs
index c39f1900..233eba7b 100644
--- a/src/parser/repeat.rs
+++ b/src/parser/repeat.rs
@@ -1205,7 +1205,7 @@ parser!{
     /// ```
     pub fn skip_until[P](end: P)(P::Input) -> ()
     where [
-        P: Parser
+        P: Parser,
     ]
     {
         take_until::<Sink<_>, _>(end).with(value(()))
diff --git a/src/parser/sequence.rs b/src/parser/sequence.rs
index 22b943db..cff2222c 100644
--- a/src/parser/sequence.rs
+++ b/src/parser/sequence.rs
@@ -140,7 +140,7 @@ macro_rules! tuple_parser {
                     }
                 }
 
-                if let None = state.$h.value {
+                if mode.is_first() || state.$h.value.is_none() {
                     let temp = match $h.parse_mode(mode, input, &mut state.$h.state) {
                         ConsumedOk(x) => {
                             first_empty_parser = current_parser + 1;
@@ -161,7 +161,7 @@ macro_rules! tuple_parser {
                 }
 
                 $(
-                    if let None = state.$id.value {
+                    if mode.is_first() || state.$id.value.is_none() {
                         current_parser += 1;
                         let before = input.checkpoint();
                         let temp = match $id.parse_mode(mode, input, &mut state.$id.state) {
@@ -608,8 +608,11 @@ where
             mode.set_first();
         }
 
-        let result = (self.1)(&mut n_parser_cache.as_mut().unwrap().1)
-            .parse_consumed_mode(mode, input, n_state);
+        let result = (self.1)(&mut n_parser_cache.as_mut().unwrap().1).parse_consumed_mode(
+            mode,
+            input,
+            n_state,
+        );
         match result {
             EmptyOk(x) => {
                 let (consumed, _) = *n_parser_cache.as_ref().unwrap();


Test patch:
diff --git a/tests/async.rs b/tests/async.rs
index 228dae22..5a22cca9 100644
--- a/tests/async.rs
+++ b/tests/async.rs
@@ -9,6 +9,7 @@ extern crate combine;
 
 extern crate futures;
 extern crate partial_io;
+extern crate tokio_codec;
 extern crate tokio_io;
 
 use std::cell::Cell;
@@ -19,19 +20,17 @@ use std::str;
 use bytes::BytesMut;
 
 use futures::{Future, Stream};
-use tokio_io::codec::FramedRead;
+use tokio_codec::{Decoder, FramedRead};
 
-use tokio_io::codec::Decoder;
-
-use combine::combinator::{
-    any_partial_state, no_partial, optional, recognize, skip_many1, try, AnyPartialState,
-};
+use combine::combinator::{any_partial_state, no_partial, optional, recognize, try,
+                          AnyPartialState, skip_many1};
 use combine::parser::char::{char, digit, letter};
 use combine::parser::item::item;
-use combine::parser::range::{range, recognize_with_value, take_while, take_while1, take_until_range};
+use combine::parser::range::{range, recognize_with_value, take_until_range, take_while,
+                             take_while1};
 use combine::parser::repeat;
 use combine::stream::{easy, RangeStream};
-use combine::{any, count_min_max, many1, skip_many, Parser};
+use combine::{any, count_min_max, skip_many, Parser, many1};
 
 quick_error! {
     #[derive(Debug)]
@@ -57,11 +56,9 @@ quick_error! {
 
 macro_rules! mk_parser {
     ($parser:expr, $self_:expr,()) => {
-
         $parser
     };
     ($parser:expr, $self_:expr,($custom_state:ty)) => {
-
         $parser($self_.1.clone())
     };
 }
diff --git a/tests/parser.rs b/tests/parser.rs
index ab6035cd..890a70b1 100644
--- a/tests/parser.rs
+++ b/tests/parser.rs
@@ -1,13 +1,13 @@
 extern crate combine;
 
+use combine::Parser;
 use combine::parser::char::{digit, letter};
 use combine::parser::choice::{choice, optional};
 use combine::parser::combinator::{no_partial, not_followed_by, try};
 use combine::parser::error::unexpected;
 use combine::parser::item::{any, eof, token, value, Token};
 use combine::parser::range::range;
-use combine::parser::repeat::{count_min_max, sep_by, sep_end_by1};
-use combine::Parser;
+use combine::parser::repeat::{count_min_max, sep_by, take_until, sep_end_by1};
 
 #[test]
 fn choice_empty() {
@@ -43,10 +43,10 @@ fn not_followed_by_does_not_consume_any_input() {
 #[cfg(feature = "std")]
 mod tests_std {
     use super::*;
+    use combine::Parser;
     use combine::parser::char::{char, digit, letter};
     use combine::stream::easy::{Error, Errors, ParseError};
     use combine::stream::state::{SourcePosition, State};
-    use combine::Parser;
 
     #[derive(Clone, PartialEq, Debug)]
     struct CloneOnly {
@@ -383,4 +383,12 @@ mod tests_std {
             Ok((vec![], "b"))
         );
     }
+
+    #[test]
+    fn sequence_parser_resets_partial_state_issue_168() {
+        assert_eq!(
+            take_until::<String, _>(try((char('a'), char('b')))).parse("aaab"),
+            Ok((String::from("aa"), "ab"))
+        );
+    }
 }