Repository: Geal/nom
Pull request #1094 (2019-12-21 19:19:12)

Added example for an escaped string parser
Added a comprehensive example for how to parse a more complex escaped string. This parser supports regular escape sequences (`\n`, `\r`, `\t`) as well as rust-style escaped code points (`\u{1F602}`) and escaped whitespace (`\     `). Thoroughly commented.


Patch:
diff --git a/Cargo.toml b/Cargo.toml
index b458e18..361421b 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,7 +1,7 @@
 [package]
 
 name = "nom"
-version = "5.0.1"
+version = "5.1.0"
 authors = [ "contact@geoffroycouprie.com" ]
 description = "A byte-oriented, zero-copy, parser combinators library"
 license = "MIT"
@@ -46,7 +46,7 @@ version = "^2.0"
 default-features = false
 
 [dependencies.lexical-core]
-version = "^0.4.0"
+version = "^0.6.0"
 optional = true
 
 [dev-dependencies]
@@ -55,7 +55,7 @@ jemallocator = "^0.1"
 doc-comment = "0.3"
 
 [build-dependencies]
-version_check = "^0.1"
+version_check = "0.9"
 
 [package.metadata.docs.rs]
 features = [ "alloc", "std", "regexp", "regexp_macros", "lexical"]
@@ -169,6 +169,11 @@ name = "s_expression"
 path = "examples/s_expression.rs"
 required-features = ["alloc"]
 
+[[example]]
+name = "string"
+required-features = ["alloc"]
+path = "examples/string.rs"
+
 [badges]
 travis-ci = { repository = "Geal/nom" }
 coveralls = { repository = "Geal/nom", branch = "master", service = "github" }
