Repository: Geal/nom (rust)

Issue:
parse_to! returns `ErrorKind::MapOpt`
Upon failure, `parse_to!` returns an error with `ErrorKind::MapOpt`. It would be better to return `ErrorKind::ParseTo` instead.

See PR https://github.com/Geal/nom/pull/747

Pull request description:
Fixes #752: Use a dedicate error kind for parse_to!
Upon failure, `parse_to!` returns an error with `ErrorKind::MapOpt`.
Return `ErrorKind::ParseTo` instead.

Reproduce with:
``` rust
use nom::{Context, Err, ErrorKind};

assert_eq!(
    Err::Error(Context::Code("ab", ErrorKind::MapOpt)),
    parse_to!("ab", usize).unwrap_err(),
)
```

Patch:
diff --git a/Cargo.toml b/Cargo.toml
index 7712935..7f5afe1 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -45,6 +45,10 @@ default-features = false
 #git = "https://github.com/carllerche/bytes"
 #rev = "a7d38e29"
 
+[package.metadata.docs.rs]
+features = [ "alloc", "std", "regexp", "regexp_macros", "verbose-errors" ]
+all-features = true
+
 [[test]]
 name = "arithmetic"
 
diff --git a/src/macros.rs b/src/macros.rs
index 7c1ec3a..66725e6 100644
--- a/src/macros.rs
+++ b/src/macros.rs
@@ -698,7 +698,7 @@ macro_rules! parse_to (
       let res: Option<$t> = ($i).parse_to();
       match res {
         Some(output) => Ok(($i.slice($i.input_len()..), output)),
-        None         => Err(Err::Error(Context::Code($i, ErrorKind::MapOpt::<u32>)))
+        None         => Err(Err::Error(Context::Code($i, ErrorKind::ParseTo::<u32>)))
       }
     }
   );
@@ -1543,4 +1543,19 @@ mod tests {
     );
     assert_eq!(test(&b"abcdefg"[..]), Ok((&b"fg"[..], &b"abcde"[..])));
   }
+
+  #[test]
+  fn parse_to() {
+    use util::Convert;
+
+    assert_eq!(
+      parse_to!("ab", usize),
+      Err(Err::Error(error_position!(
+        "ab",
+        ErrorKind::ParseTo
+      )))
+    );
+    assert_eq!(parse_to!("42", usize), Ok(("", 42)));
+    assert_eq!(ErrorKind::<u64>::convert(ErrorKind::ParseTo::<u32>), ErrorKind::ParseTo::<u64>);
+  }
 }
diff --git a/src/multi.rs b/src/multi.rs
index c6aed73..1c59d04 100644
--- a/src/multi.rs
+++ b/src/multi.rs
@@ -295,6 +295,7 @@ macro_rules! many0(
 /// # #[macro_use] extern crate nom;
 /// # use nom::Err;
 /// # use nom::ErrorKind;
+/// # use nom::types::CompleteByteSlice;
 /// # fn main() {
 ///  named!(multi<&[u8], Vec<&[u8]> >, many1!( tag!( "abcd" ) ) );
 ///
@@ -302,8 +303,13 @@ macro_rules! many0(
 ///  let b = b"azerty";
 ///
 ///  let res = vec![&b"abcd"[..], &b"abcd"[..]];
-///  assert_eq!(multi(&a[..]),Ok((&b"efgh"[..], res)));
+///  assert_eq!(multi(&a[..]), Ok((&b"efgh"[..], res)));
 ///  assert_eq!(multi(&b[..]), Err(Err::Error(error_position!(&b[..], ErrorKind::Many1))));
+///
+///  let c = CompleteByteSlice(b"abcdabcd");
+///
+///  let res = vec![CompleteByteSlice(b"abcd"), CompleteByteSlice(b"abcd")];
+///  assert_eq!(multi(c), Ok((CompleteByteSlice(b""), res)));
 /// # }
 /// ```
 #[cfg(feature = "alloc")]
@@ -926,7 +932,7 @@ macro_rules! fold_many1(
           }
 
           match failure {
-            $crate::lib::std::option::Option::Some(e) => Err(Err::Error(e)),
+            $crate::lib::std::option::Option::Some(e) => Err(Err::Failure(e)),
             $crate::lib::std::option::Option::None    => match incomplete {
               $crate::lib::std::option::Option::Some(i) => $crate::need_more($i, i),
               $crate::lib::std::option::Option::None    => Ok((input, acc))
diff --git a/src/nom.rs b/src/nom.rs
index 3f28dbe..01c6f03 100644
--- a/src/nom.rs
+++ b/src/nom.rs
@@ -584,28 +584,28 @@ pub enum Endianness {
 /// if the parameter is nom::Endianness::Big, parse a big endian u16 integer,
 /// otherwise a little endian u16 integer
 #[macro_export]
-macro_rules! u16 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { be_u16($i) } else { le_u16($i) } } ););
+macro_rules! u16 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_u16($i) } else { $crate::le_u16($i) } } ););
 /// if the parameter is nom::Endianness::Big, parse a big endian u32 integer,
 /// otherwise a little endian u32 integer
 #[macro_export]
