aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-02-24 18:24:23 +0000
committerAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2023-02-24 18:24:23 +0000
commitbc4d3761811322bd71d30843d30f394f7cf72e92 (patch)
treeed7817feac60eb8e640290f4edd26d76d8b9514b
parenta8171f087ffc781623889e922b30209cb2f69717 (diff)
parentd9eac1939674a4ff3fd957b5b2e9707f3bab3da0 (diff)
downloadnom-bc4d3761811322bd71d30843d30f394f7cf72e92.tar.gz
Snap for 9652768 from d9eac1939674a4ff3fd957b5b2e9707f3bab3da0 to simpleperf-release
Change-Id: I7449e694d59b6a85c78bcf6671bed3b7161d1b0b
-rw-r--r--.cargo_vcs_info.json2
-rw-r--r--Android.bp2
-rw-r--r--CHANGELOG.md71
-rw-r--r--Cargo.toml49
-rw-r--r--Cargo.toml.orig12
-rw-r--r--METADATA14
-rw-r--r--README.md22
-rw-r--r--TEST_MAPPING55
-rw-r--r--src/bits/complete.rs47
-rw-r--r--src/bits/mod.rs10
-rw-r--r--src/bits/streaming.rs41
-rw-r--r--src/branch/mod.rs24
-rw-r--r--src/character/complete.rs8
-rw-r--r--src/combinator/mod.rs53
-rw-r--r--src/internal.rs4
-rw-r--r--src/lib.rs7
-rw-r--r--src/macros.rs23
-rw-r--r--src/multi/mod.rs152
-rw-r--r--src/number/complete.rs78
-rw-r--r--src/number/streaming.rs76
-rw-r--r--src/sequence/mod.rs9
-rw-r--r--src/sequence/tests.rs18
-rw-r--r--src/traits.rs4
-rw-r--r--tests/issues.rs26
24 files changed, 565 insertions, 242 deletions
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 80b8de4..c356c32 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "294ffb3d9e0ade2c3b7ddfff52484b6d643dcce1"
+ "sha1": "869f8972a4383b13cf89574fda28cb7dbfd56517"
},
"path_in_vcs": ""
} \ No newline at end of file
diff --git a/Android.bp b/Android.bp
index cbd679a..809b68b 100644
--- a/Android.bp
+++ b/Android.bp
@@ -23,7 +23,7 @@ rust_library {
host_supported: true,
crate_name: "nom",
cargo_env_compat: true,
- cargo_pkg_version: "7.1.1",
+ cargo_pkg_version: "7.1.3",
srcs: ["src/lib.rs"],
edition: "2018",
features: [
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 56709ea..a8f4c02 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -6,6 +6,71 @@
### Changed
+## 7.1.3 - 2023-01-15
+
+### Thanks
+
+- @Shadow53
+
+### Fixed
+
+- panic in `many` and `count` combinators when the output type is zero sized
+
+## 7.1.2 - 2023-01-01
+
+### Thanks
+
+- @joubs
+- @Fyko
+- @LoganDark
+- @darnuria
+- @jkugelman
+- @barower
+- @puzzlewolf
+- @epage
+- @cky
+- @wolthom
+- @w1ll-i-code
+
+### Changed
+
+- documentation fixes
+- tests fixes
+- limit the initial capacity of the result vector of `many_m_n` to 64kiB
+- bits parser now accept `Parser` implementors instead of only functions
+
+### Added
+
+- implement `Tuple` parsing for the unit type as a special case
+- implement `ErrorConvert` on the unit type to make it usable as error type for bits parsers
+- bool parser for bits input
+
+## 7.1.1 - 2022-03-14
+
+### Thanks
+
+- @ThomasdenH
+- @@SphinxKnight
+- @irevoire
+- @doehyunbaek
+- @pxeger
+- @punkeel
+- @max-sixty
+- @Xiretza
+- @5c077m4n
+- @erihsu
+- @TheNeikos
+- @LoganDark
+- @nickelc
+- @chotchki
+- @ctrlcctrlv
+
+
+### Changed
+
+- documentation fixes
+- more examples
+
## 7.1.0 - 2021-11-04
### Thanks
@@ -1420,7 +1485,11 @@ Considering the number of changes since the last release, this version can conta
## Compare code
-* [unreleased](https://github.com/Geal/nom/compare/7.0.0...HEAD)
+* [unreleased](https://github.com/Geal/nom/compare/7.1.3...HEAD)
+* [7.1.2](https://github.com/Geal/nom/compare/7.1.2...7.1.3)
+* [7.1.2](https://github.com/Geal/nom/compare/7.1.1...7.1.2)
+* [7.1.1](https://github.com/Geal/nom/compare/7.1.0...7.1.1)
+* [7.1.0](https://github.com/Geal/nom/compare/7.0.0...7.1.0)
* [7.0.0](https://github.com/Geal/nom/compare/6.2.1...7.0.0)
* [6.2.1](https://github.com/Geal/nom/compare/6.2.0...6.2.1)
* [6.2.0](https://github.com/Geal/nom/compare/6.1.2...6.2.0)
diff --git a/Cargo.toml b/Cargo.toml
index 5096d4e..2388b4c 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,31 +13,63 @@
edition = "2018"
rust-version = "1.48"
name = "nom"
-version = "7.1.1"
+version = "7.1.3"
authors = ["contact@geoffroycouprie.com"]
-include = ["CHANGELOG.md", "LICENSE", "README.md", ".gitignore", "Cargo.toml", "src/*.rs", "src/*/*.rs", "tests/*.rs", "doc/nom_recipes.md"]
+include = [
+ "CHANGELOG.md",
+ "LICENSE",
+ "README.md",
+ ".gitignore",
+ "Cargo.toml",
+ "src/*.rs",
+ "src/*/*.rs",
+ "tests/*.rs",
+ "doc/nom_recipes.md",
+]
autoexamples = false
description = "A byte-oriented, zero-copy, parser combinators library"
documentation = "https://docs.rs/nom"
readme = "README.md"
-keywords = ["parser", "parser-combinators", "parsing", "streaming", "bit"]
+keywords = [
+ "parser",
+ "parser-combinators",
+ "parsing",
+ "streaming",
+ "bit",
+]
categories = ["parsing"]
license = "MIT"
repository = "https://github.com/Geal/nom"
+
[package.metadata.docs.rs]
+features = [
+ "alloc",
+ "std",
+ "docsrs",
+]
all-features = true
-features = ["alloc", "std", "docsrs"]
+
[profile.bench]
lto = true
codegen-units = 1
debug = true
[[example]]
+name = "custom_error"
+path = "examples/custom_error.rs"
+required-features = ["alloc"]
+
+[[example]]
name = "json"
path = "examples/json.rs"
required-features = ["alloc"]
[[example]]
+name = "json_iterator"
+path = "examples/json_iterator.rs"
+required-features = ["alloc"]
+
+[[example]]
name = "iterator"
path = "examples/iterator.rs"
@@ -99,6 +131,7 @@ name = "reborrow_fold"
[[test]]
name = "fnmut"
required-features = ["alloc"]
+
[dependencies.memchr]
version = "2.3"
default-features = false
@@ -106,6 +139,7 @@ default-features = false
[dependencies.minimal-lexical]
version = "0.2.0"
default-features = false
+
[dev-dependencies.doc-comment]
version = "0.3"
@@ -116,7 +150,12 @@ version = "1.0.0"
alloc = []
default = ["std"]
docsrs = []
-std = ["alloc", "memchr/std", "minimal-lexical/std"]
+std = [
+ "alloc",
+ "memchr/std",
+ "minimal-lexical/std",
+]
+
[badges.coveralls]
branch = "main"
repository = "Geal/nom"
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 37066f6..c01eeba 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,7 +1,7 @@
[package]
name = "nom"
-version = "7.1.1"
+version = "7.1.3"
authors = [ "contact@geoffroycouprie.com" ]
description = "A byte-oriented, zero-copy, parser combinators library"
license = "MIT"
@@ -105,11 +105,21 @@ name = "fnmut"
required-features = ["alloc"]
[[example]]
+name = "custom_error"
+required-features = ["alloc"]
+path = "examples/custom_error.rs"
+
+[[example]]
name = "json"
required-features = ["alloc"]
path = "examples/json.rs"
[[example]]
+name = "json_iterator"
+required-features = ["alloc"]
+path = "examples/json_iterator.rs"
+
+[[example]]
name = "iterator"
path = "examples/iterator.rs"
diff --git a/METADATA b/METADATA
index b5142c7..e948955 100644
--- a/METADATA
+++ b/METADATA
@@ -1,3 +1,7 @@
+# This project was upgraded with external_updater.
+# Usage: tools/external_updater/updater.sh update rust/crates/nom
+# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md
+
name: "nom"
description: "A byte-oriented, zero-copy, parser combinators library"
third_party {
@@ -7,13 +11,13 @@ third_party {
}
url {
type: ARCHIVE
- value: "https://static.crates.io/crates/nom/nom-7.1.1.crate"
+ value: "https://static.crates.io/crates/nom/nom-7.1.3.crate"
}
- version: "7.1.1"
+ version: "7.1.3"
license_type: NOTICE
last_upgrade_date {
- year: 2022
- month: 6
- day: 27
+ year: 2023
+ month: 2
+ day: 3
}
}
diff --git a/README.md b/README.md
index d429164..f2c1b05 100644
--- a/README.md
+++ b/README.md
@@ -17,6 +17,25 @@ error prone plumbing.
*nom will happily take a byte out of your files :)*
+<!-- toc -->
+
+- [Example](#example)
+- [Documentation](#documentation)
+- [Why use nom?](#why-use-nom)
+ - [Binary format parsers](#binary-format-parsers)
+ - [Text format parsers](#text-format-parsers)
+ - [Programming language parsers](#programming-language-parsers)
+ - [Streaming formats](#streaming-formats)
+- [Parser combinators](#parser-combinators)
+- [Technical features](#technical-features)
+- [Rust version requirements](#rust-version-requirements-msrv)
+- [Installation](#installation)
+- [Related projects](#related-projects)
+- [Parsers written with nom](#parsers-written-with-nom)
+- [Contributors](#contributors)
+
+<!-- tocstop -->
+
## Example
[Hexadecimal color](https://developer.mozilla.org/en-US/docs/Web/CSS/color) parser:
@@ -296,7 +315,8 @@ Here is a (non exhaustive) list of known projects using nom:
[Telcordia/Bellcore SR-4731 SOR OTDR files](https://github.com/JamesHarrison/otdrs),
[MySQL binary log](https://github.com/PrivateRookie/boxercrab),
[URI](https://github.com/Skasselbard/nom-uri),
-[Furigana](https://github.com/sachaarbonel/furigana.rs)
+[Furigana](https://github.com/sachaarbonel/furigana.rs),
+[Wordle Result](https://github.com/Fyko/wordle-stats/tree/main/parser)
Want to create a new parser using `nom`? A list of not yet implemented formats is available [here](https://github.com/Geal/nom/issues/14).
diff --git a/TEST_MAPPING b/TEST_MAPPING
index 88c552c..f441b9c 100644
--- a/TEST_MAPPING
+++ b/TEST_MAPPING
@@ -9,64 +9,15 @@
},
{
"path": "external/rust/crates/rusticata-macros"
- }
- ],
- "presubmit": [
- {
- "name": "apkdmverity.test"
- },
- {
- "name": "keystore2_legacy_blobs_test"
- },
- {
- "name": "keystore2_test"
- },
- {
- "name": "legacykeystore_test"
- },
- {
- "name": "libapkverify.integration_test"
- },
- {
- "name": "libapkverify.test"
- },
- {
- "name": "libidsig.test"
- },
- {
- "name": "microdroid_manager_test"
- },
- {
- "name": "virtualizationservice_device_test"
- }
- ],
- "presubmit-rust": [
- {
- "name": "apkdmverity.test"
- },
- {
- "name": "keystore2_legacy_blobs_test"
- },
- {
- "name": "keystore2_test"
- },
- {
- "name": "legacykeystore_test"
- },
- {
- "name": "libapkverify.integration_test"
- },
- {
- "name": "libapkverify.test"
},
{
- "name": "libidsig.test"
+ "path": "packages/modules/Virtualization/virtualizationmanager"
},
{
- "name": "microdroid_manager_test"
+ "path": "system/security/keystore2"
},
{
- "name": "virtualizationservice_device_test"
+ "path": "system/security/keystore2/legacykeystore"
}
]
}
diff --git a/src/bits/complete.rs b/src/bits/complete.rs
index b46bc7a..bf36dcc 100644
--- a/src/bits/complete.rs
+++ b/src/bits/complete.rs
@@ -105,6 +105,29 @@ where
}
}
+/// Parses one specific bit as a bool.
+///
+/// # Example
+/// ```rust
+/// # use nom::bits::complete::bool;
+/// # use nom::IResult;
+/// # use nom::error::{Error, ErrorKind};
+///
+/// fn parse(input: (&[u8], usize)) -> IResult<(&[u8], usize), bool> {
+/// bool(input)
+/// }
+///
+/// assert_eq!(parse(([0b10000000].as_ref(), 0)), Ok((([0b10000000].as_ref(), 1), true)));
+/// assert_eq!(parse(([0b10000000].as_ref(), 1)), Ok((([0b10000000].as_ref(), 2), false)));
+/// ```
+pub fn bool<I, E: ParseError<(I, usize)>>(input: (I, usize)) -> IResult<(I, usize), bool, E>
+where
+ I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
+{
+ let (res, bit): (_, u32) = take(1usize)(input)?;
+ Ok((res, bit != 0))
+}
+
#[cfg(test)]
mod test {
use super::*;
@@ -147,4 +170,28 @@ mod test {
Ok((([0b11111111].as_ref(), 4), 0b1000110100111111111111))
);
}
+
+ #[test]
+ fn test_bool_0() {
+ let input = [0b10000000].as_ref();
+
+ let result: crate::IResult<(&[u8], usize), bool> = bool((input, 0));
+
+ assert_eq!(result, Ok(((input, 1), true)));
+ }
+
+ #[test]
+ fn test_bool_eof() {
+ let input = [0b10000000].as_ref();
+
+ let result: crate::IResult<(&[u8], usize), bool> = bool((input, 8));
+
+ assert_eq!(
+ result,
+ Err(crate::Err::Error(crate::error::Error {
+ input: (input, 8),
+ code: ErrorKind::Eof
+ }))
+ );
+ }
}
diff --git a/src/bits/mod.rs b/src/bits/mod.rs
index 235b797..0d3f73d 100644
--- a/src/bits/mod.rs
+++ b/src/bits/mod.rs
@@ -5,7 +5,7 @@ pub mod complete;
pub mod streaming;
use crate::error::{ErrorKind, ParseError};
-use crate::internal::{Err, IResult, Needed};
+use crate::internal::{Err, IResult, Needed, Parser};
use crate::lib::std::ops::RangeFrom;
use crate::traits::{ErrorConvert, Slice};
@@ -42,9 +42,9 @@ where
E1: ParseError<(I, usize)> + ErrorConvert<E2>,
E2: ParseError<I>,
I: Slice<RangeFrom<usize>>,
- P: FnMut((I, usize)) -> IResult<(I, usize), O, E1>,
+ P: Parser<(I, usize), O, E1>,
{
- move |input: I| match parser((input, 0)) {
+ move |input: I| match parser.parse((input, 0)) {
Ok(((rest, offset), result)) => {
// If the next byte has been partially read, it will be sliced away as well.
// The parser functions might already slice away all fully read bytes.
@@ -88,7 +88,7 @@ where
E1: ParseError<I> + ErrorConvert<E2>,
E2: ParseError<(I, usize)>,
I: Slice<RangeFrom<usize>> + Clone,
- P: FnMut(I) -> IResult<I, O, E1>,
+ P: Parser<I, O, E1>,
{
move |(input, offset): (I, usize)| {
let inner = if offset % 8 != 0 {
@@ -97,7 +97,7 @@ where
input.slice((offset / 8)..)
};
let i = (input, offset);
- match parser(inner) {
+ match parser.parse(inner) {
Ok((rest, res)) => Ok(((rest, 0), res)),
Err(Err::Incomplete(Needed::Unknown)) => Err(Err::Incomplete(Needed::Unknown)),
Err(Err::Incomplete(Needed::Size(sz))) => Err(match sz.get().checked_mul(8) {
diff --git a/src/bits/streaming.rs b/src/bits/streaming.rs
index e8adc1c..a7c8d0a 100644
--- a/src/bits/streaming.rs
+++ b/src/bits/streaming.rs
@@ -79,6 +79,29 @@ where
}
}
+/// Parses one specific bit as a bool.
+///
+/// # Example
+/// ```rust
+/// # use nom::bits::complete::bool;
+/// # use nom::IResult;
+/// # use nom::error::{Error, ErrorKind};
+///
+/// fn parse(input: (&[u8], usize)) -> IResult<(&[u8], usize), bool> {
+/// bool(input)
+/// }
+///
+/// assert_eq!(parse(([0b10000000].as_ref(), 0)), Ok((([0b10000000].as_ref(), 1), true)));
+/// assert_eq!(parse(([0b10000000].as_ref(), 1)), Ok((([0b10000000].as_ref(), 2), false)));
+/// ```
+pub fn bool<I, E: ParseError<(I, usize)>>(input: (I, usize)) -> IResult<(I, usize), bool, E>
+where
+ I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
+{
+ let (res, bit): (_, u32) = take(1usize)(input)?;
+ Ok((res, bit != 0))
+}
+
#[cfg(test)]
mod test {
use super::*;
@@ -126,4 +149,22 @@ mod test {
}))
);
}
+
+ #[test]
+ fn test_bool_0() {
+ let input = [0b10000000].as_ref();
+
+ let result: crate::IResult<(&[u8], usize), bool> = bool((input, 0));
+
+ assert_eq!(result, Ok(((input, 1), true)));
+ }
+
+ #[test]
+ fn test_bool_eof() {
+ let input = [0b10000000].as_ref();
+
+ let result: crate::IResult<(&[u8], usize), bool> = bool((input, 8));
+
+ assert_eq!(result, Err(crate::Err::Incomplete(Needed::new(1))));
+ }
}
diff --git a/src/branch/mod.rs b/src/branch/mod.rs
index 9df5a29..e03622c 100644
--- a/src/branch/mod.rs
+++ b/src/branch/mod.rs
@@ -1,29 +1,5 @@
//! Choice combinators
-macro_rules! succ (
- (0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*));
- (1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*));
- (2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*));
- (3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*));
- (4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*));
- (5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*));
- (6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*));
- (7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*));
- (8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*));
- (9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*));
- (10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*));
- (11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*));
- (12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*));
- (13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*));
- (14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*));
- (15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*));
- (16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*));
- (17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*));
- (18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*));
- (19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*));
- (20, $submac:ident ! ($($rest:tt)*)) => ($submac!(21, $($rest)*));
-);
-
#[cfg(test)]
mod tests;
diff --git a/src/character/complete.rs b/src/character/complete.rs
index a98bafb..7cb760a 100644
--- a/src/character/complete.rs
+++ b/src/character/complete.rs
@@ -414,10 +414,10 @@ where
/// assert_eq!(parser("c1"), Err(Err::Error(Error::new("c1", ErrorKind::Digit))));
/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Digit))));
/// ```
-///
+///
/// ## Parsing an integer
/// You can use `digit1` in combination with [`map_res`] to parse an integer:
-///
+///
/// ```
/// # use nom::{Err, error::{Error, ErrorKind}, IResult, Needed};
/// # use nom::combinator::map_res;
@@ -425,12 +425,12 @@ where
/// fn parser(input: &str) -> IResult<&str, u32> {
/// map_res(digit1, str::parse)(input)
/// }
-///
+///
/// assert_eq!(parser("416"), Ok(("", 416)));
/// assert_eq!(parser("12b"), Ok(("b", 12)));
/// assert!(parser("b").is_err());
/// ```
-///
+///
/// [`map_res`]: crate::combinator::map_res
pub fn digit1<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
where
diff --git a/src/combinator/mod.rs b/src/combinator/mod.rs
index 7071cc7..fe08d4a 100644
--- a/src/combinator/mod.rs
+++ b/src/combinator/mod.rs
@@ -218,7 +218,9 @@ where
}
}
-/// Optional parser: Will return `None` if not successful.
+/// Optional parser, will return `None` on [`Err::Error`].
+///
+/// To chain an error up, see [`cut`].
///
/// ```rust
/// # use nom::{Err,error::ErrorKind, IResult};
@@ -575,18 +577,55 @@ where
}
}
-/// transforms an error to failure
+/// Transforms an [`Err::Error`] (recoverable) to [`Err::Failure`] (unrecoverable)
+///
+/// This commits the parse result, preventing alternative branch paths like with
+/// [`nom::branch::alt`][crate::branch::alt].
///
+/// # Example
+///
+/// Without `cut`:
/// ```rust
/// # use nom::{Err,error::ErrorKind, IResult};
+/// # use nom::character::complete::{one_of, digit1};
+/// # use nom::combinator::rest;
+/// # use nom::branch::alt;
+/// # use nom::sequence::preceded;
+/// # fn main() {
+///
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// alt((
+/// preceded(one_of("+-"), digit1),
+/// rest
+/// ))(input)
+/// }
+///
+/// assert_eq!(parser("+10 ab"), Ok((" ab", "10")));
+/// assert_eq!(parser("ab"), Ok(("", "ab")));
+/// assert_eq!(parser("+"), Ok(("", "+")));
+/// # }
+/// ```
+///
+/// With `cut`:
+/// ```rust
+/// # use nom::{Err,error::ErrorKind, IResult, error::Error};
+/// # use nom::character::complete::{one_of, digit1};
+/// # use nom::combinator::rest;
+/// # use nom::branch::alt;
+/// # use nom::sequence::preceded;
/// use nom::combinator::cut;
-/// use nom::character::complete::alpha1;
/// # fn main() {
///
-/// let mut parser = cut(alpha1);
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// alt((
+/// preceded(one_of("+-"), cut(digit1)),
+/// rest
+/// ))(input)
+/// }
///
-/// assert_eq!(parser("abcd;"), Ok((";", "abcd")));
-/// assert_eq!(parser("123;"), Err(Err::Failure(("123;", ErrorKind::Alpha))));
+/// assert_eq!(parser("+10 ab"), Ok((" ab", "10")));
+/// assert_eq!(parser("ab"), Ok(("", "ab")));
+/// assert_eq!(parser("+"), Err(Err::Failure(Error { input: "", code: ErrorKind::Digit })));
/// # }
/// ```
pub fn cut<I, O, E: ParseError<I>, F>(mut parser: F) -> impl FnMut(I) -> IResult<I, O, E>
@@ -643,6 +682,8 @@ where
/// Call the iterator's [ParserIterator::finish] method to get the remaining input if successful,
/// or the error value if we encountered an error.
///
+/// On [`Err::Error`], iteration will stop. To instead chain an error up, see [`cut`].
+///
/// ```rust
/// use nom::{combinator::iterator, IResult, bytes::complete::tag, character::complete::alpha1, sequence::terminated};
/// use std::collections::HashMap;
diff --git a/src/internal.rs b/src/internal.rs
index 8a3c6a1..b7572fb 100644
--- a/src/internal.rs
+++ b/src/internal.rs
@@ -473,7 +473,9 @@ mod tests {
#[cfg(target_pointer_width = "64")]
fn size_test() {
assert_size!(IResult<&[u8], &[u8], (&[u8], u32)>, 40);
- assert_size!(IResult<&str, &str, u32>, 40);
+ //FIXME: since rust 1.65, this is now 32 bytes, likely thanks to https://github.com/rust-lang/rust/pull/94075
+ // deactivating that test for now because it'll have different values depending on the rust version
+ // assert_size!(IResult<&str, &str, u32>, 40);
assert_size!(Needed, 8);
assert_size!(Err<u32>, 16);
assert_size!(ErrorKind, 1);
diff --git a/src/lib.rs b/src/lib.rs
index 9429467..3beb2f4 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -439,15 +439,16 @@ pub use self::traits::*;
pub use self::str::*;
#[macro_use]
+mod macros;
+#[macro_use]
pub mod error;
+pub mod branch;
pub mod combinator;
mod internal;
-mod traits;
-#[macro_use]
-pub mod branch;
pub mod multi;
pub mod sequence;
+mod traits;
pub mod bits;
pub mod bytes;
diff --git a/src/macros.rs b/src/macros.rs
new file mode 100644
index 0000000..980d2d9
--- /dev/null
+++ b/src/macros.rs
@@ -0,0 +1,23 @@
+macro_rules! succ (
+ (0, $submac:ident ! ($($rest:tt)*)) => ($submac!(1, $($rest)*));
+ (1, $submac:ident ! ($($rest:tt)*)) => ($submac!(2, $($rest)*));
+ (2, $submac:ident ! ($($rest:tt)*)) => ($submac!(3, $($rest)*));
+ (3, $submac:ident ! ($($rest:tt)*)) => ($submac!(4, $($rest)*));
+ (4, $submac:ident ! ($($rest:tt)*)) => ($submac!(5, $($rest)*));
+ (5, $submac:ident ! ($($rest:tt)*)) => ($submac!(6, $($rest)*));
+ (6, $submac:ident ! ($($rest:tt)*)) => ($submac!(7, $($rest)*));
+ (7, $submac:ident ! ($($rest:tt)*)) => ($submac!(8, $($rest)*));
+ (8, $submac:ident ! ($($rest:tt)*)) => ($submac!(9, $($rest)*));
+ (9, $submac:ident ! ($($rest:tt)*)) => ($submac!(10, $($rest)*));
+ (10, $submac:ident ! ($($rest:tt)*)) => ($submac!(11, $($rest)*));
+ (11, $submac:ident ! ($($rest:tt)*)) => ($submac!(12, $($rest)*));
+ (12, $submac:ident ! ($($rest:tt)*)) => ($submac!(13, $($rest)*));
+ (13, $submac:ident ! ($($rest:tt)*)) => ($submac!(14, $($rest)*));
+ (14, $submac:ident ! ($($rest:tt)*)) => ($submac!(15, $($rest)*));
+ (15, $submac:ident ! ($($rest:tt)*)) => ($submac!(16, $($rest)*));
+ (16, $submac:ident ! ($($rest:tt)*)) => ($submac!(17, $($rest)*));
+ (17, $submac:ident ! ($($rest:tt)*)) => ($submac!(18, $($rest)*));
+ (18, $submac:ident ! ($($rest:tt)*)) => ($submac!(19, $($rest)*));
+ (19, $submac:ident ! ($($rest:tt)*)) => ($submac!(20, $($rest)*));
+ (20, $submac:ident ! ($($rest:tt)*)) => ($submac!(21, $($rest)*));
+);
diff --git a/src/multi/mod.rs b/src/multi/mod.rs
index a119134..7312908 100644
--- a/src/multi/mod.rs
+++ b/src/multi/mod.rs
@@ -11,15 +11,28 @@ use crate::lib::std::vec::Vec;
use crate::traits::{InputLength, InputTake, ToUsize};
use core::num::NonZeroUsize;
-/// Repeats the embedded parser until it fails
-/// and returns the results in a `Vec`.
+/// Don't pre-allocate more than 64KiB when calling `Vec::with_capacity`.
+///
+/// Pre-allocating memory is a nice optimization but count fields can't
+/// always be trusted. We should clamp initial capacities to some reasonable
+/// amount. This reduces the risk of a bogus count value triggering a panic
+/// due to an OOM error.
+///
+/// This does not affect correctness. Nom will always read the full number
+/// of elements regardless of the capacity cap.
+#[cfg(feature = "alloc")]
+const MAX_INITIAL_CAPACITY_BYTES: usize = 65536;
+
+/// Repeats the embedded parser, gathering the results in a `Vec`.
+///
+/// This stops on [`Err::Error`] and returns the results that were accumulated. To instead chain an error up, see
+/// [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `f` The parser to apply.
///
-/// *Note*: if the parser passed to `many0` accepts empty inputs
-/// (like `alpha0` or `digit0`), `many0` will return an error,
-/// to prevent going into an infinite loop
+/// *Note*: if the parser passed in accepts empty inputs (like `alpha0` or `digit0`), `many0` will
+/// return an error, to prevent going into an infinite loop
///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed, IResult};
@@ -64,10 +77,10 @@ where
}
}
-/// Runs the embedded parser until it fails and
-/// returns the results in a `Vec`. Fails if
-/// the embedded parser does not produce at least
-/// one result.
+/// Runs the embedded parser, gathering the results in a `Vec`.
+///
+/// This stops on [`Err::Error`] if there is at least one result, and returns the results that were accumulated. To instead chain an error up,
+/// see [`cut`][crate::combinator::cut].
///
/// # Arguments
/// * `f` The parser to apply.
@@ -126,9 +139,12 @@ where
}
}
-/// Applies the parser `f` until the parser `g` produces
-/// a result. Returns a pair consisting of the results of
-/// `f` in a `Vec` and the result of `g`.
+/// Applies the parser `f` until the parser `g` produces a result.
+///
+/// Returns a tuple of the results of `f` in a `Vec` and the result of `g`.
+///
+/// `f` keeps going so long as `g` produces [`Err::Error`]. To instead chain an error up, see [`cut`][crate::combinator::cut].
+///
/// ```rust
/// # use nom::{Err, error::{Error, ErrorKind}, Needed, IResult};
/// use nom::multi::many_till;
@@ -183,8 +199,11 @@ where
}
}
-/// Alternates between two parsers to produce
-/// a list of elements.
+/// Alternates between two parsers to produce a list of elements.
+///
+/// This stops when either parser returns [`Err::Error`] and returns the results that were accumulated. To instead chain an error up, see
+/// [`cut`][crate::combinator::cut].
+///
/// # Arguments
/// * `sep` Parses the separator between list elements.
/// * `f` Parses the elements of the list.
@@ -253,9 +272,13 @@ where
}
}
-/// Alternates between two parsers to produce
-/// a list of elements. Fails if the element
-/// parser does not produce at least one element.
+/// Alternates between two parsers to produce a list of elements until [`Err::Error`].
+///
+/// Fails if the element parser does not produce at least one element.$
+///
+/// This stops when either parser returns [`Err::Error`] and returns the results that were accumulated. To instead chain an error up, see
+/// [`cut`][crate::combinator::cut].
+///
/// # Arguments
/// * `sep` Parses the separator between list elements.
/// * `f` Parses the elements of the list.
@@ -323,13 +346,20 @@ where
}
}
-/// Repeats the embedded parser `n` times or until it fails
-/// and returns the results in a `Vec`. Fails if the
-/// embedded parser does not succeed at least `m` times.
+/// Repeats the embedded parser `m..=n` times
+///
+/// This stops before `n` when the parser returns [`Err::Error`] and returns the results that were accumulated. To instead chain an error up, see
+/// [`cut`][crate::combinator::cut].
+///
/// # Arguments
/// * `m` The minimum number of iterations.
/// * `n` The maximum number of iterations.
/// * `f` The parser to apply.
+///
+/// *Note*: If the parser passed to `many1` accepts empty inputs
+/// (like `alpha0` or `digit0`), `many1` will return an error,
+/// to prevent going into an infinite loop.
+///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed, IResult};
/// use nom::multi::many_m_n;
@@ -362,7 +392,9 @@ where
return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN)));
}
- let mut res = crate::lib::std::vec::Vec::with_capacity(min);
+ let max_initial_capacity =
+ MAX_INITIAL_CAPACITY_BYTES / crate::lib::std::mem::size_of::<O>().max(1);
+ let mut res = crate::lib::std::vec::Vec::with_capacity(min.min(max_initial_capacity));
for count in 0..max {
let len = input.input_len();
match parse.parse(input.clone()) {
@@ -392,10 +424,17 @@ where
}
}
-/// Repeats the embedded parser until it fails
-/// and returns the number of successful iterations.
+/// Repeats the embedded parser, counting the results
+///
+/// This stops on [`Err::Error`]. To instead chain an error up, see
+/// [`cut`][crate::combinator::cut].
+///
/// # Arguments
/// * `f` The parser to apply.
+///
+/// *Note*: if the parser passed in accepts empty inputs (like `alpha0` or `digit0`), `many0` will
+/// return an error, to prevent going into an infinite loop
+///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed, IResult};
/// use nom::multi::many0_count;
@@ -442,12 +481,18 @@ where
}
}
-/// Repeats the embedded parser until it fails
-/// and returns the number of successful iterations.
-/// Fails if the embedded parser does not succeed
-/// at least once.
+/// Runs the embedded parser, counting the results.
+///
+/// This stops on [`Err::Error`] if there is at least one result. To instead chain an error up,
+/// see [`cut`][crate::combinator::cut].
+///
/// # Arguments
/// * `f` The parser to apply.
+///
+/// *Note*: If the parser passed to `many1` accepts empty inputs
+/// (like `alpha0` or `digit0`), `many1` will return an error,
+/// to prevent going into an infinite loop.
+///
/// ```rust
/// # use nom::{Err, error::{Error, ErrorKind}, Needed, IResult};
/// use nom::multi::many1_count;
@@ -499,8 +544,8 @@ where
}
}
-/// Runs the embedded parser a specified number
-/// of times. Returns the results in a `Vec`.
+/// Runs the embedded parser `count` times, gathering the results in a `Vec`
+///
/// # Arguments
/// * `f` The parser to apply.
/// * `count` How often to apply the parser.
@@ -529,7 +574,9 @@ where
{
move |i: I| {
let mut input = i.clone();
- let mut res = crate::lib::std::vec::Vec::with_capacity(count);
+ let max_initial_capacity =
+ MAX_INITIAL_CAPACITY_BYTES / crate::lib::std::mem::size_of::<O>().max(1);
+ let mut res = crate::lib::std::vec::Vec::with_capacity(count.min(max_initial_capacity));
for _ in 0..count {
let input_ = input.clone();
@@ -551,8 +598,10 @@ where
}
}
-/// Runs the embedded parser repeatedly, filling the given slice with results. This parser fails if
-/// the input runs out before the given slice is full.
+/// Runs the embedded parser repeatedly, filling the given slice with results.
+///
+/// This parser fails if the input runs out before the given slice is full.
+///
/// # Arguments
/// * `f` The parser to apply.
/// * `buf` The slice to fill
@@ -602,13 +651,20 @@ where
}
}
-/// Applies a parser until it fails and accumulates
-/// the results using a given function and initial value.
+/// Repeats the embedded parser, calling `g` to gather the results.
+///
+/// This stops on [`Err::Error`]. To instead chain an error up, see
+/// [`cut`][crate::combinator::cut].
+///
/// # Arguments
/// * `f` The parser to apply.
/// * `init` A function returning the initial value.
/// * `g` The function that combines a result of `f` with
/// the current accumulator.
+///
+/// *Note*: if the parser passed in accepts empty inputs (like `alpha0` or `digit0`), `many0` will
+/// return an error, to prevent going into an infinite loop
+///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed, IResult};
/// use nom::multi::fold_many0;
@@ -670,15 +726,21 @@ where
}
}
-/// Applies a parser until it fails and accumulates
-/// the results using a given function and initial value.
-/// Fails if the embedded parser does not succeed at least
-/// once.
+/// Repeats the embedded parser, calling `g` to gather the results.
+///
+/// This stops on [`Err::Error`] if there is at least one result. To instead chain an error up,
+/// see [`cut`][crate::combinator::cut].
+///
/// # Arguments
/// * `f` The parser to apply.
/// * `init` A function returning the initial value.
/// * `g` The function that combines a result of `f` with
/// the current accumulator.
+///
+/// *Note*: If the parser passed to `many1` accepts empty inputs
+/// (like `alpha0` or `digit0`), `many1` will return an error,
+/// to prevent going into an infinite loop.
+///
/// ```rust
/// # use nom::{Err, error::{Error, ErrorKind}, Needed, IResult};
/// use nom::multi::fold_many1;
@@ -748,10 +810,11 @@ where
}
}
-/// Applies a parser `n` times or until it fails and accumulates
-/// the results using a given function and initial value.
-/// Fails if the embedded parser does not succeed at least `m`
-/// times.
+/// Repeats the embedded parser `m..=n` times, calling `g` to gather the results
+///
+/// This stops before `n` when the parser returns [`Err::Error`]. To instead chain an error up, see
+/// [`cut`][crate::combinator::cut].
+///
/// # Arguments
/// * `m` The minimum number of iterations.
/// * `n` The maximum number of iterations.
@@ -759,6 +822,11 @@ where
/// * `init` A function returning the initial value.
/// * `g` The function that combines a result of `f` with
/// the current accumulator.
+///
+/// *Note*: If the parser passed to `many1` accepts empty inputs
+/// (like `alpha0` or `digit0`), `many1` will return an error,
+/// to prevent going into an infinite loop.
+///
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed, IResult};
/// use nom::multi::fold_many_m_n;
diff --git a/src/number/complete.rs b/src/number/complete.rs
index 715da32..98b8b3a 100644
--- a/src/number/complete.rs
+++ b/src/number/complete.rs
@@ -13,26 +13,6 @@ use crate::traits::{
AsBytes, AsChar, Compare, InputIter, InputLength, InputTake, InputTakeAtPosition, Offset, Slice,
};
-#[doc(hidden)]
-macro_rules! map(
- // Internal parser, do not use directly
- (__impl $i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- $crate::combinator::map(move |i| {$submac!(i, $($args)*)}, $g).parse($i)
- );
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- map!(__impl $i, $submac!($($args)*), $g)
- );
- ($i:expr, $f:expr, $g:expr) => (
- map!(__impl $i, call!($f), $g)
- );
-);
-
-#[doc(hidden)]
-macro_rules! call (
- ($i:expr, $fun:expr) => ( $fun( $i ) );
- ($i:expr, $fun:expr, $($args:expr),* ) => ( $fun( $i, $($args),* ) );
-);
-
/// Recognizes an unsigned 1 byte integer.
///
/// *Complete version*: Returns an error if there is not enough input data.
@@ -248,7 +228,7 @@ pub fn be_i8<I, E: ParseError<I>>(input: I) -> IResult<I, i8, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, be_u8, |x| x as i8)
+ be_u8.map(|x| x as i8).parse(input)
}
/// Recognizes a big endian signed 2 bytes integer.
@@ -271,7 +251,7 @@ pub fn be_i16<I, E: ParseError<I>>(input: I) -> IResult<I, i16, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, be_u16, |x| x as i16)
+ be_u16.map(|x| x as i16).parse(input)
}
/// Recognizes a big endian signed 3 bytes integer.
@@ -295,16 +275,20 @@ where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
// Same as the unsigned version but we need to sign-extend manually here
- map!(input, be_u24, |x| if x & 0x80_00_00 != 0 {
- (x | 0xff_00_00_00) as i32
- } else {
- x as i32
- })
+ be_u24
+ .map(|x| {
+ if x & 0x80_00_00 != 0 {
+ (x | 0xff_00_00_00) as i32
+ } else {
+ x as i32
+ }
+ })
+ .parse(input)
}
/// Recognizes a big endian signed 4 bytes integer.
///
-/// *Complete version*: Teturns an error if there is not enough input data.
+/// *Complete version*: Returns an error if there is not enough input data.
/// ```rust
/// # use nom::{Err, error::ErrorKind, Needed};
/// # use nom::Needed::Size;
@@ -322,7 +306,7 @@ pub fn be_i32<I, E: ParseError<I>>(input: I) -> IResult<I, i32, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, be_u32, |x| x as i32)
+ be_u32.map(|x| x as i32).parse(input)
}
/// Recognizes a big endian signed 8 bytes integer.
@@ -345,7 +329,7 @@ pub fn be_i64<I, E: ParseError<I>>(input: I) -> IResult<I, i64, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, be_u64, |x| x as i64)
+ be_u64.map(|x| x as i64).parse(input)
}
/// Recognizes a big endian signed 16 bytes integer.
@@ -368,7 +352,7 @@ pub fn be_i128<I, E: ParseError<I>>(input: I) -> IResult<I, i128, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, be_u128, |x| x as i128)
+ be_u128.map(|x| x as i128).parse(input)
}
/// Recognizes an unsigned 1 byte integer.
@@ -586,7 +570,7 @@ pub fn le_i8<I, E: ParseError<I>>(input: I) -> IResult<I, i8, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, be_u8, |x| x as i8)
+ be_u8.map(|x| x as i8).parse(input)
}
/// Recognizes a little endian signed 2 bytes integer.
@@ -609,7 +593,7 @@ pub fn le_i16<I, E: ParseError<I>>(input: I) -> IResult<I, i16, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, le_u16, |x| x as i16)
+ le_u16.map(|x| x as i16).parse(input)
}
/// Recognizes a little endian signed 3 bytes integer.
@@ -633,11 +617,15 @@ where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
// Same as the unsigned version but we need to sign-extend manually here
- map!(input, le_u24, |x| if x & 0x80_00_00 != 0 {
- (x | 0xff_00_00_00) as i32
- } else {
- x as i32
- })
+ le_u24
+ .map(|x| {
+ if x & 0x80_00_00 != 0 {
+ (x | 0xff_00_00_00) as i32
+ } else {
+ x as i32
+ }
+ })
+ .parse(input)
}
/// Recognizes a little endian signed 4 bytes integer.
@@ -660,7 +648,7 @@ pub fn le_i32<I, E: ParseError<I>>(input: I) -> IResult<I, i32, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, le_u32, |x| x as i32)
+ le_u32.map(|x| x as i32).parse(input)
}
/// Recognizes a little endian signed 8 bytes integer.
@@ -683,7 +671,7 @@ pub fn le_i64<I, E: ParseError<I>>(input: I) -> IResult<I, i64, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, le_u64, |x| x as i64)
+ le_u64.map(|x| x as i64).parse(input)
}
/// Recognizes a little endian signed 16 bytes integer.
@@ -706,7 +694,7 @@ pub fn le_i128<I, E: ParseError<I>>(input: I) -> IResult<I, i128, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, le_u128, |x| x as i128)
+ le_u128.map(|x| x as i128).parse(input)
}
/// Recognizes an unsigned 1 byte integer
@@ -957,7 +945,7 @@ pub fn i8<I, E: ParseError<I>>(i: I) -> IResult<I, i8, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(i, u8, |x| x as i8)
+ u8.map(|x| x as i8).parse(i)
}
/// Recognizes a signed 2 byte integer
@@ -1595,7 +1583,7 @@ where
*/
let (i, s) = recognize_float_or_exceptions(input)?;
match s.parse_to() {
- Some(f) => (Ok((i, f))),
+ Some(f) => Ok((i, f)),
None => Err(crate::Err::Error(E::from_error_kind(
i,
crate::error::ErrorKind::Float,
@@ -1648,7 +1636,7 @@ where
*/
let (i, s) = recognize_float_or_exceptions(input)?;
match s.parse_to() {
- Some(f) => (Ok((i, f))),
+ Some(f) => Ok((i, f)),
None => Err(crate::Err::Error(E::from_error_kind(
i,
crate::error::ErrorKind::Float,
@@ -2111,7 +2099,7 @@ mod tests {
#[cfg(feature = "std")]
fn parse_f64(i: &str) -> IResult<&str, f64, ()> {
- match recognize_float(i) {
+ match recognize_float_or_exceptions(i) {
Err(e) => Err(e),
Ok((i, s)) => {
if s.is_empty() {
diff --git a/src/number/streaming.rs b/src/number/streaming.rs
index 9ee9f48..b4e856d 100644
--- a/src/number/streaming.rs
+++ b/src/number/streaming.rs
@@ -12,26 +12,6 @@ use crate::traits::{
AsBytes, AsChar, Compare, InputIter, InputLength, InputTake, InputTakeAtPosition, Offset, Slice,
};
-#[doc(hidden)]
-macro_rules! map(
- // Internal parser, do not use directly
- (__impl $i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- $crate::combinator::map(move |i| {$submac!(i, $($args)*)}, $g).parse($i)
- );
- ($i:expr, $submac:ident!( $($args:tt)* ), $g:expr) => (
- map!(__impl $i, $submac!($($args)*), $g)
- );
- ($i:expr, $f:expr, $g:expr) => (
- map!(__impl $i, call!($f), $g)
- );
-);
-
-#[doc(hidden)]
-macro_rules! call (
- ($i:expr, $fun:expr) => ( $fun( $i ) );
- ($i:expr, $fun:expr, $($args:expr),* ) => ( $fun( $i, $($args),* ) );
-);
-
/// Recognizes an unsigned 1 byte integer.
///
/// *Streaming version*: Will return `Err(nom::Err::Incomplete(_))` if there is not enough data.
@@ -242,7 +222,7 @@ pub fn be_i8<I, E: ParseError<I>>(input: I) -> IResult<I, i8, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, be_u8, |x| x as i8)
+ be_u8.map(|x| x as i8).parse(input)
}
/// Recognizes a big endian signed 2 bytes integer.
@@ -262,7 +242,7 @@ pub fn be_i16<I, E: ParseError<I>>(input: I) -> IResult<I, i16, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, be_u16, |x| x as i16)
+ be_u16.map(|x| x as i16).parse(input)
}
/// Recognizes a big endian signed 3 bytes integer.
@@ -283,11 +263,15 @@ where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
// Same as the unsigned version but we need to sign-extend manually here
- map!(input, be_u24, |x| if x & 0x80_00_00 != 0 {
- (x | 0xff_00_00_00) as i32
- } else {
- x as i32
- })
+ be_u24
+ .map(|x| {
+ if x & 0x80_00_00 != 0 {
+ (x | 0xff_00_00_00) as i32
+ } else {
+ x as i32
+ }
+ })
+ .parse(input)
}
/// Recognizes a big endian signed 4 bytes integer.
@@ -307,7 +291,7 @@ pub fn be_i32<I, E: ParseError<I>>(input: I) -> IResult<I, i32, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, be_u32, |x| x as i32)
+ be_u32.map(|x| x as i32).parse(input)
}
/// Recognizes a big endian signed 8 bytes integer.
@@ -328,7 +312,7 @@ pub fn be_i64<I, E: ParseError<I>>(input: I) -> IResult<I, i64, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, be_u64, |x| x as i64)
+ be_u64.map(|x| x as i64).parse(input)
}
/// Recognizes a big endian signed 16 bytes integer.
@@ -348,7 +332,7 @@ pub fn be_i128<I, E: ParseError<I>>(input: I) -> IResult<I, i128, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, be_u128, |x| x as i128)
+ be_u128.map(|x| x as i128).parse(input)
}
/// Recognizes an unsigned 1 byte integer.
@@ -560,7 +544,7 @@ pub fn le_i8<I, E: ParseError<I>>(input: I) -> IResult<I, i8, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, le_u8, |x| x as i8)
+ le_u8.map(|x| x as i8).parse(input)
}
/// Recognizes a little endian signed 2 bytes integer.
@@ -583,7 +567,7 @@ pub fn le_i16<I, E: ParseError<I>>(input: I) -> IResult<I, i16, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, le_u16, |x| x as i16)
+ le_u16.map(|x| x as i16).parse(input)
}
/// Recognizes a little endian signed 3 bytes integer.
@@ -607,11 +591,15 @@ where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
// Same as the unsigned version but we need to sign-extend manually here
- map!(input, le_u24, |x| if x & 0x80_00_00 != 0 {
- (x | 0xff_00_00_00) as i32
- } else {
- x as i32
- })
+ le_u24
+ .map(|x| {
+ if x & 0x80_00_00 != 0 {
+ (x | 0xff_00_00_00) as i32
+ } else {
+ x as i32
+ }
+ })
+ .parse(input)
}
/// Recognizes a little endian signed 4 bytes integer.
@@ -634,7 +622,7 @@ pub fn le_i32<I, E: ParseError<I>>(input: I) -> IResult<I, i32, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, le_u32, |x| x as i32)
+ le_u32.map(|x| x as i32).parse(input)
}
/// Recognizes a little endian signed 8 bytes integer.
@@ -657,7 +645,7 @@ pub fn le_i64<I, E: ParseError<I>>(input: I) -> IResult<I, i64, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, le_u64, |x| x as i64)
+ le_u64.map(|x| x as i64).parse(input)
}
/// Recognizes a little endian signed 16 bytes integer.
@@ -680,7 +668,7 @@ pub fn le_i128<I, E: ParseError<I>>(input: I) -> IResult<I, i128, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(input, le_u128, |x| x as i128)
+ le_u128.map(|x| x as i128).parse(input)
}
/// Recognizes an unsigned 1 byte integer
@@ -931,7 +919,7 @@ pub fn i8<I, E: ParseError<I>>(i: I) -> IResult<I, i8, E>
where
I: Slice<RangeFrom<usize>> + InputIter<Item = u8> + InputLength,
{
- map!(i, u8, |x| x as i8)
+ u8.map(|x| x as i8).parse(i)
}
/// Recognizes a signed 2 byte integer
@@ -1567,7 +1555,7 @@ where
*/
let (i, s) = recognize_float_or_exceptions(input)?;
match s.parse_to() {
- Some(f) => (Ok((i, f))),
+ Some(f) => Ok((i, f)),
None => Err(crate::Err::Error(E::from_error_kind(
i,
crate::error::ErrorKind::Float,
@@ -1621,7 +1609,7 @@ where
*/
let (i, s) = recognize_float_or_exceptions(input)?;
match s.parse_to() {
- Some(f) => (Ok((i, f))),
+ Some(f) => Ok((i, f)),
None => Err(crate::Err::Error(E::from_error_kind(
i,
crate::error::ErrorKind::Float,
@@ -2191,7 +2179,7 @@ mod tests {
#[cfg(feature = "std")]
fn parse_f64(i: &str) -> IResult<&str, f64, ()> {
use crate::traits::ParseTo;
- match recognize_float(i) {
+ match recognize_float_or_exceptions(i) {
Err(e) => Err(e),
Ok((i, s)) => {
if s.is_empty() {
diff --git a/src/sequence/mod.rs b/src/sequence/mod.rs
index e09d413..735ab45 100644
--- a/src/sequence/mod.rs
+++ b/src/sequence/mod.rs
@@ -252,6 +252,15 @@ macro_rules! tuple_trait_inner(
tuple_trait!(FnA A, FnB B, FnC C, FnD D, FnE E, FnF F, FnG G, FnH H, FnI I, FnJ J, FnK K, FnL L,
FnM M, FnN N, FnO O, FnP P, FnQ Q, FnR R, FnS S, FnT T, FnU U);
+// Special case: implement `Tuple` for `()`, the unit type.
+// This can come up in macros which accept a variable number of arguments.
+// Literally, `()` is an empty tuple, so it should simply parse nothing.
+impl<I, E: ParseError<I>> Tuple<I, (), E> for () {
+ fn parse(&mut self, input: I) -> IResult<I, (), E> {
+ Ok((input, ()))
+ }
+}
+
///Applies a tuple of parsers one by one and returns their results as a tuple.
///There is a maximum of 21 parsers
/// ```rust
diff --git a/src/sequence/tests.rs b/src/sequence/tests.rs
index 201579b..30ad0d6 100644
--- a/src/sequence/tests.rs
+++ b/src/sequence/tests.rs
@@ -1,6 +1,6 @@
use super::*;
use crate::bytes::streaming::{tag, take};
-use crate::error::ErrorKind;
+use crate::error::{Error, ErrorKind};
use crate::internal::{Err, IResult, Needed};
use crate::number::streaming::be_u16;
@@ -272,3 +272,19 @@ fn tuple_test() {
Err(Err::Error(error_position!(&b"jk"[..], ErrorKind::Tag)))
);
}
+
+#[test]
+fn unit_type() {
+ assert_eq!(
+ tuple::<&'static str, (), Error<&'static str>, ()>(())("abxsbsh"),
+ Ok(("abxsbsh", ()))
+ );
+ assert_eq!(
+ tuple::<&'static str, (), Error<&'static str>, ()>(())("sdfjakdsas"),
+ Ok(("sdfjakdsas", ()))
+ );
+ assert_eq!(
+ tuple::<&'static str, (), Error<&'static str>, ()>(())(""),
+ Ok(("", ()))
+ );
+}
diff --git a/src/traits.rs b/src/traits.rs
index f6a683c..394e5bc 100644
--- a/src/traits.rs
+++ b/src/traits.rs
@@ -1330,6 +1330,10 @@ impl<I> ErrorConvert<error::VerboseError<(I, usize)>> for error::VerboseError<I>
}
}
+impl ErrorConvert<()> for () {
+ fn convert(self) {}
+}
+
#[cfg(feature = "std")]
#[cfg_attr(feature = "docsrs", doc(cfg(feature = "std")))]
/// Helper trait to show a byte slice as a hex dump
diff --git a/tests/issues.rs b/tests/issues.rs
index f7e2799..7985702 100644
--- a/tests/issues.rs
+++ b/tests/issues.rs
@@ -214,3 +214,29 @@ fn issue_1282_findtoken_char() {
let parser = one_of::<_, _, Error<_>>(&['a', 'b', 'c'][..]);
assert_eq!(parser("aaa"), Ok(("aa", 'a')));
}
+
+#[test]
+fn issue_1459_clamp_capacity() {
+ use nom::character::complete::char;
+
+ // shouldn't panic
+ use nom::multi::many_m_n;
+ let mut parser = many_m_n::<_, _, (), _>(usize::MAX, usize::MAX, char('a'));
+ assert_eq!(parser("a"), Err(nom::Err::Error(())));
+
+ // shouldn't panic
+ use nom::multi::count;
+ let mut parser = count::<_, _, (), _>(char('a'), usize::MAX);
+ assert_eq!(parser("a"), Err(nom::Err::Error(())));
+}
+
+#[test]
+fn issue_1617_count_parser_returning_zero_size() {
+ use nom::{bytes::complete::tag, combinator::map, error::Error, multi::count};
+
+ // previously, `count()` panicked if the parser had type `O = ()`
+ let parser = map(tag::<_, _, Error<&str>>("abc"), |_| ());
+ // shouldn't panic
+ let result = count(parser, 3)("abcabcabcdef").expect("parsing should succeed");
+ assert_eq!(result, ("def", vec![(), (), ()]));
+}