diff --git a/README.md b/README.md
index a69e49d..6f28262 100644
--- a/README.md
+++ b/README.md
@@ -247,6 +247,7 @@ Here is a (non exhaustive) list of known projects using nom:
   * [libconfig-like configuration file format](https://github.com/filipegoncalves/rust-config)
   * [Web archive](https://github.com/sbeckeriv/warc_nom_parser)
   * [proto files](https://github.com/tafia/protobuf-parser)
+  * [Fountain screenplay markup](https://github.com/adamchalmers/fountain-rs)
 - Programming languages:
   * [PHP](https://github.com/tagua-vm/parser)
   * [Basic Calculator](https://github.com/balajisivaraman/basic_calculator_rs)
@@ -254,12 +255,14 @@ Here is a (non exhaustive) list of known projects using nom:
   * [Lua](https://github.com/doomrobo/nom-lua53)
   * [SQL](https://github.com/ms705/nom-sql)
   * [Elm](https://github.com/cout970/Elm-interpreter)
+  * [SystemVerilog](https://github.com/dalance/sv-parser)
 - Interface definition formats:
   * [Thrift](https://github.com/thehydroimpulse/thrust)
 - Audio, video and image formats:
   * [GIF](https://github.com/Geal/gif.rs)
   * [MagicaVoxel .vox](https://github.com/davidedmonds/dot_vox)
   * [midi](https://github.com/derekdreery/nom-midi-rs)
+  * [SWF](https://github.com/open-flash/swf-parser)
   * [WAVE](http://github.com/noise-Labs/wave)
 - Document formats:
   * [TAR](https://github.com/Keruspe/tar-parser.rs)
@@ -268,7 +271,7 @@ Here is a (non exhaustive) list of known projects using nom:
   * [Redis database files](https://github.com/badboy/rdb-rs)
 - Network protocol formats:
   * [Bencode](https://github.com/jbaum98/bencode.rs)
-  * [IMAP](https://github.com/djc/imap-proto)
+  * [IMAP](https://github.com/djc/tokio-imap)
   * [IRC](https://github.com/Detegr/RBot-parser)
   * [Pcap-NG](https://github.com/richo/pcapng-rs)
   * [Pcap](https://github.com/ithinuel/pcap-rs)
diff --git a/build.rs b/build.rs
index 994d7f9..9743c90 100644
--- a/build.rs
+++ b/build.rs
@@ -1,13 +1,7 @@
 extern crate version_check;
 
 fn main() {
-  match version_check::is_min_version("1.28.0") {
-    Some((true, _actual_version)) => {
-      println!("cargo:rustc-cfg=stable_i128");
-    }
-    Some(_) => (),
-    None => {
-      eprintln!("couldn't query version info from rustc");
-    }
+  if version_check::is_min_version("1.28.0").unwrap_or(true) {
+    println!("cargo:rustc-cfg=stable_i128");
   }
 }
diff --git a/doc/archive/upgrading_to_nom_4.md b/doc/archive/upgrading_to_nom_4.md
index 3c8fae1..092a48d 100644
--- a/doc/archive/upgrading_to_nom_4.md
+++ b/doc/archive/upgrading_to_nom_4.md
@@ -18,7 +18,7 @@ pub enum IResult<I,O,E=u32> {
   Done(I,O),
   /// indicates the parser encountered an error. E is a custom error type you can redefine
   Error(Err<E>),
-  /// Incomplete contains a Needed, an enum than can represent a known quantity of input data, or unknown
+  /// Incomplete contains a Needed, an enum that can represent a known quantity of input data, or unknown
   Incomplete(Needed)
 }
 
diff --git a/doc/choosing_a_combinator.md b/doc/choosing_a_combinator.md
index cc7f670..507b4b7 100644
--- a/doc/choosing_a_combinator.md
+++ b/doc/choosing_a_combinator.md
@@ -10,51 +10,50 @@ Those are used to recognize the lowest level elements of your grammar, like, "he
 
 | combinator | usage | input | output | comment |
 |---|---|---|---|---|
-| [char](https://docs.rs/nom/4.0.0/nom/macro.char.html) | `char!('a')` |  `"abc"` | `Ok(("bc", 'a'))`| matches one character (works with non ASCII chars too) | 
-| [is_a](https://docs.rs/nom/4.0.0/nom/macro.is_a.html) | ` is_a!("ab")` |  `"ababc"` | `Ok(("c", "abab"))`|matches a sequence of any of the characters passed as arguments|
-| [is_not](https://docs.rs/nom/4.0.0/nom/macro.is_not.html) |`is_not!("cd")` |  `"ababc"` | `Ok(("c", "abab"))`|matches a sequence of none of the characters passed as arguments|
-| [one_of](https://docs.rs/nom/4.0.0/nom/macro.one_of.html) |`one_of!("abc")` |  `"abc"` | `Ok(("bc", 'a'))`|matches one of the provided characters (works with non ASCII characters too)|
-| [none_of](https://docs.rs/nom/4.0.0/nom/macro.none_of.html) |`none_of!("abc")` |  `"xyab"` | `Ok(("yab", 'x'))`|matches anything but the provided characters|
-| [tag](https://docs.rs/nom/4.0.0/nom/macro.tag.html) |`tag!("hello")` |  `"hello world"` | `Ok((" world", "hello"))`|recognizes a specific suite of characters or bytes|
-| [tag_no_case](https://docs.rs/nom/4.0.0/nom/macro.tag_no_case.html) |`tag_no_case!("hello")` |  `"HeLLo World"` | `Ok((" World", "HeLLo"))`|case insensitive comparison. Note that case insensitive comparison is not well defined for unicode, and that you might have bad surprises|
-| [take](https://docs.rs/nom/4.0.0/nom/macro.take.html) |`take!(4)` |  `"hello"` | `Ok(("o", "hell"))`|takes a specific number of bytes or characters|
-| [take_while](https://docs.rs/nom/4.0.0/nom/macro.take_while.html) |`take_while!(is_alphabetic)` |  `"abc123"` | `Ok(("123", "abc"))`| returns the longest list of bytes for which the provided function returns true. `take_while1` does the same, but must return at least one character|
-| [take_till](https://docs.rs/nom/4.0.0/nom/macro.take_till.html) |`take_till!(is_alphabetic)` |  `"123abc"` | `Ok(("abc", "123))`|returns the longest list of bytes or characters until the provided function returns true. `take_till1` does the same, but must return at least one character. This is the reverse behaviour from `take_while`: `take_till!(f)` is equivalent to `take_while!(|c| !f(c))`|
-| [take_until](https://docs.rs/nom/4.0.0/nom/macro.take_until.html) | `take_until!("world")` |  `"Hello world"` | `Ok(("world", "Hello "))`|returns the longest list of bytes or characters until the provided tag is found. `take_until1` does the same, but must return at least one character|
+| [char](https://docs.rs/nom/latest/nom/macro.char.html) | `char!('a')` |  `"abc"` | `Ok(("bc", 'a'))`| matches one character (works with non ASCII chars too) | 
+| [is_a](https://docs.rs/nom/latest/nom/macro.is_a.html) | ` is_a!("ab")` |  `"ababc"` | `Ok(("c", "abab"))`|matches a sequence of any of the characters passed as arguments|
+| [is_not](https://docs.rs/nom/latest/nom/macro.is_not.html) |`is_not!("cd")` |  `"ababc"` | `Ok(("c", "abab"))`|matches a sequence of none of the characters passed as arguments|
+| [one_of](https://docs.rs/nom/latest/nom/macro.one_of.html) |`one_of!("abc")` |  `"abc"` | `Ok(("bc", 'a'))`|matches one of the provided characters (works with non ASCII characters too)|
+| [none_of](https://docs.rs/nom/latest/nom/macro.none_of.html) |`none_of!("abc")` |  `"xyab"` | `Ok(("yab", 'x'))`|matches anything but the provided characters|
+| [tag](https://docs.rs/nom/latest/nom/macro.tag.html) |`tag!("hello")` |  `"hello world"` | `Ok((" world", "hello"))`|recognizes a specific suite of characters or bytes|
+| [tag_no_case](https://docs.rs/nom/latest/nom/macro.tag_no_case.html) |`tag_no_case!("hello")` |  `"HeLLo World"` | `Ok((" World", "HeLLo"))`|case insensitive comparison. Note that case insensitive comparison is not well defined for unicode, and that you might have bad surprises|
+| [take](https://docs.rs/nom/latest/nom/macro.take.html) |`take!(4)` |  `"hello"` | `Ok(("o", "hell"))`|takes a specific number of bytes or characters|
+| [take_while](https://docs.rs/nom/latest/nom/macro.take_while.html) |`take_while!(is_alphabetic)` |  `"abc123"` | `Ok(("123", "abc"))`| returns the longest list of bytes for which the provided function returns true. `take_while1` does the same, but must return at least one character|
+| [take_till](https://docs.rs/nom/latest/nom/macro.take_till.html) |`take_till!(is_alphabetic)` |  `"123abc"` | `Ok(("abc", "123))`|returns the longest list of bytes or characters until the provided function returns true. `take_till1` does the same, but must return at least one character. This is the reverse behaviour from `take_while`: `take_till!(f)` is equivalent to `take_while!(|c| !f(c))`|
+| [take_until](https://docs.rs/nom/latest/nom/macro.take_until.html) | `take_until!("world")` |  `"Hello world"` | `Ok(("world", "Hello "))`|returns the longest list of bytes or characters until the provided tag is found. `take_until1` does the same, but must return at least one character|
 
 
 ## Choice combinators
 
 | combinator | usage | input | output | comment |
 |---|---|---|---|---|
-| [alt](https://docs.rs/nom/4.0.0/nom/macro.alt.html) |`alt!(tag!("ab") \| tag!("cd"))` |  `"cdef"` | `Ok( ("ef", "cd") )`|try a list of parsers and return the result of the first successful one|
-| [switch](https://docs.rs/nom/4.0.0/nom/macro.switch.html) |`switch!(take!(2), "ab" => tag!("XYZ") \| "cd" => tag!("123"))` |  `"cd1234"` | `Ok(("4", "123"))`|choose the next parser depending on the result of the first one, if successful, and returns the result of the second parser|
-| [permutation](https://docs.rs/nom/4.0.0/nom/macro.permutation.html) | `permutation!(tag!("ab"), tag!("cd"), tag!("12"))` |  `"cd12abc"` | `Ok( ("c", ("ab", "cd", "12") )`|succeeds when all its child parser have succeeded, whatever the order|
+| [alt](https://docs.rs/nom/latest/nom/macro.alt.html) |`alt!(tag!("ab") \| tag!("cd"))` |  `"cdef"` | `Ok( ("ef", "cd") )`|try a list of parsers and return the result of the first successful one|
+| [switch](https://docs.rs/nom/latest/nom/macro.switch.html) |`switch!(take!(2), "ab" => tag!("XYZ") \| "cd" => tag!("123"))` |  `"cd1234"` | `Ok(("4", "123"))`|choose the next parser depending on the result of the first one, if successful, and returns the result of the second parser|
+| [permutation](https://docs.rs/nom/latest/nom/macro.permutation.html) | `permutation!(tag!("ab"), tag!("cd"), tag!("12"))` |  `"cd12abc"` | `Ok( ("c", ("ab", "cd", "12") )`|succeeds when all its child parser have succeeded, whatever the order|
 
 ## Sequence combinators
 | combinator | usage | input | output | comment |
 |---|---|---|---|---|
-| [delimited](https://docs.rs/nom/4.0.0/nom/macro.delimited.html) |`delimited!(char!('('), take!(2), char!(')'))` |  `"(ab)cd"` | `Ok( ("cd", "ab") )`||
-| [preceded](https://docs.rs/nom/4.0.0/nom/macro.preceded.html) |`preceded!(tag!("ab"), tag!("XY"))` |  `"abXYZ"` | `Ok( ("Z", "XY") )`||
-| [terminated](https://docs.rs/nom/4.0.0/nom/macro.terminated.html) |`terminated!(tag!("ab"), tag!("XY"))` |  `"abXYZ"` | `Ok( ("Z", "ab") )`||
-| [pair](https://docs.rs/nom/4.0.0/nom/macro.pair.html) |`pair!(tag!("ab"), tag!("XY"))` |  `"abXYZ"` | `Ok( ("Z", ("ab", "XY")) )`||
-| [separated_pair](https://docs.rs/nom/4.0.0/nom/macro.separated_pair.html) |`separated_pair!(tag!("hello"), char!(','), tag!("world"))` |  `"hello,world!"` | `Ok( ("!", ("hello", "world")) )`||
-| [tuple](https://docs.rs/nom/4.0.0/nom/macro.tuple.html) |`tuple!(tag!("ab"), tag!("XY"), take!(1))` |  `"abXYZ!"` | `Ok( ("!", ("ab", "XY", "Z")) )`|chains parsers and assemble the sub results in a tuple. You can use as many child parsers as you can put elements in a tuple|
-| [do_parse](https://docs.rs/nom/4.0.0/nom/macro.do_parse.html) |`do_parse!(tag: take!(2) >> length: be_u8 >> data: take!(length) >> (Buffer { tag: tag, data: data}) )` |  `&[0, 0, 3, 1, 2, 3][..]` | `Buffer { tag: &[0, 0][..], data: &[1, 2, 3][..] }`|`do_parse` applies sub parsers in a sequence. it can store intermediary results and make them available for later parsers|
+| [delimited](https://docs.rs/nom/latest/nom/macro.delimited.html) |`delimited!(char!('('), take!(2), char!(')'))` |  `"(ab)cd"` | `Ok( ("cd", "ab") )`||
+| [preceded](https://docs.rs/nom/latest/nom/macro.preceded.html) |`preceded!(tag!("ab"), tag!("XY"))` |  `"abXYZ"` | `Ok( ("Z", "XY") )`||
+| [terminated](https://docs.rs/nom/latest/nom/macro.terminated.html) |`terminated!(tag!("ab"), tag!("XY"))` |  `"abXYZ"` | `Ok( ("Z", "ab") )`||
+| [pair](https://docs.rs/nom/latest/nom/macro.pair.html) |`pair!(tag!("ab"), tag!("XY"))` |  `"abXYZ"` | `Ok( ("Z", ("ab", "XY")) )`||
+| [separated_pair](https://docs.rs/nom/latest/nom/macro.separated_pair.html) |`separated_pair!(tag!("hello"), char!(','), tag!("world"))` |  `"hello,world!"` | `Ok( ("!", ("hello", "world")) )`||
+| [tuple](https://docs.rs/nom/latest/nom/macro.tuple.html) |`tuple!(tag!("ab"), tag!("XY"), take!(1))` |  `"abXYZ!"` | `Ok( ("!", ("ab", "XY", "Z")) )`|chains parsers and assemble the sub results in a tuple. You can use as many child parsers as you can put elements in a tuple|
+| [do_parse](https://docs.rs/nom/latest/nom/macro.do_parse.html) |`do_parse!(tag: take!(2) >> length: be_u8 >> data: take!(length) >> (Buffer { tag: tag, data: data}) )` |  `&[0, 0, 3, 1, 2, 3][..]` | `Buffer { tag: &[0, 0][..], data: &[1, 2, 3][..] }`|`do_parse` applies sub parsers in a sequence. it can store intermediary results and make them available for later parsers|
 
 ## Applying a parser multiple times
 
 | combinator | usage | input | output | comment |
 |---|---|---|---|---|
-| [count](https://docs.rs/nom/4.0.0/nom/macro.count.html) |`count!(take!(2), 3)` |  `"abcdefgh"` | `Ok( ("gh", vec!("ab", "cd", "ef")) )`|applies the child parser a specified number of times|
-| [count_fixed](https://docs.rs/nom/4.0.0/nom/macro.count_fixed.html) |`count_fixed!(&[u8], take!(2), 3)` |  `"abcdefgh"` | `Ok( ("gh", ["ab", "cd", "ef"]))`|applies the child parser a fixed number of times and returns a fixed size array. The type must be specified and it must be `Copy`|
-| [many0](https://docs.rs/nom/4.0.0/nom/macro.many0.html) |`many0!(tag!("ab"))` |  `"abababc"` | `Ok( ("c", vec!("ab", "ab", "ab")) )`|Applies the parser 0 or more times and returns the list of results in a Vec. `many1` does the same operation but must return at least one element|
-| [many_m_n](https://docs.rs/nom/4.0.0/nom/macro.many_m_n.html) |`many_m_n!(1, 3, tag!("ab"))` |  `"ababc"` | `Ok( ("c", vec!("ab", "ab")) )`|applies the parser between m and n times (n included) and returns the list of results in a Vec|
-| [many_till](https://docs.rs/nom/4.0.0/nom/macro.many_till.html) |`many_till!( tag!( "ab" ), tag!( "ef" ) )` |  `"ababefg"` | `Ok( ("g", (vec!("ab", "ab"), "ef")) )`|Applies the first parser until the second applies. Returns a tuple containing the list of results from the first in a Vec and the result of the second.|
-| [separated_list](https://docs.rs/nom/4.0.0/nom/macro.separated_list.html) |`separated_list!(tag!(","), tag!("ab"))` |  `"ab,ab,ab."` | `Ok( (".", vec!("ab", "ab", "ab")) )`|`separated_nonempty_list` works like `separated_list` but must returns at least one element|
-| [fold_many0](https://docs.rs/nom/4.0.0/nom/macro.fold_many0.html) |`fold_many0!(be_u8, 0, \|acc, item\| acc + item)` |  `[1, 2, 3]` | `Ok( ([], 6) )`|applies the parser 0 or more times and folds the list of return values. The `fold_many1` version must apply the child parser at least one time|
-| [fold_many_m_n](https://docs.rs/nom/4.0.0/nom/macro.fold_many_m_n.html) |`fold_many_m_n!(1, 2, be_u8, 0, \|acc, item\| acc + item)` |  `[1, 2, 3]` | `Ok( ([3], 3))`|applies the parser between m and n times (n included) and folds the list of return value|
-| [length_count](https://docs.rs/nom/4.0.0/nom/macro.length_count.html) |`length_count!(number, tag!("ab"))` |  `"2ababab"` | `Ok( ("ab", vec!("ab", "ab")) )`|gets a number from the first parser, then applies the second parser that many times|
+| [count](https://docs.rs/nom/latest/nom/macro.count.html) |`count!(take!(2), 3)` |  `"abcdefgh"` | `Ok( ("gh", vec!("ab", "cd", "ef")) )`|applies the child parser a specified number of times|
+| [many0](https://docs.rs/nom/latest/nom/macro.many0.html) |`many0!(tag!("ab"))` |  `"abababc"` | `Ok( ("c", vec!("ab", "ab", "ab")) )`|Applies the parser 0 or more times and returns the list of results in a Vec. `many1` does the same operation but must return at least one element|
+| [many_m_n](https://docs.rs/nom/latest/nom/macro.many_m_n.html) |`many_m_n!(1, 3, tag!("ab"))` |  `"ababc"` | `Ok( ("c", vec!("ab", "ab")) )`|applies the parser between m and n times (n included) and returns the list of results in a Vec|
+| [many_till](https://docs.rs/nom/latest/nom/macro.many_till.html) |`many_till!( tag!( "ab" ), tag!( "ef" ) )` |  `"ababefg"` | `Ok( ("g", (vec!("ab", "ab"), "ef")) )`|Applies the first parser until the second applies. Returns a tuple containing the list of results from the first in a Vec and the result of the second.|
+| [separated_list](https://docs.rs/nom/latest/nom/macro.separated_list.html) |`separated_list!(tag!(","), tag!("ab"))` |  `"ab,ab,ab."` | `Ok( (".", vec!("ab", "ab", "ab")) )`|`separated_nonempty_list` works like `separated_list` but must returns at least one element|
+| [fold_many0](https://docs.rs/nom/latest/nom/macro.fold_many0.html) |`fold_many0!(be_u8, 0, \|acc, item\| acc + item)` |  `[1, 2, 3]` | `Ok( ([], 6) )`|applies the parser 0 or more times and folds the list of return values. The `fold_many1` version must apply the child parser at least one time|
+| [fold_many_m_n](https://docs.rs/nom/latest/nom/macro.fold_many_m_n.html) |`fold_many_m_n!(1, 2, be_u8, 0, \|acc, item\| acc + item)` |  `[1, 2, 3]` | `Ok( ([3], 3))`|applies the parser between m and n times (n included) and folds the list of return value|
+| [length_count](https://docs.rs/nom/latest/nom/macro.length_count.html) |`length_count!(number, tag!("ab"))` |  `"2ababab"` | `Ok( ("ab", vec!("ab", "ab")) )`|gets a number from the first parser, then applies the second parser that many times|
 
 ## Integers
 
@@ -107,7 +106,7 @@ Parsing integers from binary formats can be done in two ways: with parser functi
 
 ## Binary format parsing
 
-- `length_data!`: gets a number from the first parser, than takes a subslice of the input of that size, and returns that subslice
+- `length_data!`: gets a number from the first parser, then takes a subslice of the input of that size, and returns that subslice
 - `length_bytes!`: alias for length_data
 - `length_value!`: gets a number from the first parser, takes a subslice of the input of that size, then applies the second parser on that subslice. If the second parser returns `Incomplete`, `length_value!` will return an error
 
diff --git a/doc/error_management.md b/doc/error_management.md
index 171cc10..3151fb3 100644
--- a/doc/error_management.md
+++ b/doc/error_management.md
@@ -8,13 +8,13 @@ This is done through the third type parameter of `IResult`, nom's parser result
 type:
 
 ```rust
-pub type IResult<I, O, E=(I,ErrorKind)> = Result<(I, O), Err<E>>;
+pub type IResult<I, O, E=(I, ErrorKind)> = Result<(I, O), Err<E>>;
 
 pub enum Err<E> {
-  Incomplete(Needed),
-  Error(E),
-  Failure(E),
-  }
+    Incomplete(Needed),
+    Error(E),
+    Failure(E),
+}
 ```
 
 This error type is completely generic in nom's combinators, so you can choose
@@ -35,21 +35,21 @@ combinators, defined as follows:
 
 ```rust
 pub trait ParseError<I>: Sized {
-  fn from_error_kind(input: I, kind: ErrorKind) -> Self;
+    fn from_error_kind(input: I, kind: ErrorKind) -> Self;
 
-  fn append(input: I, kind: ErrorKind, other: Self) -> Self;
+    fn append(input: I, kind: ErrorKind, other: Self) -> Self;
 
-  fn from_char(input: I, _: char) -> Self {
-    Self::from_error_kind(input, ErrorKind::Char)
-  }
+    fn from_char(input: I, _: char) -> Self {
+        Self::from_error_kind(input, ErrorKind::Char)
+    }
 
-  fn or(self, other: Self) -> Self {
-  other
-  }
+    fn or(self, other: Self) -> Self {
+        other
+    }
 
-  fn add_context(_input: I, _ctx: &'static str, other: Self) -> Self {
-    other
-  }
+    fn add_context(_input: I, _ctx: &'static str, other: Self) -> Self {
+        other
+    }
 }
 ```
 
@@ -98,7 +98,7 @@ error. Here is what it could return:
 
 ```rust
 fn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
-  dbg_dmp(tag("abcd"), "tag")(i)
+    dbg_dmp(tag("abcd"), "tag")(i)
 }
 
 let a = &b"efghijkl"[..];
@@ -119,28 +119,28 @@ You can go further with the [nom-trace crate](https://github.com/rust-bakery/nom
 declare_trace!();
 
 pub fn main() {
-  named!(parser<&str, Vec<&str>>,
-    //wrap a parser with tr!() to add a trace point
-    tr!(preceded!(
-      tr!(tag!("data: ")),
-      tr!(delimited!(
-        tag!("("),
-        separated_list!(
-          tr!(tag!(",")),
-          tr!(nom::digit)
-        ),
-        tr!(tag!(")"))
-      ))
-    ))
-  );
-
-  println!("parsed: {:?}", parser("data: (1,2,3)"));
-
-  // prints the last parser trace
-  print_trace!();
-
-  // the list of trace events can be cleared
-  reset_trace!();
+    named!(parser<&str, Vec<&str>>,
+        //wrap a parser with tr!() to add a trace point
+        tr!(preceded!(
+        tr!(tag!("data: ")),
+        tr!(delimited!(
+            tag!("("),
+            separated_list!(
+            tr!(tag!(",")),
+            tr!(nom::digit)
+            ),
+            tr!(tag!(")"))
+        ))
+        ))
+    );
+
+    println!("parsed: {:?}", parser("data: (1,2,3)"));
+
+    // prints the last parser trace
+    print_trace!();
+
+    // the list of trace events can be cleared
+    reset_trace!();
 }
 ```
 
diff --git a/doc/making_a_new_parser_from_scratch.md b/doc/making_a_new_parser_from_scratch.md
index 757980d..dd97562 100644
--- a/doc/making_a_new_parser_from_scratch.md
+++ b/doc/making_a_new_parser_from_scratch.md
@@ -189,7 +189,7 @@ this function wraps a parser that accepts a `&[u8]` as input and
 prints its hexdump if the child parser encountered an error:
 
 ```rust
-use nom::{util::dbg_dmp, bytes::complete::tag};
+use nom::{dbg_dmp, bytes::complete::tag};
 
 fn f(i: &[u8]) -> IResult<&[u8], &[u8]> {
   dbg_dmp(tag("abcd"))(i)
diff --git a/examples/json.rs b/examples/json.rs
index f703ad4..488e420 100644
--- a/examples/json.rs
+++ b/examples/json.rs
@@ -1,7 +1,7 @@
 #![cfg(feature = "alloc")]
 
-extern crate nom;
 extern crate jemallocator;
+extern crate nom;
 
 #[global_allocator]
 static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
@@ -10,8 +10,8 @@ use nom::{
   branch::alt,
   bytes::complete::{escaped, tag, take_while},
   character::complete::{alphanumeric1 as alphanumeric, char, one_of},
-  combinator::{map, opt, cut},
-  error::{context, convert_error, ErrorKind, ParseError,VerboseError},
+  combinator::{cut, map, opt, value},
+  error::{context, convert_error, ErrorKind, ParseError, VerboseError},
   multi::separated_list,
   number::complete::double,
   sequence::{delimited, preceded, separated_pair, terminated},
@@ -61,17 +61,26 @@ fn parse_str<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str
 
 /// `tag(string)` generates a parser that recognizes the argument string.
 ///
-/// we can combine it with other functions, like `map` that takes the result
-/// of another parser, and applies a function over it (`map` itself generates
-/// a new parser`.
+/// we can combine it with other functions, like `value` that takes another
+/// parser, and if that parser returns without an error, returns a given
+/// constant value.
 ///
 /// `alt` is another combinator that tries multiple parsers one by one, until
 /// one of them succeeds
+///
+/// `value` is a combinator that returns its value if the inner parser
 fn boolean<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, bool, E> {
-  alt((
-      map(tag("false"), |_| false),
-      map(tag("true"), |_| true)
-  ))(input)
+  // This is a parser that returns `true` if it sees the string "true", and
+  // an error otherwise
+  let parse_true = value(true, tag("true"));
+
+  // This is a parser that returns `true` if it sees the string "true", and
+  // an error otherwise
+  let parse_false = value(false, tag("false"));
+
+  // `alt` combines the two parsers. It returns the result of the first
+  // successful parser, or an error
+  alt((parse_true, parse_false))(input)
 }
 
 /// this parser combines the previous `parse_str` parser, that recognizes the
@@ -86,13 +95,7 @@ fn boolean<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, bool,
 /// - `context` lets you add a static string to provide more information in the
 /// error chain (to indicate which parser had an error)
 fn string<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E> {
-  context("string",
-    preceded(
-      char('\"'),
-      cut(terminated(
-          parse_str,
-          char('\"')
-  ))))(i)
+  context("string", preceded(char('\"'), cut(terminated(parse_str, char('\"')))))(i)
 }
 
 /// some combinators, like `separated_list` or `many0`, will call a parser repeatedly,
@@ -102,34 +105,37 @@ fn string<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, &'a str, E
 fn array<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, Vec<JsonValue>, E> {
   context(
     "array",
-    preceded(char('['),
-    cut(terminated(
-      separated_list(preceded(sp, char(',')), value),
-      preceded(sp, char(']'))))
-  ))(i)
+    preceded(
+      char('['),
+      cut(terminated(
+        separated_list(preceded(sp, char(',')), json_value),
+        preceded(sp, char(']')),
+      )),
+    ),
+  )(i)
 }
 
 fn key_value<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, (&'a str, JsonValue), E> {
-separated_pair(preceded(sp, string), cut(preceded(sp, char(':'))), value)(i)
+  separated_pair(preceded(sp, string), cut(preceded(sp, char(':'))), json_value)(i)
 }
 
 fn hash<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, HashMap<String, JsonValue>, E> {
   context(
     "map",
-    preceded(char('{'),
-    cut(terminated(
-      map(
-        separated_list(preceded(sp, char(',')), key_value),
-        |tuple_vec| {
+    preceded(
+      char('{'),
+      cut(terminated(
+        map(separated_list(preceded(sp, char(',')), key_value), |tuple_vec| {
           tuple_vec.into_iter().map(|(k, v)| (String::from(k), v)).collect()
-      }),
-      preceded(sp, char('}')),
-    ))
-  ))(i)
+        }),
+        preceded(sp, char('}')),
+      )),
+    ),
+  )(i)
 }
 
 /// here, we apply the space parser before trying to parse a value
-fn value<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, JsonValue, E> {
+fn json_value<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, JsonValue, E> {
   preceded(
     sp,
     alt((
@@ -144,11 +150,7 @@ fn value<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, JsonValue,
 
 /// the root element of a JSON parser is either an object or an array
 fn root<'a, E: ParseError<&'a str>>(i: &'a str) -> IResult<&'a str, JsonValue, E> {
-  delimited(
-    sp,
-    alt((map(hash, JsonValue::Object), map(array, JsonValue::Array))),
-    opt(sp),
-  )(i)
+  delimited(sp, alt((map(hash, JsonValue::Object), map(array, JsonValue::Array))), opt(sp))(i)
 }
 
 fn main() {
@@ -193,10 +195,7 @@ fn main() {
   //         ),
   //     ),
   // )
-  println!(
-    "parsing a valid file:\n{:#?}\n",
-    root::<(&str, ErrorKind)>(data)
-  );
+  println!("parsing a valid file:\n{:#?}\n", root::<(&str, ErrorKind)>(data));
 
   let data = "  { \"a\"\t: 42,
   \"b\": [ \"x\", \"y\", 12 ] ,
@@ -262,7 +261,6 @@ fn main() {
 
   match root::<VerboseError<&str>>(data) {
     Err(Err::Error(e)) | Err(Err::Failure(e)) => {
-
       // here we use the `convert_error` function, to transform a `VerboseError<&str>`
       // into a printable trace.
       //
@@ -282,6 +280,6 @@ fn main() {
       //   ^
       println!("verbose errors - `root::<VerboseError>(data)`:\n{}", convert_error(data, e));
     }
-    _ => {},
+    _ => {}
   }
 }
diff --git a/examples/s_expression.rs b/examples/s_expression.rs
index 09bef2b..a462e1c 100644
--- a/examples/s_expression.rs
+++ b/examples/s_expression.rs
@@ -347,7 +347,7 @@ fn main() {
   let expression_1 = "((if (= (+ 3 (/ 9 3))
          (* 2 3))
      *
-     /) 
+     /)
   456 123)";
   println!("\"{}\"\nevaled gives us: {:?}", expression_1, eval_from_str(expression_1));
 }
diff --git a/examples/string.rs b/examples/string.rs
new file mode 100644
index 0000000..3007ad6
--- /dev/null
+++ b/examples/string.rs
@@ -0,0 +1,178 @@
+//! This example shows an example of how to parse an escaped string. The
+//! rules for the string are similar to JSON and rust. A string is:
+//!
+//! - Enclosed by double quotes
+//! - Can contain any raw unescaped code point besides \ and "
+//! - Matches the following escape sequences: \b, \f, \n, \r, \t, \", \\, \/
+//! - Matches code points like Rust: \u{XXXX}, where XXXX can be up to 6
+//!   hex characters
+//! - an escape followed by whitespace consumes all whitespace between the
+//!   escape and the next non-whitespace character
+
+#![cfg(feature = "alloc")]
+
+extern crate jemallocator;
+extern crate nom;
+
+#[global_allocator]
+static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
+
+use nom::branch::alt;
+use nom::bytes::streaming::{is_not, take_while_m_n};
+use nom::character::streaming::{char, multispace1};
+use nom::combinator::{map, map_opt, map_res, value, verify};
+use nom::error::ParseError;
+use nom::multi::fold_many0;
+use nom::sequence::{delimited, preceded};
+use nom::IResult;
+
+// parser combinators are constructed from the bottom up:
+// first we write parsers for the smallest elements (escaped characters),
+// then combine them into larger parsers.
+
+/// Parse a unicode sequence, of the form u{XXXX}, where XXXX is 1 to 6
+/// hexadecimal numerals. We will combine this later with parse_escaped_char
+/// to parse sequences like \u{00AC}.
+fn parse_unicode<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, char, E> {
+  // `take_while_m_n` parses between `m` and `n` bytes (inclusive) that match
+  // a predicate. `parse_hex` here parses between 1 and 6 hexadecimal numerals.
+  let parse_hex = take_while_m_n(1, 6, |c: char| c.is_ascii_hexdigit());
+
+  // `preceeded` takes a prefix parser, and if it succeeds, returns the result
+  // of the body parser. In this case, it parses u{XXXX}.
+  let parse_delimited_hex = preceded(
+    char('u'),
+    // `delimited` is like `preceded`, but it parses both a prefix and a suffix.
+    // It returns the result of the middle parser. In this case, it parses
+    // {XXXX}, where XXXX is 1 to 6 hex numerals, and returns XXXX
+    delimited(char('{'), parse_hex, char('}')),
+  );
+
+  // `map_res` takes the result of a parser and applies a function that returns
+  // a Result. In this case we take the hex bytes from parse_hex and attempt to
+  // convert them to a u32.
+  let parse_u32 = map_res(parse_delimited_hex, move |hex| u32::from_str_radix(hex, 16));
+
+  // map_opt is like map_res, but it takes an Option instead of a Result. If
+  // the function returns None, map_opt returns an error. In this case, because
+  // not all u32 values are valid unicode code points, we have to fallibly
+  // convert to char with from_u32.
+  map_opt(parse_u32, |value| std::char::from_u32(value))(input)
+}
+
+/// Parse an escaped character: \n, \t, \r, \u{00AC}, etc.
+fn parse_escaped_char<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, char, E> {
+  preceded(
+    char('\\'),
+    // `alt` tries each each parser in sequence, returning the result of
+    // the first successful match
+    alt((
+      parse_unicode,
+      // The `value` parser returns a fixed value (the first argument) if its
+      // parser (the second argument) succeeds. In these cases, it looks for
+      // the marker characters (n, r, t, etc) and returns the matching
+      // character (\n, \r, \t, etc).
+      value('\n', char('n')),
+      value('\r', char('r')),
+      value('\t', char('t')),
+      value('\u{08}', char('b')),
+      value('\u{0C}', char('f')),
+      value('\\', char('\\')),
+      value('/', char('/')),
+      value('"', char('"')),
+    )),
+  )(input)
+}
+
+/// Parse a backslash, followed by any amount of whitespace. This is used later
+/// to discard any escaped whitespace.
+fn parse_escaped_whitespace<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, &'a str, E> {
+  preceded(char('\\'), multispace1)(input)
+}
+
+/// Parse a non-empty block of text that doesn't include \ or "
+fn parse_literal<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, &'a str, E> {
+  // `is_not` parses a string of 0 or more characters that aren't one of the
+  // given characters.
+  let not_quote_slash = is_not("\"\\");
+
+  // `verify` runs a parser, then runs a verification function on the output of
+  // the parser. The verification function accepts out output only if it
+  // returns true. In this case, we want to ensure that the output of is_not
+  // is non-empty.
+  verify(not_quote_slash, |s: &str| !s.is_empty())(input)
+}
+
+/// A string fragment contains a fragment of a string being parsed: either
+/// a non-empty Literal (a series of non-escaped characters), a single
+/// parsed escaped character, or a block of escaped whitespace.
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+enum StringFragment<'a> {
+  Literal(&'a str),
+  EscapedChar(char),
+  EscapedWS,
+}
+
+/// Combine parse_literal, parse_escaped_whitespace, and parse_escaped_char
+/// into a StringFragment.
+fn parse_fragment<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, StringFragment<'a>, E> {
+  alt((
+    // The `map` combinator runs a parser, then applies a function to the output
+    // of that parser.
+    map(parse_literal, StringFragment::Literal),
+    map(parse_escaped_char, StringFragment::EscapedChar),
+    value(StringFragment::EscapedWS, parse_escaped_whitespace),
+  ))(input)
+}
+
+/// Parse a string. Use a loop of parse_fragment and push all of the fragments
+/// into an output string.
+fn parse_string<'a, E: ParseError<&'a str>>(input: &'a str) -> IResult<&'a str, String, E> {
+  // fold_many0 is the equivalent of iterator::fold. It runs a parser in a loop,
+  // and for each output value, calls a folding function on each output value.
+  let build_string = fold_many0(
+    // Our parser function– parses a single string fragment
+    parse_fragment,
+    // Our init value, an empty string
+    String::new(),
+    // Our folding function. For each fragment, append the fragment to the
+    // string.
+    |mut string, fragment| {
+      match fragment {
+        StringFragment::Literal(s) => string.push_str(s),
+        StringFragment::EscapedChar(c) => string.push(c),
+        StringFragment::EscapedWS => {}
+      }
+      string
+    },
+  );
+
+  // Finally, parse the string. Note that, if `build_string` could accept a raw
+  // " character, the closing delimiter " would never match. When using
+  // `delimited` with a looping parser (like fold_many0), be sure that the
+  // loop won't accidentally match your closing delimiter!
+  delimited(char('"'), build_string, char('"'))(input)
+}
+
+fn main() {
+  let data = "\"abc\"";
+  println!("EXAMPLE 1:\nParsing a simple input string: {}", data);
+  let result = parse_string::<()>(data);
+  assert_eq!(result, Ok(("", String::from("abc"))));
+  println!("Result: {}\n\n", result.unwrap().1);
+
+  let data = "\"tab:\\tafter tab, newline:\\nnew line, quote: \\\", emoji: \\u{1F602}, newline:\\nescaped whitespace: \\    abc\"";
+  println!(
+    "EXAMPLE 2:\nParsing a string with escape sequences, newline literal, and escaped whitespace:\n\n{}\n",
+    data
+  );
+  let result = parse_string::<()>(data);
+  assert_eq!(
+    result,
+    Ok((
+      "",
+      String::from("tab:\tafter tab, newline:\nnew line, quote: \", emoji: 😂, newline:\nescaped whitespace: abc")
+    ))
+  );
+  println!("Result:\n\n{}", result.unwrap().1);
+}
diff --git a/src/bits/mod.rs b/src/bits/mod.rs
index dba0bf9..a6b12f1 100644
--- a/src/bits/mod.rs
+++ b/src/bits/mod.rs
@@ -23,10 +23,10 @@ use crate::traits::{Slice, ErrorConvert};
 /// # #[macro_use] extern crate nom;
 /// # use nom::IResult;
 /// use nom::bits::bits;
-/// use nom::bits::complete::take_bits;
+/// use nom::bits::complete::take;
 ///
 /// fn take_4_bits(input: &[u8]) -> IResult<&[u8], u64> {
-///   bits( take_bits(4usize) )(input)
+///   bits(take::<_, _, _, (_, _)>(4usize))(input)
 /// }
 ///
 /// let input = vec![0xAB, 0xCD, 0xEF, 0x12];
@@ -117,4 +117,3 @@ where
 {
   bytes(parser)(input)
 }
-
diff --git a/src/branch/mod.rs b/src/branch/mod.rs
index babb5f2..55d3633 100644
--- a/src/branch/mod.rs
+++ b/src/branch/mod.rs
@@ -107,7 +107,7 @@ macro_rules! alt_trait_impl(
     > Alt<Input, Output, Error> for ( $($id),+ ) {
 
       fn choice(&self, input: Input) -> IResult<Input, Output, Error> {
-        let mut err = None;
+        let mut err: Option<Error> = None;
         alt_trait_inner!(0, self, input, err, $($id)+);
 
         Err(Err::Error(Error::append(input, ErrorKind::Alt, err.unwrap())))
@@ -120,11 +120,10 @@ macro_rules! alt_trait_inner(
   ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident $($id:ident)+) => (
     match $self.$it($input.clone()) {
       Err(Err::Error(e)) => {
-        if $err.is_none() {
-          $err = Some(e);
-        } else {
-          $err = Some($err.unwrap().or(e));
-        }
+        $err = Some(match $err.take() {
+          None => e,
+          Some(prev) => prev.or(e),
+        });
         succ!($it, alt_trait_inner!($self, $input, $err, $($id)+))
       },
       res => return res,
@@ -133,11 +132,10 @@ macro_rules! alt_trait_inner(
   ($it:tt, $self:expr, $input:expr, $err:expr, $head:ident) => (
     match $self.$it($input.clone()) {
       Err(Err::Error(e)) => {
-        if $err.is_none() {
-          $err = Some(e);
-        } else {
-          $err = Some($err.unwrap().or(e));
-        }
+        $err = Some(match $err.take() {
+          None => e,
+          Some(prev) => prev.or(e),
+        });
       },
       res => return res,
     }
diff --git a/src/bytes/complete.rs b/src/bytes/complete.rs
index 7f98fee..8bf4220 100644
--- a/src/bytes/complete.rs
+++ b/src/bytes/complete.rs
@@ -276,8 +276,10 @@ where
       None => {
         let len = input.input_len();
         if len >= n {
-          let res: IResult<_, _, Error> = Ok(input.take_split(n));
-          res
+          match input.slice_index(n) {
+            Some(index) => Ok(input.take_split(index)),
+            None => Err(Err::Error(Error::from_error_kind(input, ErrorKind::TakeWhileMN)))
+          }
         } else {
           if len >= m && len <= n {
             let res: IResult<_, _, Error> = Ok((input.slice(len..), input));
@@ -637,3 +639,20 @@ where
   escaped_transform(normal, control_char, transform)(i)
 
 }
+
+#[cfg(test)]
+mod tests {
+  use super::*;
+
+  #[test]
+  fn complete_take_while_m_n_utf8_all_matching() {
+    let result: IResult<&str, &str> = super::take_while_m_n(1, 4, |c: char| c.is_alphabetic())("øn");
+    assert_eq!(result, Ok(("", "øn")));
+  }
+
+  #[test]
+  fn complete_take_while_m_n_utf8_all_matching_substring() {
+    let result: IResult<&str, &str> = super::take_while_m_n(1, 1, |c: char| c.is_alphabetic())("øn");
+    assert_eq!(result, Ok(("n", "ø")));
+  }
+}
diff --git a/src/bytes/macros.rs b/src/bytes/macros.rs
index f914f3e..1e24ba8 100644
--- a/src/bytes/macros.rs
+++ b/src/bytes/macros.rs
@@ -256,7 +256,7 @@ macro_rules! take_while1 (
 /// # #[macro_use] extern crate nom;
 /// # use nom::character::is_alphanumeric;
 /// # fn main() {
-///  named!( alpha, take_while!( is_alphanumeric ) );
+///  named!( alpha, take_while_m_n!(3, 6, is_alphanumeric ) );
 ///
 ///  let r = alpha(&b"abcd\nefgh"[..]);
 ///  assert_eq!(r, Ok((&b"\nefgh"[..], &b"abcd"[..])));
@@ -863,6 +863,12 @@ mod tests {
     assert_eq!(parser("😃!"), Ok(("!", "😃")));
   }
 
+  #[test]
+  fn take_while_m_n_utf8_full_match() {
+    named!(parser<&str, &str>, take_while_m_n!(1, 1, |c: char| c.is_alphabetic()));
+    assert_eq!(parser("øn"), Ok(("n", "ø")));
+  }
+
   #[cfg(nightly)]
   use test::Bencher;
 
diff --git a/src/bytes/streaming.rs b/src/bytes/streaming.rs
index 278cc3c..f6e6706 100644
--- a/src/bytes/streaming.rs
+++ b/src/bytes/streaming.rs
@@ -282,8 +282,10 @@ where
       None => {
         let len = input.input_len();
         if len >= n {
-          let res: IResult<_, _, Error> = Ok(input.take_split(n));
-          res
+          match input.slice_index(n) {
+            Some(index) => Ok(input.take_split(index)),
+            None => Err(Err::Error(Error::from_error_kind(input, ErrorKind::TakeWhileMN)))
+          }
         } else {
           let needed = if m > len { m - len } else { 1 };
           Err(Err::Incomplete(Needed::Size(needed)))
diff --git a/src/character/complete.rs b/src/character/complete.rs
index 1f3cd35..beddc3f 100644
--- a/src/character/complete.rs
+++ b/src/character/complete.rs
@@ -365,11 +365,22 @@ where
 }
 
 /// Recognizes zero or more ASCII numerical characters: 0-9
+///
+/// *complete version*: Will return an error if there's not enough input data,
+/// or the whole input if no terminating token is found (a non digit character).
+///
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::ErrorKind, IResult, Needed};
+/// # use nom::character::complete::digit0;
+/// # fn main() {
 /// fn parser(input: &str) -> IResult<&str, &str> {
 ///     digit0(input)
 /// }
 ///
 /// assert_eq!(parser("21c"), Ok(("c", "21")));
+/// assert_eq!(parser("21"), Ok(("", "21")));
 /// assert_eq!(parser("a21c"), Ok(("a21c", "")));
 /// assert_eq!(parser(""), Ok(("", "")));
 /// # }
diff --git a/src/combinator/mod.rs b/src/combinator/mod.rs
index 487fdd1..933bed8 100644
--- a/src/combinator/mod.rs
+++ b/src/combinator/mod.rs
@@ -811,7 +811,7 @@ mod tests {
       let input: &[u8] = &[3, 100, 101, 102, 103, 104][..];
       assert_parse!(flat_map(be_u8, take)(input), Ok((&[103, 104][..], &[100, 101, 102][..])));
   }
-  
+
   #[test]
   fn test_map_opt() {
       let input: &[u8] = &[50][..];
diff --git a/src/error.rs b/src/error.rs
index 91baa9f..612d4bd 100644
--- a/src/error.rs
+++ b/src/error.rs
@@ -11,7 +11,6 @@
 /// It provides methods to create an error from some combinators,
 /// and combine existing errors in combinators like `alt`
 pub trait ParseError<I>: Sized {
-
   /// creates an error from the input position and an [ErrorKind]
   fn from_error_kind(input: I, kind: ErrorKind) -> Self;
 
@@ -50,9 +49,9 @@ impl<I> ParseError<I> for (I, ErrorKind) {
 }
 
 impl<I> ParseError<I> for () {
-  fn from_error_kind(_: I, _: ErrorKind) -> Self { }
+  fn from_error_kind(_: I, _: ErrorKind) -> Self {}
 
-  fn append(_: I, _: ErrorKind, _: Self) -> Self { }
+  fn append(_: I, _: ErrorKind, _: Self) -> Self {}
 }
 
 /// creates an error from the input position and an [ErrorKind]
@@ -71,7 +70,7 @@ pub fn append_error<I, E: ParseError<I>>(input: I, kind: ErrorKind, other: E) ->
 /// through a parse tree. With some post processing (cf `examples/json.rs`),
 /// it can be used to display user friendly error messages
 #[cfg(feature = "alloc")]
-#[derive(Clone,Debug,PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 pub struct VerboseError<I> {
   /// list of errors accumulated by `VerboseError`, containing the affected
   /// part of input data, and some context
@@ -79,7 +78,7 @@ pub struct VerboseError<I> {
 }
 
 #[cfg(feature = "alloc")]
-#[derive(Clone,Debug,PartialEq)]
+#[derive(Clone, Debug, PartialEq)]
 /// error context for `VerboseError`
 pub enum VerboseErrorKind {
   /// static string added by the `context` function
@@ -94,7 +93,7 @@ pub enum VerboseErrorKind {
 impl<I> ParseError<I> for VerboseError<I> {
   fn from_error_kind(input: I, kind: ErrorKind) -> Self {
     VerboseError {
-      errors: vec![(input, VerboseErrorKind::Nom(kind))]
+      errors: vec![(input, VerboseErrorKind::Nom(kind))],
     }
   }
 
@@ -105,7 +104,7 @@ impl<I> ParseError<I> for VerboseError<I> {
 
   fn from_char(input: I, c: char) -> Self {
     VerboseError {
-      errors: vec![(input, VerboseErrorKind::Char(c))]
+      errors: vec![(input, VerboseErrorKind::Char(c))],
     }
   }
 
@@ -124,91 +123,108 @@ use crate::internal::{Err, IResult};
 #[cfg(feature = "alloc")]
 pub fn context<I: Clone, E: ParseError<I>, F, O>(context: &'static str, f: F) -> impl Fn(I) -> IResult<I, O, E>
 where
-  F: Fn(I) -> IResult<I, O, E> {
-
-    move |i: I| {
-      match f(i.clone()) {
-        Ok(o) => Ok(o),
-        Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)),
-        Err(Err::Error(e)) => Err(Err::Error(E::add_context(i, context, e))),
-        Err(Err::Failure(e)) => Err(Err::Failure(E::add_context(i, context, e))),
-      }
-    }
+  F: Fn(I) -> IResult<I, O, E>,
+{
+  move |i: I| match f(i.clone()) {
+    Ok(o) => Ok(o),
+    Err(Err::Incomplete(i)) => Err(Err::Incomplete(i)),
+    Err(Err::Error(e)) => Err(Err::Error(E::add_context(i, context, e))),
+    Err(Err::Failure(e)) => Err(Err::Failure(E::add_context(i, context, e))),
+  }
 }
 
 /// transforms a `VerboseError` into a trace with input position information
-#[cfg(feature="alloc")]
+#[cfg(feature = "alloc")]
 pub fn convert_error(input: &str, e: VerboseError<&str>) -> crate::lib::std::string::String {
-  use crate::{
-    lib::std:: iter::repeat,
-    traits::Offset
-  };
-
-  let lines: crate::lib::std::vec::Vec<_> = input.lines().map(crate::lib::std::string::String::from).collect();
+  use crate::lib::std::fmt::Write;
+  use crate::traits::Offset;
 
   let mut result = crate::lib::std::string::String::new();
 
   for (i, (substring, kind)) in e.errors.iter().enumerate() {
-    let mut offset = input.offset(substring);
+    let offset = input.offset(substring);
 
-    if lines.is_empty() {
+    if input.is_empty() {
       match kind {
-        VerboseErrorKind::Char(c) => {
-          result += &format!("{}: expected '{}', got empty input\n\n", i, c);
-        }
-        VerboseErrorKind::Context(s) => {
-          result += &format!("{}: in {}, got empty input\n\n", i, s);
-        },
-        VerboseErrorKind::Nom(e) => {
-          result += &format!("{}: in {:?}, got empty input\n\n", i, e);
-        }
+        VerboseErrorKind::Char(c) => write!(&mut result, "{}: expected '{}', got empty input\n\n", i, c),
+        VerboseErrorKind::Context(s) => write!(&mut result, "{}: in {}, got empty input\n\n", i, s),
+        VerboseErrorKind::Nom(e) => write!(&mut result, "{}: in {:?}, got empty input\n\n", i, e),
       }
     } else {
-      let mut line = 0;
-      let mut column = 0;
-
-      for (j, l) in lines.iter().enumerate() {
-        if offset <= l.len() {
-          line = j;
-          column = offset;
-          break;
-        } else {
-          offset = offset - l.len() - 1;
-        }
-      }
+      let prefix = &input.as_bytes()[..offset];
 
-      match kind {
-        VerboseErrorKind::Char(c) => {
-          result += &format!("{}: at line {}:\n", i, line);
-          result += &lines[line];
-          result += "\n";
+      // Count the number of newlines in the first `offset` bytes of input
+      let line_number = prefix.iter().filter(|&&b| b == b'\n').count() + 1;
 
-          if column > 0 {
-            result += &repeat(' ').take(column).collect::<crate::lib::std::string::String>();
-          }
-          result += "^\n";
-          result += &format!("expected '{}', found {}\n\n", c, substring.chars().next().unwrap());
-        }
-        VerboseErrorKind::Context(s) => {
-          result += &format!("{}: at line {}, in {}:\n", i, line, s);
-          result += &lines[line];
-          result += "\n";
-          if column > 0 {
-            result += &repeat(' ').take(column).collect::<crate::lib::std::string::String>();
-          }
-          result += "^\n\n";
+      // Find the line that includes the subslice:
+      // Find the *last* newline before the substring starts
+      let line_begin = prefix.iter().rev().position(|&b| b == b'\n').map(|pos| offset - pos).unwrap_or(0);
+
+      // Find the full line after that newline
+      let line = input[line_begin..].lines().next().unwrap_or(&input[line_begin..]).trim_end();
+
+      // The (1-indexed) column number is the offset of our substring into that line
+      let column_number = line.offset(substring) + 1;
+
+      match kind {
+        VerboseErrorKind::Char(c) => if let Some(actual) = substring.chars().next() {
+          write!(
+            &mut result,
+            "{i}: at line {line_number}:\n\
+               {line}\n\
+               {caret:>column$}\n\
+               expected '{expected}', found {actual}\n\n",
+            i = i,
+            line_number = line_number,
+            line = line,
+            caret = '^',
+            column = column_number,
+            expected = c,
+            actual = actual,
+          )
+        } else {
+          write!(
+            &mut result,
+            "{i}: at line {line_number}:\n\
+               {line}\n\
+               {caret:>column$}\n\
+               expected '{expected}', got end of input\n\n",
+            i = i,
+            line_number = line_number,
+            line = line,
+            caret = '^',
+            column = column_number,
+            expected = c,
+          )
         },
-        VerboseErrorKind::Nom(e) => {
-          result += &format!("{}: at line {}, in {:?}:\n", i, line, e);
-          result += &lines[line];
-          result += "\n";
-          if column > 0 {
-            result += &repeat(' ').take(column).collect::<crate::lib::std::string::String>();
-          }
-          result += "^\n\n";
-        }
+        VerboseErrorKind::Context(s) => write!(
+          &mut result,
+          "{i}: at line {line_number}, in {context}:\n\
+             {line}\n\
+             {caret:>column$}\n\n",
+          i = i,
+          line_number = line_number,
+          context = s,
+          line = line,
+          caret = '^',
+          column = column_number,
+        ),
+        VerboseErrorKind::Nom(e) => write!(
+          &mut result,
+          "{i}: at line {line_number}, in {nom_err:?}:\n\
+             {line}\n\
+             {caret:>column$}\n\n",
+          i = i,
+          line_number = line_number,
+          nom_err = e,
+          line = line,
+          caret = '^',
+          column = column_number,
+        ),
       }
     }
+    // Because `write!` to a `String` is infallible, this `unwrap` is fine.
+    .unwrap();
   }
 
   result
@@ -535,7 +551,6 @@ macro_rules! flat_map(
   );
 );
 
-
 #[cfg(test)]
 #[cfg(feature = "alloc")]
 mod tests {
diff --git a/src/internal.rs b/src/internal.rs
index e53e4c2..401f98a 100644
--- a/src/internal.rs
+++ b/src/internal.rs
@@ -73,18 +73,55 @@ impl<E> Err<E> {
     }
   }
 
+  /// Applies the given function to the inner error
+  pub fn map<E2, F>(self, f: F) -> Err<E2>
+    where F: FnOnce(E) -> E2
+  {
+    match self {
+      Err::Incomplete(n) => Err::Incomplete(n),
+      Err::Failure(t) => Err::Failure(f(t)),
+      Err::Error(t) => Err::Error(f(t)),
+    }
+  }
+
   /// automatically converts between errors if the underlying type supports it
   pub fn convert<F>(e: Err<F>) -> Self
-    where E: From<F> {
-    match e {
+    where E: From<F>
+  {
+    e.map(Into::into)
+  }
+}
+
+impl<T> Err<(T, ErrorKind)> {
+  /// maps `Err<(T, ErrorKind)>` to `Err<(U, ErrorKind)>` with the given F: T -> U
+  pub fn map_input<U, F>(self, f: F) -> Err<(U, ErrorKind)>
+    where F: FnOnce(T) -> U {
+    match self {
       Err::Incomplete(n) => Err::Incomplete(n),
-      Err::Failure(c) => Err::Failure(c.into()),
-      Err::Error(c) => Err::Error(c.into()),
+      Err::Failure((input, k)) => Err::Failure((f(input), k)),
+      Err::Error((input, k)) => Err::Error((f(input), k)),
     }
   }
 }
 
-/*
+#[cfg(feature = "std")]
+impl Err<(&[u8], ErrorKind)> {
+  /// Obtaining ownership
+  pub fn to_owned(self) -> Err<(Vec<u8>, ErrorKind)> {
+    self.map_input(ToOwned::to_owned)
+  }
+}
+
+#[cfg(feature = "std")]
+impl Err<(&str, ErrorKind)> {
+  /// automatically converts between errors if the underlying type supports it
+  pub fn to_owned(self) -> Err<(String, ErrorKind)> {
+    self.map_input(ToOwned::to_owned)
+  }
+}
+
+impl<E: Eq> Eq for Err<E> {}
+
 #[cfg(feature = "std")]
 use std::fmt;
 
@@ -94,7 +131,12 @@ where
   E: fmt::Debug,
 {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-    write!(f, "{:?}", self)
+    match self {
+      Err::Incomplete(Needed::Size(u)) => write!(f, "Parsing requires {} bytes/chars", u),
+      Err::Incomplete(Needed::Unknown) => write!(f, "Parsing requires more data"),
+      Err::Failure(c) => write!(f, "Parsing Failure: {:?}", c),
+      Err::Error(c) => write!(f, "Parsing Error: {:?}", c),
+    }
   }
 }
 
@@ -104,21 +146,12 @@ use std::error::Error;
 #[cfg(feature = "std")]
 impl<E> Error for Err<E>
 where
-  I: fmt::Debug,
   E: fmt::Debug,
 {
-  fn description(&self) -> &str {
-    match self {
-      &Err::Incomplete(..) => "there was not enough data",
-      &Err::Error(Context::Code(_, ref error_kind)) | &Err::Failure(Context::Code(_, ref error_kind)) => error_kind.description(),
-    }
-  }
-
-  fn cause(&self) -> Option<&Error> {
-    None
+  fn source(&self) -> Option<&(dyn Error + 'static)> {
+    None // no underlying error
   }
 }
-*/
 
 #[cfg(test)]
 mod tests {
@@ -143,4 +176,10 @@ mod tests {
     assert_size!(ErrorKind, 1);
   }
 
+  #[test]
+  fn err_map_test() {
+    let e = Err::Error(1);
+    assert_eq!(e.map(|v| v + 1), Err::Error(2));
+  }
+
 }
diff --git a/src/multi/macros.rs b/src/multi/macros.rs
index 4d884b4..10b66b8 100644
--- a/src/multi/macros.rs
+++ b/src/multi/macros.rs
@@ -356,8 +356,8 @@ macro_rules! length_count(
 
 /// `length_data!(I -> IResult<I, nb>) => O`
 ///
-/// `length_data` gets a number from the first parser, than takes a subslice of the input
-/// of that size, and returns that subslice
+/// `length_data` gets a number from the first parser, then takes a subslice of the input
+/// of that size and returns that subslice
 ///
 /// ```rust
 /// # #[macro_use] extern crate nom;
diff --git a/src/multi/mod.rs b/src/multi/mod.rs
index 7e86112..e8f26dd 100644
--- a/src/multi/mod.rs
+++ b/src/multi/mod.rs
@@ -367,7 +367,7 @@ where
               i = i2;
             }
           }
-        }  
+        }
       }
     }
   }
@@ -893,11 +893,10 @@ where
   fold_many_m_n(m, n, f, init, g)(i)
 }
 
-/// Gets a number from the first parser,
-/// takes a subslice of the input of that size,
-/// then applies the second parser on that subslice.
-/// If the second parser returns Incomplete,
-/// length_value will return an error.
+/// Gets a number from the parser and returns a
+/// subslice of the input of that size.
+/// If the parser returns Incomplete,
+/// length_data will return an error.
 /// # Arguments
 /// * `f` The parser to apply.
 /// ```rust
diff --git a/src/number/complete.rs b/src/number/complete.rs
index 28abfdc..b8d4232 100644
--- a/src/number/complete.rs
+++ b/src/number/complete.rs
@@ -832,16 +832,9 @@ pub fn float<T, E:ParseError<T>>(input: T) -> IResult<T, f32, E>
 where
   T: crate::traits::AsBytes + InputLength + Slice<RangeFrom<usize>>,
 {
-  let res = ::lexical_core::try_atof32_slice(input.as_bytes());
-
-  match res.error.code {
-    ::lexical_core::ErrorCode::Success => Ok((input.slice(input.input_len()..), res.value)),
-    ::lexical_core::ErrorCode::InvalidDigit => if res.error.index == 0 {
-      Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)))
-    } else {
-      Ok((input.slice(res.error.index..), res.value))
-    },
-    _ => Err(Err::Error(E::from_error_kind(input, ErrorKind::Float))),
+  match ::lexical_core::parse_partial(input.as_bytes()) {
+    Ok((value, processed)) => Ok((input.slice(processed..), value)),
+    Err(_) => Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)))
   }
 }
 
@@ -906,16 +899,9 @@ pub fn double<T, E:ParseError<T>>(input: T) -> IResult<T, f64, E>
 where
   T: crate::traits::AsBytes + InputLength + Slice<RangeFrom<usize>>,
 {
-  let res = ::lexical_core::try_atof64_slice(input.as_bytes());
-
-  match res.error.code {
-    ::lexical_core::ErrorCode::Success => Ok((input.slice(input.input_len()..), res.value)),
-    ::lexical_core::ErrorCode::InvalidDigit => if res.error.index == 0 {
-      Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)))
-    } else {
-      Ok((input.slice(res.error.index..), res.value))
-    },
-    _ => Err(Err::Error(E::from_error_kind(input, ErrorKind::Float))),
+  match ::lexical_core::parse_partial(input.as_bytes()) {
+    Ok((value, processed)) => Ok((input.slice(processed..), value)),
+    Err(_) => Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)))
   }
 }
 
diff --git a/src/number/streaming.rs b/src/number/streaming.rs
index 914578c..beaa7a6 100644
--- a/src/number/streaming.rs
+++ b/src/number/streaming.rs
@@ -113,7 +113,7 @@ pub fn be_u32<'a, E: ParseError<&'a[u8]>>(i: &'a[u8]) -> IResult<&'a[u8], u32, E
 /// Recognizes a big endian unsigned 8 bytes integer
 ///
 /// *streaming version*: will return `Err(nom::Err::Incomplete(_))` if there is not enough data
-/// 
+///
 /// ```rust
 /// # use nom::{Err, error::ErrorKind, Needed};
 /// # use nom::Needed::Size;
@@ -258,7 +258,7 @@ pub fn be_i32<'a, E: ParseError<&'a[u8]>>(i: &'a[u8]) -> IResult<&'a[u8], i32, E
 /// Recognizes a big endian signed 8 bytes integer
 ///
 /// *streaming version*: will return `Err(nom::Err::Incomplete(_))` if there is not enough data
-/// 
+///
 /// ```rust
 /// # use nom::{Err, error::ErrorKind, Needed};
 /// # use nom::Needed::Size;
@@ -829,18 +829,15 @@ pub fn float<T, E:ParseError<T>>(input: T) -> IResult<T, f32, E>
 where
   T: crate::traits::AsBytes + InputLength + Slice<RangeFrom<usize>>,
 {
-  let res = ::lexical_core::try_atof32_slice(input.as_bytes());
-
-  match res.error.code {
-    ::lexical_core::ErrorCode::Success => Err(Err::Incomplete(Needed::Unknown)),
-    ::lexical_core::ErrorCode::InvalidDigit => {
-      if res.error.index == 0 {
-        Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)))
+  match ::lexical_core::parse_partial(input.as_bytes()) {
+    Ok((value, processed)) => {
+      if (processed == input.input_len()) {
+        Err(Err::Incomplete(Needed::Unknown))
       } else {
-        Ok((input.slice(res.error.index..), res.value))
+        Ok((input.slice(processed..), value))
       }
     },
-    _ => Err(Err::Error(E::from_error_kind(input, ErrorKind::Float))),
+    Err(_) => Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)))
   }
 }
 
@@ -905,18 +902,15 @@ pub fn double<T, E:ParseError<T>>(input: T) -> IResult<T, f64, E>
 where
   T: crate::traits::AsBytes + InputLength + Slice<RangeFrom<usize>>,
 {
-  let res = ::lexical_core::try_atof64_slice(input.as_bytes());
-
-  match res.error.code {
-    ::lexical_core::ErrorCode::Success => Err(Err::Incomplete(Needed::Unknown)),
-    ::lexical_core::ErrorCode::InvalidDigit => {
-      if res.error.index == 0 {
-        Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)))
+  match ::lexical_core::parse_partial(input.as_bytes()) {
+    Ok((value, processed)) => {
+      if (processed == input.input_len()) {
+        Err(Err::Incomplete(Needed::Unknown))
       } else {
-        Ok((input.slice(res.error.index..), res.value))
+        Ok((input.slice(processed..), value))
       }
-    }
-    _ => Err(Err::Error(E::from_error_kind(input, ErrorKind::Float))),
+    },
+    Err(_) => Err(Err::Error(E::from_error_kind(input, ErrorKind::Float)))
   }
 }
 
diff --git a/src/traits.rs b/src/traits.rs
index 43f43c2..468c745 100644
--- a/src/traits.rs
+++ b/src/traits.rs
@@ -1109,22 +1109,26 @@ impl ExtendInto for char {
 /// with 32 and 64 bits pointer platforms
 pub trait ToUsize {
   /// converts self to usize
+  #[inline]
   fn to_usize(&self) -> usize;
 }
 
 impl ToUsize for u8 {
+  #[inline]
   fn to_usize(&self) -> usize {
     *self as usize
   }
 }
 
 impl ToUsize for u16 {
+  #[inline]
   fn to_usize(&self) -> usize {
     *self as usize
   }
 }
 
 impl ToUsize for usize {
+  #[inline]
   fn to_usize(&self) -> usize {
     *self
   }
@@ -1132,6 +1136,7 @@ impl ToUsize for usize {
 
 #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))]
 impl ToUsize for u32 {
+  #[inline]
   fn to_usize(&self) -> usize {
     *self as usize
   }
@@ -1139,6 +1144,7 @@ impl ToUsize for u32 {
 
 #[cfg(target_pointer_width = "64")]
 impl ToUsize for u64 {
+  #[inline]
   fn to_usize(&self) -> usize {
     *self as usize
   }


Test patch:
diff --git a/tests/issues.rs b/tests/issues.rs
index 094b47c..62a1a01 100644
--- a/tests/issues.rs
+++ b/tests/issues.rs
@@ -298,3 +298,21 @@ fn issue_many_m_n_with_zeros() {
     let parser = many_m_n::<_, _, (), _>(0, 0, char('a'));
     assert_eq!(parser("aaa"), Ok(("aaa", vec!())));
 }
+
+#[test]
+fn issue_1027_convert_error_panic_nonempty() {
+  use nom::error::{VerboseError, convert_error};
+  use nom::sequence::pair;
+  use nom::character::complete::char;
+
+  let input = "a";
+
+  let result: IResult<_, _, VerboseError<&str>> = pair(char('a'), char('b'))(input);
+  let err = match result.unwrap_err() {
+    Err::Error(e) => e,
+    _ => unreachable!(),
+  };
+
+  let msg = convert_error(&input, err);
+  assert_eq!(msg, "0: at line 1:\na\n ^\nexpected \'b\', got end of input\n\n");
+}