-macro_rules! u32 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { be_u32($i) } else { le_u32($i) } } ););
+macro_rules! u32 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_u32($i) } else { $crate::le_u32($i) } } ););
 /// if the parameter is nom::Endianness::Big, parse a big endian u64 integer,
 /// otherwise a little endian u64 integer
 #[macro_export]
-macro_rules! u64 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { be_u64($i) } else { le_u64($i) } } ););
+macro_rules! u64 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_u64($i) } else { $crate::le_u64($i) } } ););
 
 /// if the parameter is nom::Endianness::Big, parse a big endian i16 integer,
 /// otherwise a little endian i16 integer
 #[macro_export]
-macro_rules! i16 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { be_i16($i) } else { le_i16($i) } } ););
+macro_rules! i16 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_i16($i) } else { $crate::le_i16($i) } } ););
 /// if the parameter is nom::Endianness::Big, parse a big endian i32 integer,
 /// otherwise a little endian i32 integer
 #[macro_export]
-macro_rules! i32 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { be_i32($i) } else { le_i32($i) } } ););
+macro_rules! i32 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_i32($i) } else { $crate::le_i32($i) } } ););
 /// if the parameter is nom::Endianness::Big, parse a big endian i64 integer,
 /// otherwise a little endian i64 integer
 #[macro_export]
-macro_rules! i64 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { be_i64($i) } else { le_i64($i) } } ););
+macro_rules! i64 ( ($i:expr, $e:expr) => ( {if $crate::Endianness::Big == $e { $crate::be_i64($i) } else { $crate::le_i64($i) } } ););
 
 /// Recognizes big endian 4 bytes floating point number
 #[inline]
@@ -695,6 +695,17 @@ where
   Ok((input.slice(input.input_len()..), input))
 }
 
+/// Return the length of the remaining input.
+#[inline]
+pub fn rest_len<T>(input: T) -> IResult<T, usize>
+where
+  T: Slice<Range<usize>> + Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
+  T: InputLength,
+{
+  let len = input.input_len();
+  Ok((input, len))
+}
+
 /// Return the remaining input, for strings.
 #[inline]
 pub fn rest_s(input: &str) -> IResult<&str, &str> {
@@ -1316,6 +1327,12 @@ mod tests {
     assert_eq!(rest(input), Ok((empty, input)));
   }
 
+  #[test]
+  fn rest_len_on_slices() {
+    let input: &[u8] = &b"Hello, world!"[..];
+    assert_eq!(rest_len(input), Ok((input, input.len())));
+  }
+
   #[test]
   fn configurable_endianness() {
     named!(be_tst16<u16>, u16!(Endianness::Big));
diff --git a/src/util.rs b/src/util.rs
index cc1a73d..e1a5a48 100644
--- a/src/util.rs
+++ b/src/util.rs
@@ -490,6 +490,7 @@ pub enum ErrorKind<E = u32> {
   TakeTill1,
   TakeUntilAndConsume1,
   TakeWhileMN,
+  ParseTo,
 }
 
 #[cfg_attr(rustfmt, rustfmt_skip)]
@@ -557,6 +558,7 @@ pub fn error_to_u32<E>(e: &ErrorKind<E>) -> u32 {
     ErrorKind::TakeTill1                 => 67,
     ErrorKind::TakeUntilAndConsume1      => 68,
     ErrorKind::TakeWhileMN               => 69,
+    ErrorKind::ParseTo                   => 70,
   }
 }
 
@@ -626,6 +628,7 @@ impl<E> ErrorKind<E> {
       ErrorKind::TakeTill1                 => "TakeTill1",
       ErrorKind::TakeUntilAndConsume1      => "Take at least 1 until and consume",
       ErrorKind::TakeWhileMN               => "TakeWhileMN",
+      ErrorKind::ParseTo                   => "Parse string to the specified type",
     }
   }
 
@@ -707,6 +710,7 @@ impl<F, E: From<F>> Convert<ErrorKind<F>> for ErrorKind<E> {
       ErrorKind::TakeTill1                 => ErrorKind::TakeTill1,
       ErrorKind::TakeUntilAndConsume1      => ErrorKind::TakeUntilAndConsume1,
       ErrorKind::TakeWhileMN               => ErrorKind::TakeWhileMN,
+      ErrorKind::ParseTo                   => ErrorKind::ParseTo,
     }
   }
 }


Test patch:
diff --git a/tests/issues.rs b/tests/issues.rs
index 8d4115e..588e54d 100644
--- a/tests/issues.rs
+++ b/tests/issues.rs
@@ -255,6 +255,14 @@ named!(issue_741_str<CompleteStr, CompleteStr>, re_match!(r"^_?[A-Za-z][0-9A-Z_a
 named!(issue_741_bytes<CompleteByteSlice, CompleteByteSlice>, re_bytes_match!(r"^_?[A-Za-z][0-9A-Z_a-z-]*"));
 
 
+#[test]
+fn issue_752() {
+    assert_eq!(
+        Err::Error(nom::Context::Code("ab", nom::ErrorKind::ParseTo)),
+        parse_to!("ab", usize).unwrap_err(),
+    )
+}
+
 fn atom_specials(c: u8) -> bool {
     c == b'q'
 }