From 1da834c7b1fcbfc3ccb8d258f9ebb7aa161f9911 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Fri, 17 Sep 2021 22:48:18 +0200 Subject: [PATCH 01/38] Add NomRange type and implement range argument for many --- src/multi/mod.rs | 148 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 148 insertions(+) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 9f7288863..0e008ab35 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -991,3 +991,151 @@ where Ok((input, res)) } } + +/// Range many +/// ```rust +/// # #[macro_use] extern crate nom; +/// # use nom::{Err, error::ErrorKind, Needed, IResult}; +/// use nom::multi::many; +/// use nom::bytes::complete::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// many(0..=2, tag("abc"))(s) +/// } +/// +/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); +/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); +/// assert_eq!(parser("123123"), Ok(("123123", vec![]))); +/// assert_eq!(parser(""), Ok(("", vec![]))); +/// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); +/// ``` +#[cfg(feature = "alloc")] +#[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] +pub fn many( + range: G, + mut parse: F, +) -> impl FnMut(I) -> IResult, E> +where + I: Clone + InputLength, + F: Parser, + E: ParseError, + G: NomRange, +{ + move |mut input: I| { + let start = range.lower_bound(); + let end = match range.upper_bound() { + Some(e) => e, + None => UpperBound::Inclusive(usize::MAX), + }; + + if let Some(start) = start { + if !end.contains(start) { + return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))); + } + } + + let mut res = crate::lib::std::vec::Vec::with_capacity(start.unwrap_or(0)); + let mut count = 0; + + loop { + count += 1; + if !end.contains(count) { + break + } + let len = input.input_len(); + match parse.parse(input.clone()) { + Ok((tail, value)) => { + // infinite loop check: the parser must always consume + if tail.input_len() == len { + return Err(Err::Error(E::from_error_kind(input, ErrorKind::ManyMN))); + } + + res.push(value); + input = tail; + } + Err(Err::Error(e)) => { + if count < start.unwrap_or(0) { + return Err(Err::Error(E::append(input, ErrorKind::ManyMN, e))); + } else { + return Ok((input, res)); + } + } + Err(e) => { + return Err(e); + } + } + } + + Ok((input, res)) + } +} + +/// +pub enum UpperBound { + /// + Inclusive(usize), + /// + Exclusive(usize), +} + +impl UpperBound { + /// + fn contains(&self, number: usize) -> bool { + match self { + UpperBound::Exclusive(bound) => number < *bound, + UpperBound::Inclusive(bound) => number <= *bound, + } + } +} + +/// +pub trait NomRange { + /// + fn lower_bound(&self) -> Option; + /// + fn upper_bound(&self) -> Option; + /// + fn contains(&self, number: usize) -> bool; +} + +impl NomRange for usize { + fn lower_bound(&self) -> Option {Some(*self)} + fn upper_bound(&self) -> Option {Some(UpperBound::Inclusive(*self))} + fn contains(&self, number: usize) -> bool {*self == number} +} + +impl NomRange for core::ops::Range { + fn lower_bound(&self) -> Option {Some(self.start)} + fn upper_bound(&self) -> Option {Some(UpperBound::Exclusive(self.end))} + fn contains(&self, number: usize) -> bool {self.start <= number && number < self.end} +} + +impl NomRange for core::ops::RangeFrom { + fn lower_bound(&self) -> Option {Some(self.start)} + fn upper_bound(&self) -> Option {None} + fn contains(&self, number: usize) -> bool {self.start <= number} +} + +impl NomRange for core::ops::RangeTo { + fn lower_bound(&self) -> Option {None} + fn upper_bound(&self) -> Option {Some(UpperBound::Exclusive(self.end))} + fn contains(&self, number: usize) -> bool {number < self.end} +} + +impl NomRange for core::ops::RangeFull { + fn lower_bound(&self) -> Option {None} + fn upper_bound(&self) -> Option {None} + fn contains(&self, _number: usize) -> bool {true} +} + +impl NomRange for core::ops::RangeInclusive { + fn lower_bound(&self) -> Option {Some(*self.start())} + fn upper_bound(&self) -> Option {Some(UpperBound::Inclusive(*self.end()))} + fn contains(&self, number: usize) -> bool {*self.start() <= number && number <= *self.end()} +} + +impl NomRange for core::ops::RangeToInclusive { + fn lower_bound(&self) -> Option {None} + fn upper_bound(&self) -> Option {Some(UpperBound::Inclusive(self.end))} + fn contains(&self, number: usize) -> bool {number <= self.end} +} From f2236c84b6720aca86bae73bb4513c45d2f76a23 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Fri, 17 Sep 2021 23:01:44 +0200 Subject: [PATCH 02/38] Add range fold parser --- src/multi/mod.rs | 87 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 0e008ab35..c1c16f20d 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -1025,7 +1025,7 @@ where let start = range.lower_bound(); let end = match range.upper_bound() { Some(e) => e, - None => UpperBound::Inclusive(usize::MAX), + None => UpperBound::Inclusive(usize::MAX), //TODO instead always fail with upper unbounded? }; if let Some(start) = start { @@ -1070,6 +1070,91 @@ where } } +/// Range fold +/// ```rust +/// # #[macro_use] extern crate nom; +/// # use nom::{Err, error::ErrorKind, Needed, IResult}; +/// use nom::multi::fold_many; +/// use nom::bytes::complete::tag; +/// +/// fn parser(s: &str) -> IResult<&str, Vec<&str>> { +/// fold_many( +/// 0..=2, +/// tag("abc"), +/// Vec::new, +/// |mut acc: Vec<_>, item| { +/// acc.push(item); +/// acc +/// } +/// )(s) +/// } +/// +/// assert_eq!(parser("abcabc"), Ok(("", vec!["abc", "abc"]))); +/// assert_eq!(parser("abc123"), Ok(("123", vec!["abc"]))); +/// assert_eq!(parser("123123"), Ok(("123123", vec![]))); +/// assert_eq!(parser(""), Ok(("", vec![]))); +/// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); +/// ``` +pub fn fold_many( + range: J, + mut parse: F, + mut init: H, + mut fold: G, +) -> impl FnMut(I) -> IResult +where + I: Clone + InputLength, + F: Parser, + G: FnMut(R, O) -> R, + H: FnMut() -> R, + E: ParseError, + J: NomRange, +{ + move |mut input: I| { + match (range.lower_bound(), range.upper_bound()) { + (Some(start), Some(end)) => { + if !end.contains(start) { + return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))); + } + }, + _ => {}, + } + + let mut acc = init(); + let mut count: usize = 0; + loop { + count = count.saturating_add(1); + if let Some(end) = range.upper_bound() { + if !end.contains(count) { + break; + } + } + let len = input.input_len(); + match parse.parse(input.clone()) { + Ok((tail, value)) => { + // infinite loop check: the parser must always consume + if tail.input_len() == len { + return Err(Err::Error(E::from_error_kind(tail, ErrorKind::ManyMN))); + } + + acc = fold(acc, value); + input = tail; + } + //FInputXMError: handle failure properly + Err(Err::Error(err)) => { + if !range.contains(count) { + return Err(Err::Error(E::append(input, ErrorKind::ManyMN, err))); + } else { + break; + } + } + Err(e) => return Err(e), + } + } + + Ok((input, acc)) + } +} + /// pub enum UpperBound { /// From c8de0b447509bb5d442684a6496d5798934acc1f Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Fri, 17 Sep 2021 23:58:13 +0200 Subject: [PATCH 03/38] Use core::ops::RangeBounds instead --- src/multi/mod.rs | 124 ++++++++++++----------------------------------- 1 file changed, 31 insertions(+), 93 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index c1c16f20d..af1475df4 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -1019,29 +1019,36 @@ where I: Clone + InputLength, F: Parser, E: ParseError, - G: NomRange, + G: core::ops::RangeBounds, { move |mut input: I| { - let start = range.lower_bound(); - let end = match range.upper_bound() { - Some(e) => e, - None => UpperBound::Inclusive(usize::MAX), //TODO instead always fail with upper unbounded? + use std::ops::Bound; + let start = match range.start_bound() { + Bound::Included(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))), + Bound::Excluded(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))), + Bound::Included(start) => Some(*start), + Bound::Excluded(start) => Some(*start + 1), + _ => None, }; - if let Some(start) = start { - if !end.contains(start) { - return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))); - } + if let Bound::Unbounded = range.end_bound() { + return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))); } + let mut res = crate::lib::std::vec::Vec::with_capacity(start.unwrap_or(0)); let mut count = 0; loop { count += 1; - if !end.contains(count) { - break + if match range.end_bound() { + Bound::Included(end) => count > *end, + Bound::Excluded(end) => count >= *end, + _ => false, + } { + break; } + let len = input.input_len(); match parse.parse(input.clone()) { Ok((tail, value)) => { @@ -1107,15 +1114,13 @@ where G: FnMut(R, O) -> R, H: FnMut() -> R, E: ParseError, - J: NomRange, + J: core::ops::RangeBounds, { move |mut input: I| { - match (range.lower_bound(), range.upper_bound()) { - (Some(start), Some(end)) => { - if !end.contains(start) { - return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))); - } - }, + use std::ops::Bound; + match range.start_bound() { + Bound::Included(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))), + Bound::Excluded(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))), _ => {}, } @@ -1123,11 +1128,14 @@ where let mut count: usize = 0; loop { count = count.saturating_add(1); - if let Some(end) = range.upper_bound() { - if !end.contains(count) { - break; - } + if match range.end_bound() { + Bound::Included(end) => count > *end, + Bound::Excluded(end) => count >= *end, + _ => false, + } { + break; } + let len = input.input_len(); match parse.parse(input.clone()) { Ok((tail, value)) => { @@ -1141,7 +1149,7 @@ where } //FInputXMError: handle failure properly Err(Err::Error(err)) => { - if !range.contains(count) { + if !range.contains(&count) { return Err(Err::Error(E::append(input, ErrorKind::ManyMN, err))); } else { break; @@ -1154,73 +1162,3 @@ where Ok((input, acc)) } } - -/// -pub enum UpperBound { - /// - Inclusive(usize), - /// - Exclusive(usize), -} - -impl UpperBound { - /// - fn contains(&self, number: usize) -> bool { - match self { - UpperBound::Exclusive(bound) => number < *bound, - UpperBound::Inclusive(bound) => number <= *bound, - } - } -} - -/// -pub trait NomRange { - /// - fn lower_bound(&self) -> Option; - /// - fn upper_bound(&self) -> Option; - /// - fn contains(&self, number: usize) -> bool; -} - -impl NomRange for usize { - fn lower_bound(&self) -> Option {Some(*self)} - fn upper_bound(&self) -> Option {Some(UpperBound::Inclusive(*self))} - fn contains(&self, number: usize) -> bool {*self == number} -} - -impl NomRange for core::ops::Range { - fn lower_bound(&self) -> Option {Some(self.start)} - fn upper_bound(&self) -> Option {Some(UpperBound::Exclusive(self.end))} - fn contains(&self, number: usize) -> bool {self.start <= number && number < self.end} -} - -impl NomRange for core::ops::RangeFrom { - fn lower_bound(&self) -> Option {Some(self.start)} - fn upper_bound(&self) -> Option {None} - fn contains(&self, number: usize) -> bool {self.start <= number} -} - -impl NomRange for core::ops::RangeTo { - fn lower_bound(&self) -> Option {None} - fn upper_bound(&self) -> Option {Some(UpperBound::Exclusive(self.end))} - fn contains(&self, number: usize) -> bool {number < self.end} -} - -impl NomRange for core::ops::RangeFull { - fn lower_bound(&self) -> Option {None} - fn upper_bound(&self) -> Option {None} - fn contains(&self, _number: usize) -> bool {true} -} - -impl NomRange for core::ops::RangeInclusive { - fn lower_bound(&self) -> Option {Some(*self.start())} - fn upper_bound(&self) -> Option {Some(UpperBound::Inclusive(*self.end()))} - fn contains(&self, number: usize) -> bool {*self.start() <= number && number <= *self.end()} -} - -impl NomRange for core::ops::RangeToInclusive { - fn lower_bound(&self) -> Option {None} - fn upper_bound(&self) -> Option {Some(UpperBound::Inclusive(self.end))} - fn contains(&self, number: usize) -> bool {number <= self.end} -} From 0dd44cab4b9a7609922860ea3d15de5f89bf684d Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 18 Sep 2021 00:36:44 +0200 Subject: [PATCH 04/38] Allow conversion from usize to RangeBounds --- src/multi/mod.rs | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index af1475df4..b852ddd3c 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -10,6 +10,7 @@ use crate::internal::{Err, IResult, Needed, Parser}; use crate::lib::std::vec::Vec; use crate::traits::{InputLength, InputTake, ToUsize}; use core::num::NonZeroUsize; +use core::ops::{RangeBounds, Bound}; /// Repeats the embedded parser until it fails /// and returns the results in a `Vec`. @@ -1011,7 +1012,7 @@ where /// ``` #[cfg(feature = "alloc")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] -pub fn many( +pub fn many( range: G, mut parse: F, ) -> impl FnMut(I) -> IResult, E> @@ -1019,10 +1020,11 @@ where I: Clone + InputLength, F: Parser, E: ParseError, - G: core::ops::RangeBounds, + G: IntoRangeBounds, + H: RangeBounds { + let range = range.convert(); move |mut input: I| { - use std::ops::Bound; let start = match range.start_bound() { Bound::Included(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))), Bound::Excluded(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))), @@ -1102,7 +1104,7 @@ where /// assert_eq!(parser(""), Ok(("", vec![]))); /// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); /// ``` -pub fn fold_many( +pub fn fold_many( range: J, mut parse: F, mut init: H, @@ -1114,10 +1116,11 @@ where G: FnMut(R, O) -> R, H: FnMut() -> R, E: ParseError, - J: core::ops::RangeBounds, + J: IntoRangeBounds, + K: RangeBounds, { + let range = range.convert(); move |mut input: I| { - use std::ops::Bound; match range.start_bound() { Bound::Included(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))), Bound::Excluded(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))), @@ -1162,3 +1165,23 @@ where Ok((input, acc)) } } + +/// +pub trait IntoRangeBounds +where + T: RangeBounds +{ + /// + fn convert(self) -> T; +} + +impl IntoRangeBounds for T +where + T: RangeBounds +{ + fn convert(self) -> T {self} +} + +impl IntoRangeBounds> for usize { + fn convert(self) -> std::ops::RangeInclusive {self..=self} +} From 1ee3ee41746d85bfb3f0cb49586850cdc52c6dfb Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 18 Sep 2021 00:52:57 +0200 Subject: [PATCH 05/38] Add documentation --- src/multi/mod.rs | 23 +++++++++++++++++++---- 1 file changed, 19 insertions(+), 4 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index b852ddd3c..6fc1e5dd0 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -993,7 +993,12 @@ where } } -/// Range many +/// Repeats the embedded parser and returns the results in a `Vec`. +/// Fails if the amount of time the embedded parser is run is not +/// within the specified range. +/// # Arguments +/// * `range` The amount of times to apply the parser. +/// * `parse` The parser to apply. /// ```rust /// # #[macro_use] extern crate nom; /// # use nom::{Err, error::ErrorKind, Needed, IResult}; @@ -1079,7 +1084,17 @@ where } } -/// Range fold +/// Applies a parser and accumulates the results using a given +/// function and initial value. +/// Fails if the amount of time the embedded parser is run is not +/// within the specified range. +/// +/// # Arguments +/// * `range` The amount of times to apply the parser. +/// * `parse` The parser to apply. +/// * `init` A function returning the initial value. +/// * `fold` The function that combines a result of `f` with +/// the current accumulator. /// ```rust /// # #[macro_use] extern crate nom; /// # use nom::{Err, error::ErrorKind, Needed, IResult}; @@ -1166,12 +1181,12 @@ where } } -/// +/// Allows conversion of a type into a RangeBound. pub trait IntoRangeBounds where T: RangeBounds { - /// + /// Convert to a RangeBound fn convert(self) -> T; } From 9644b7fc7c75e7b948d66a5d0070322d18e656ae Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 18 Sep 2021 00:57:08 +0200 Subject: [PATCH 06/38] Fix formatting --- src/multi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 6fc1e5dd0..30c217118 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -1026,7 +1026,7 @@ where F: Parser, E: ParseError, G: IntoRangeBounds, - H: RangeBounds + H: RangeBounds, { let range = range.convert(); move |mut input: I| { From 8e5c840e19e1c69ceb53669e34bc25e2300348f7 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 18 Sep 2021 01:02:28 +0200 Subject: [PATCH 07/38] Move IntoRangeBounds trait into traits.rs --- src/multi/mod.rs | 22 +--------------------- src/traits.rs | 22 ++++++++++++++++++++++ 2 files changed, 23 insertions(+), 21 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 30c217118..05bf4632b 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -8,7 +8,7 @@ use crate::error::ParseError; use crate::internal::{Err, IResult, Needed, Parser}; #[cfg(feature = "alloc")] use crate::lib::std::vec::Vec; -use crate::traits::{InputLength, InputTake, ToUsize}; +use crate::traits::{InputLength, InputTake, ToUsize, IntoRangeBounds}; use core::num::NonZeroUsize; use core::ops::{RangeBounds, Bound}; @@ -1180,23 +1180,3 @@ where Ok((input, acc)) } } - -/// Allows conversion of a type into a RangeBound. -pub trait IntoRangeBounds -where - T: RangeBounds -{ - /// Convert to a RangeBound - fn convert(self) -> T; -} - -impl IntoRangeBounds for T -where - T: RangeBounds -{ - fn convert(self) -> T {self} -} - -impl IntoRangeBounds> for usize { - fn convert(self) -> std::ops::RangeInclusive {self..=self} -} diff --git a/src/traits.rs b/src/traits.rs index a073fd3da..28ca9190b 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -9,6 +9,8 @@ use crate::lib::std::str::CharIndices; use crate::lib::std::str::Chars; use crate::lib::std::str::FromStr; +use core::ops::RangeBounds; + #[cfg(feature = "alloc")] use crate::lib::std::string::String; #[cfg(feature = "alloc")] @@ -1395,6 +1397,26 @@ impl HexDisplay for str { } } +/// Allows conversion of a type into a RangeBound. +pub trait IntoRangeBounds +where + T: RangeBounds +{ + /// Convert to a RangeBound + fn convert(self) -> T; +} + +impl IntoRangeBounds for T +where + T: RangeBounds +{ + fn convert(self) -> T {self} +} + +impl IntoRangeBounds> for usize { + fn convert(self) -> std::ops::RangeInclusive {self..=self} +} + #[cfg(test)] mod tests { use super::*; From 2dad2758bb2185bfaf3aa5c381f95b35a3a85cad Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 18 Sep 2021 01:09:47 +0200 Subject: [PATCH 08/38] Deprecate obsolete functions --- src/multi/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 05bf4632b..bd86dd397 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -38,6 +38,7 @@ use core::ops::{RangeBounds, Bound}; /// ``` #[cfg(feature = "alloc")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] +#[deprecated = "Replaced with `many`"] pub fn many0(mut f: F) -> impl FnMut(I) -> IResult, E> where I: Clone + InputLength, @@ -93,6 +94,7 @@ where /// ``` #[cfg(feature = "alloc")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] +#[deprecated = "Replaced with `many`"] pub fn many1(mut f: F) -> impl FnMut(I) -> IResult, E> where I: Clone + InputLength, @@ -350,6 +352,7 @@ where /// ``` #[cfg(feature = "alloc")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] +#[deprecated = "Replaced with `many`"] pub fn many_m_n( min: usize, max: usize, @@ -638,6 +641,7 @@ where /// assert_eq!(parser("123123"), Ok(("123123", vec![]))); /// assert_eq!(parser(""), Ok(("", vec![]))); /// ``` +#[deprecated = "Replaced with `fold`"] pub fn fold_many0( mut f: F, mut init: H, @@ -709,6 +713,7 @@ where /// assert_eq!(parser("123123"), Err(Err::Error(Error::new("123123", ErrorKind::Many1)))); /// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Many1)))); /// ``` +#[deprecated = "Replaced with `fold`"] pub fn fold_many1( mut f: F, mut init: H, @@ -793,6 +798,7 @@ where /// assert_eq!(parser(""), Ok(("", vec![]))); /// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); /// ``` +#[deprecated = "Replaced with `fold`"] pub fn fold_many_m_n( min: usize, max: usize, From cd48ff087ba7b451eb0a09f11c0f072c921c8793 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 18 Sep 2021 01:13:06 +0200 Subject: [PATCH 09/38] Rename fold_many to fold --- src/multi/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index bd86dd397..3be8e46c1 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -1125,7 +1125,7 @@ where /// assert_eq!(parser(""), Ok(("", vec![]))); /// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); /// ``` -pub fn fold_many( +pub fn fold( range: J, mut parse: F, mut init: H, From d67bafb77a2037a768cf52d5509936d3c14337de Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 18 Sep 2021 13:00:36 +0200 Subject: [PATCH 10/38] Add proper error types, Fix corner cases with unbounded and inclusive ranges, add tests --- src/error.rs | 6 ++ src/multi/mod.rs | 89 +++++++++++++++++------- src/multi/tests.rs | 169 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 238 insertions(+), 26 deletions(-) diff --git a/src/error.rs b/src/error.rs index 498b5e135..17024875a 100644 --- a/src/error.rs +++ b/src/error.rs @@ -417,6 +417,8 @@ pub enum ErrorKind { Float, Satisfy, Fail, + Many, + Fold, } #[rustfmt::skip] @@ -477,6 +479,8 @@ pub fn error_to_u32(e: &ErrorKind) -> u32 { ErrorKind::Float => 73, ErrorKind::Satisfy => 74, ErrorKind::Fail => 75, + ErrorKind::Many => 76, + ErrorKind::Fold => 77, } } @@ -539,6 +543,8 @@ impl ErrorKind { ErrorKind::Float => "Float", ErrorKind::Satisfy => "Satisfy", ErrorKind::Fail => "Fail", + ErrorKind::Many => "Many", + ErrorKind::Fold => "Fold", } } } diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 3be8e46c1..716a40ad8 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -1037,27 +1037,49 @@ where let range = range.convert(); move |mut input: I| { let start = match range.start_bound() { - Bound::Included(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))), - Bound::Excluded(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))), + Bound::Included(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::Many))), + Bound::Excluded(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::Many))), Bound::Included(start) => Some(*start), Bound::Excluded(start) => Some(*start + 1), _ => None, }; - if let Bound::Unbounded = range.end_bound() { - return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))); - } - let mut res = crate::lib::std::vec::Vec::with_capacity(start.unwrap_or(0)); - let mut count = 0; + let mut count: usize = 0; + let mut exhausted = false; loop { - count += 1; - if match range.end_bound() { - Bound::Included(end) => count > *end, - Bound::Excluded(end) => count >= *end, - _ => false, + if match (count.saturating_add(1), range.end_bound()) { + (count, Bound::Included(end)) => { + if count > *end { + true + } else { + if (count == usize::MAX) && !exhausted { + if !exhausted { + exhausted = true; + false + } else { + true + } + } else { + false + } + } + }, + (count, Bound::Excluded(end)) => count >= *end, + (count, Bound::Unbounded)=> { + if count == usize::MAX { + if !exhausted { + exhausted = true; + false + } else { + true + } + } else { + false + } + } } { break; } @@ -1067,15 +1089,16 @@ where Ok((tail, value)) => { // infinite loop check: the parser must always consume if tail.input_len() == len { - return Err(Err::Error(E::from_error_kind(input, ErrorKind::ManyMN))); + return Err(Err::Error(E::from_error_kind(input, ErrorKind::Many))); } res.push(value); input = tail; + count = count.saturating_add(1); } Err(Err::Error(e)) => { - if count < start.unwrap_or(0) { - return Err(Err::Error(E::append(input, ErrorKind::ManyMN, e))); + if !range.contains(&count) { + return Err(Err::Error(E::append(input, ErrorKind::Many, e))); } else { return Ok((input, res)); } @@ -1104,11 +1127,11 @@ where /// ```rust /// # #[macro_use] extern crate nom; /// # use nom::{Err, error::ErrorKind, Needed, IResult}; -/// use nom::multi::fold_many; +/// use nom::multi::fold; /// use nom::bytes::complete::tag; /// /// fn parser(s: &str) -> IResult<&str, Vec<&str>> { -/// fold_many( +/// fold( /// 0..=2, /// tag("abc"), /// Vec::new, @@ -1143,18 +1166,33 @@ where let range = range.convert(); move |mut input: I| { match range.start_bound() { - Bound::Included(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))), - Bound::Excluded(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::ManyMN))), + Bound::Included(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::Fold))), + Bound::Excluded(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::Fold))), _ => {}, } let mut acc = init(); let mut count: usize = 0; + let mut exhausted = false; loop { - count = count.saturating_add(1); - if match range.end_bound() { - Bound::Included(end) => count > *end, - Bound::Excluded(end) => count >= *end, + if match (count.saturating_add(1), range.end_bound()) { + (count, Bound::Included(end)) => { + if count > *end { + true + } else { + if (count == usize::MAX) && !exhausted { + if !exhausted { + exhausted = true; + false + } else { + true + } + } else { + false + } + } + }, + (count, Bound::Excluded(end)) => count >= *end, _ => false, } { break; @@ -1165,16 +1203,17 @@ where Ok((tail, value)) => { // infinite loop check: the parser must always consume if tail.input_len() == len { - return Err(Err::Error(E::from_error_kind(tail, ErrorKind::ManyMN))); + return Err(Err::Error(E::from_error_kind(tail, ErrorKind::Fold))); } acc = fold(acc, value); input = tail; + count = count.saturating_add(1); } //FInputXMError: handle failure properly Err(Err::Error(err)) => { if !range.contains(&count) { - return Err(Err::Error(E::append(input, ErrorKind::ManyMN, err))); + return Err(Err::Error(E::append(input, ErrorKind::Fold, err))); } else { break; } diff --git a/src/multi/tests.rs b/src/multi/tests.rs index 2a96f845b..6c6bd0387 100644 --- a/src/multi/tests.rs +++ b/src/multi/tests.rs @@ -13,7 +13,7 @@ use crate::{ lib::std::vec::Vec, multi::{ count, fold_many0, fold_many1, fold_many_m_n, length_count, many0, many1, many_m_n, many_till, - separated_list0, separated_list1, + separated_list0, separated_list1, many, fold, }, }; @@ -542,3 +542,170 @@ fn many1_count_test() { ))) ); } + +#[test] +#[cfg(feature= "alloc")] +fn many_test() { + fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + many(0.., tag("abcd"))(i) + } + fn multi_empty(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + many(0.., tag(""))(i) + } + + assert_eq!(multi(&b"abcdef"[..]), Ok((&b"ef"[..], vec![&b"abcd"[..]]))); + assert_eq!( + multi(&b"abcdabcdefgh"[..]), + Ok((&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]])) + ); + assert_eq!(multi(&b"azerty"[..]), Ok((&b"azerty"[..], Vec::new()))); + assert_eq!(multi(&b"abcdab"[..]), Err(Err::Incomplete(Needed::new(2)))); + assert_eq!(multi(&b"abcd"[..]), Err(Err::Incomplete(Needed::new(4)))); + assert_eq!(multi(&b""[..]), Err(Err::Incomplete(Needed::new(4)))); + assert_eq!( + multi_empty(&b"abcdef"[..]), + Err(Err::Error(error_position!( + &b"abcdef"[..], + ErrorKind::Many + ))) + ); + + + fn multi1(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + many(1.., tag("abcd"))(i) + } + + let a = &b"abcdef"[..]; + let b = &b"abcdabcdefgh"[..]; + let c = &b"azerty"[..]; + let d = &b"abcdab"[..]; + + let res1 = vec![&b"abcd"[..]]; + assert_eq!(multi1(a), Ok((&b"ef"[..], res1))); + let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; + assert_eq!(multi1(b), Ok((&b"efgh"[..], res2))); + assert_eq!( + multi1(c), + Err(Err::Error(error_position!(c, ErrorKind::Tag))) + ); + assert_eq!(multi1(d), Err(Err::Incomplete(Needed::new(2)))); + + + fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { + println!("input: {:?}", input); + Err(Err::Error(error_position!(input, ErrorKind::Tag))) + } + + // should not go into an infinite loop + fn multi0(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + many(0.., tst)(i) + } + let a = &b"abcdef"[..]; + assert_eq!(multi0(a), Ok((a, Vec::new()))); + + fn multi1_2(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + many(1.., tst)(i) + } + let a = &b"abcdef"[..]; + assert_eq!( + multi1_2(a), + Err(Err::Error(error_position!(a, ErrorKind::Tag))) + ); + + + fn multi_m_n(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + many(2..=4, tag("Abcd"))(i) + } + + let a = &b"Abcdef"[..]; + let b = &b"AbcdAbcdefgh"[..]; + let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; + let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; + let e = &b"AbcdAb"[..]; + + assert_eq!( + multi_m_n(a), + Err(Err::Error(error_position!(&b"ef"[..], ErrorKind::Tag))) + ); + let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!(multi_m_n(b), Ok((&b"efgh"[..], res1))); + let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!(multi_m_n(c), Ok((&b"efgh"[..], res2))); + let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!(multi_m_n(d), Ok((&b"Abcdefgh"[..], res3))); + assert_eq!(multi_m_n(e), Err(Err::Incomplete(Needed::new(2)))); +} + +#[test] +fn fold_test() { + fn fold_into_vec(mut acc: Vec, item: T) -> Vec { + acc.push(item); + acc + } + fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fold(0.., tag("abcd"), Vec::new, fold_into_vec)(i) + } + fn multi_empty(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fold(0.., tag(""), Vec::new, fold_into_vec)(i) + } + + assert_eq!(multi(&b"abcdef"[..]), Ok((&b"ef"[..], vec![&b"abcd"[..]]))); + assert_eq!( + multi(&b"abcdabcdefgh"[..]), + Ok((&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]])) + ); + assert_eq!(multi(&b"azerty"[..]), Ok((&b"azerty"[..], Vec::new()))); + assert_eq!(multi(&b"abcdab"[..]), Err(Err::Incomplete(Needed::new(2)))); + assert_eq!(multi(&b"abcd"[..]), Err(Err::Incomplete(Needed::new(4)))); + assert_eq!(multi(&b""[..]), Err(Err::Incomplete(Needed::new(4)))); + assert_eq!( + multi_empty(&b"abcdef"[..]), + Err(Err::Error(error_position!( + &b"abcdef"[..], + ErrorKind::Fold + ))) + ); + + + fn multi1(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fold(1.., tag("abcd"), Vec::new, fold_into_vec)(i) + } + + let a = &b"abcdef"[..]; + let b = &b"abcdabcdefgh"[..]; + let c = &b"azerty"[..]; + let d = &b"abcdab"[..]; + + let res1 = vec![&b"abcd"[..]]; + assert_eq!(multi1(a), Ok((&b"ef"[..], res1))); + let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; + assert_eq!(multi1(b), Ok((&b"efgh"[..], res2))); + assert_eq!( + multi1(c), + Err(Err::Error(error_position!(c, ErrorKind::Tag))) + ); + assert_eq!(multi1(d), Err(Err::Incomplete(Needed::new(2)))); + + + fn multi_m_n(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fold(2..=4, tag("Abcd"), Vec::new, fold_into_vec)(i) + } + + let a = &b"Abcdef"[..]; + let b = &b"AbcdAbcdefgh"[..]; + let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; + let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; + let e = &b"AbcdAb"[..]; + + assert_eq!( + multi_m_n(a), + Err(Err::Error(error_position!(&b"ef"[..], ErrorKind::Tag))) + ); + let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!(multi_m_n(b), Ok((&b"efgh"[..], res1))); + let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!(multi_m_n(c), Ok((&b"efgh"[..], res2))); + let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!(multi_m_n(d), Ok((&b"Abcdefgh"[..], res3))); + assert_eq!(multi_m_n(e), Err(Err::Incomplete(Needed::new(2)))); +} From 3f814c5dd89cf77316f03cf0f87aa3b3609115ab Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 18 Sep 2021 13:09:46 +0200 Subject: [PATCH 11/38] Add tests for usize -> range. Document behaviour of unbounded ranges. --- src/multi/mod.rs | 6 ++++-- src/multi/tests.rs | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 45 insertions(+), 2 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 716a40ad8..9b13339c5 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -1003,7 +1003,8 @@ where /// Fails if the amount of time the embedded parser is run is not /// within the specified range. /// # Arguments -/// * `range` The amount of times to apply the parser. +/// * `range` The amount of times to apply the parser. A range without +/// an upper bound is the same as `(lower..=usize::MAX)`. /// * `parse` The parser to apply. /// ```rust /// # #[macro_use] extern crate nom; @@ -1119,7 +1120,8 @@ where /// within the specified range. /// /// # Arguments -/// * `range` The amount of times to apply the parser. +/// * `range` The amount of times to apply the parser. A range without +/// an upper bound means the parser can run infinitely. /// * `parse` The parser to apply. /// * `init` A function returning the initial value. /// * `fold` The function that combines a result of `f` with diff --git a/src/multi/tests.rs b/src/multi/tests.rs index 6c6bd0387..bedf52f89 100644 --- a/src/multi/tests.rs +++ b/src/multi/tests.rs @@ -634,6 +634,27 @@ fn many_test() { let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; assert_eq!(multi_m_n(d), Ok((&b"Abcdefgh"[..], res3))); assert_eq!(multi_m_n(e), Err(Err::Incomplete(Needed::new(2)))); + + + fn multi_fixed(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + many(2, tag("Abcd"))(i) + } + + let a = &b"Abcdef"[..]; + let b = &b"AbcdAbcdefgh"[..]; + let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; + let d = &b"AbcdAb"[..]; + + assert_eq!( + multi_fixed(a), + Err(Err::Error(error_position!(&b"ef"[..], ErrorKind::Tag))) + ); + + let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!(multi_fixed(b), Ok((&b"efgh"[..], res1))); + let res2 = vec![&b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!(multi_fixed(c), Ok((&b"AbcdAbcdefgh"[..], res2))); + assert_eq!(multi_fixed(d), Err(Err::Incomplete(Needed::new(2)))); } #[test] @@ -708,4 +729,24 @@ fn fold_test() { let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; assert_eq!(multi_m_n(d), Ok((&b"Abcdefgh"[..], res3))); assert_eq!(multi_m_n(e), Err(Err::Incomplete(Needed::new(2)))); + + fn multi_fixed(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fold(2, tag("Abcd"), Vec::new, fold_into_vec)(i) + } + + let a = &b"Abcdef"[..]; + let b = &b"AbcdAbcdefgh"[..]; + let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; + let d = &b"AbcdAb"[..]; + + assert_eq!( + multi_fixed(a), + Err(Err::Error(error_position!(&b"ef"[..], ErrorKind::Tag))) + ); + + let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!(multi_fixed(b), Ok((&b"efgh"[..], res1))); + let res2 = vec![&b"Abcd"[..], &b"Abcd"[..]]; + assert_eq!(multi_fixed(c), Ok((&b"AbcdAbcdefgh"[..], res2))); + assert_eq!(multi_fixed(d), Err(Err::Incomplete(Needed::new(2)))); } From 346c738facf21ae1fcaf87beebcdbb53b65bb370 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 18 Sep 2021 13:23:12 +0200 Subject: [PATCH 12/38] Migrate examples and tests to use ranged parsers instead --- examples/s_expression.rs | 6 +++--- examples/string.rs | 9 +++++---- src/multi/tests.rs | 8 ++++++++ src/str.rs | 4 ++-- tests/arithmetic.rs | 8 +++++--- tests/arithmetic_ast.rs | 6 +++--- tests/fnmut.rs | 4 ++-- tests/ini.rs | 8 ++++---- tests/ini_str.rs | 6 +++--- tests/issues.rs | 8 ++++---- tests/json.rs | 4 ++-- tests/mp4.rs | 4 ++-- tests/multiline.rs | 4 ++-- tests/overflow.rs | 16 ++++++---------- tests/reborrow_fold.rs | 4 ++-- 15 files changed, 53 insertions(+), 46 deletions(-) diff --git a/examples/s_expression.rs b/examples/s_expression.rs index 703097054..a1f74de20 100644 --- a/examples/s_expression.rs +++ b/examples/s_expression.rs @@ -13,7 +13,7 @@ use nom::{ character::complete::{alpha1, char, digit1, multispace0, multispace1, one_of}, combinator::{cut, map, map_res, opt}, error::{context, VerboseError}, - multi::many0, + multi::many, sequence::{delimited, preceded, terminated, tuple}, IResult, Parser, }; @@ -176,7 +176,7 @@ where /// `tuple` is used to sequence parsers together, so we can translate this directly /// and then map over it to transform the output into an `Expr::Application` fn parse_application<'a>(i: &'a str) -> IResult<&'a str, Expr, VerboseError<&'a str>> { - let application_inner = map(tuple((parse_expr, many0(parse_expr))), |(head, tail)| { + let application_inner = map(tuple((parse_expr, many(0.., parse_expr))), |(head, tail)| { Expr::Application(Box::new(head), tail) }); // finally, we wrap it in an s-expression @@ -226,7 +226,7 @@ fn parse_quote<'a>(i: &'a str) -> IResult<&'a str, Expr, VerboseError<&'a str>> // we find the `'` (quote) character, use cut to say that we're unambiguously // looking for an s-expression of 0 or more expressions, and then parse them map( - context("quote", preceded(tag("'"), cut(s_exp(many0(parse_expr))))), + context("quote", preceded(tag("'"), cut(s_exp(many(0.., parse_expr))))), |exprs| Expr::Quote(exprs), )(i) } diff --git a/examples/string.rs b/examples/string.rs index f89d3d126..896a32992 100644 --- a/examples/string.rs +++ b/examples/string.rs @@ -19,7 +19,7 @@ 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::{FromExternalError, ParseError}; -use nom::multi::fold_many0; +use nom::multi::fold; use nom::sequence::{delimited, preceded}; use nom::IResult; @@ -139,9 +139,10 @@ fn parse_string<'a, E>(input: &'a str) -> IResult<&'a str, String, E> where E: ParseError<&'a str> + FromExternalError<&'a str, std::num::ParseIntError>, { - // fold_many0 is the equivalent of iterator::fold. It runs a parser in a loop, + // fold 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( + let build_string = fold( + 0.., // Our parser function– parses a single string fragment parse_fragment, // Our init value, an empty string @@ -160,7 +161,7 @@ where // 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 + // `delimited` with a looping parser (like fold), be sure that the // loop won't accidentally match your closing delimiter! delimited(char('"'), build_string, char('"'))(input) } diff --git a/src/multi/tests.rs b/src/multi/tests.rs index bedf52f89..85e6bcf08 100644 --- a/src/multi/tests.rs +++ b/src/multi/tests.rs @@ -9,6 +9,7 @@ use crate::{ sequence::{pair, tuple}, }; #[cfg(feature = "alloc")] +#[allow(deprecated)] use crate::{ lib::std::vec::Vec, multi::{ @@ -103,6 +104,7 @@ fn separated_list1_test() { #[test] #[cfg(feature = "alloc")] +#[allow(deprecated)] fn many0_test() { fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { many0(tag("abcd"))(i) @@ -141,6 +143,7 @@ fn many0_bench(b: &mut Bencher) { #[test] #[cfg(feature = "alloc")] +#[allow(deprecated)] fn many1_test() { fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { many1(tag("abcd"))(i) @@ -189,6 +192,7 @@ fn many_till_test() { #[test] #[cfg(feature = "std")] +#[allow(deprecated)] fn infinite_many() { fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { println!("input: {:?}", input); @@ -214,6 +218,7 @@ fn infinite_many() { #[test] #[cfg(feature = "alloc")] +#[allow(deprecated)] fn many_m_n_test() { fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { many_m_n(2, 4, tag("Abcd"))(i) @@ -416,6 +421,7 @@ fn length_value_test() { #[test] #[cfg(feature = "alloc")] +#[allow(deprecated)] fn fold_many0_test() { fn fold_into_vec(mut acc: Vec, item: T) -> Vec { acc.push(item); @@ -448,6 +454,7 @@ fn fold_many0_test() { #[test] #[cfg(feature = "alloc")] +#[allow(deprecated)] fn fold_many1_test() { fn fold_into_vec(mut acc: Vec, item: T) -> Vec { acc.push(item); @@ -475,6 +482,7 @@ fn fold_many1_test() { #[test] #[cfg(feature = "alloc")] +#[allow(deprecated)] fn fold_many_m_n_test() { fn fold_into_vec(mut acc: Vec, item: T) -> Vec { acc.push(item); diff --git a/src/str.rs b/src/str.rs index e8d38c6c2..a9982377a 100644 --- a/src/str.rs +++ b/src/str.rs @@ -1,7 +1,7 @@ #[cfg(test)] mod test { #[cfg(feature = "alloc")] - use crate::{branch::alt, bytes::complete::tag_no_case, combinator::recognize, multi::many1}; + use crate::{branch::alt, bytes::complete::tag_no_case, combinator::recognize, multi::many}; use crate::{ bytes::complete::{is_a, is_not, tag, take, take_till, take_until}, error::{self, ErrorKind}, @@ -507,7 +507,7 @@ mod test { let b = "ababcd"; fn f(i: &str) -> IResult<&str, &str> { - recognize(many1(alt((tag("a"), tag("b")))))(i) + recognize(many(1.., alt((tag("a"), tag("b")))))(i) } assert_eq!(f(&a[..]), Ok((&a[6..], &a[..]))); diff --git a/tests/arithmetic.rs b/tests/arithmetic.rs index 5b627a97a..6f600162e 100644 --- a/tests/arithmetic.rs +++ b/tests/arithmetic.rs @@ -4,7 +4,7 @@ use nom::{ character::complete::char, character::complete::{digit1 as digit, space0 as space}, combinator::map_res, - multi::fold_many0, + multi::fold, sequence::{delimited, pair}, IResult, }; @@ -35,7 +35,8 @@ fn factor(i: &str) -> IResult<&str, i64> { fn term(i: &str) -> IResult<&str, i64> { let (i, init) = factor(i)?; - fold_many0( + fold( + 0.., pair(alt((char('*'), char('/'))), factor), move || init, |acc, (op, val): (char, i64)| { @@ -51,7 +52,8 @@ fn term(i: &str) -> IResult<&str, i64> { fn expr(i: &str) -> IResult<&str, i64> { let (i, init) = term(i)?; - fold_many0( + fold( + 0.., pair(alt((char('+'), char('-'))), term), move || init, |acc, (op, val): (char, i64)| { diff --git a/tests/arithmetic_ast.rs b/tests/arithmetic_ast.rs index ca1511096..b2e67450a 100644 --- a/tests/arithmetic_ast.rs +++ b/tests/arithmetic_ast.rs @@ -8,7 +8,7 @@ use nom::{ bytes::complete::tag, character::complete::{digit1 as digit, multispace0 as multispace}, combinator::{map, map_res}, - multi::many0, + multi::many, sequence::{delimited, preceded}, IResult, }; @@ -90,7 +90,7 @@ fn fold_exprs(initial: Expr, remainder: Vec<(Oper, Expr)>) -> Expr { fn term(i: &str) -> IResult<&str, Expr> { let (i, initial) = factor(i)?; - let (i, remainder) = many0(alt(( + let (i, remainder) = many(0.., alt(( |i| { let (i, mul) = preceded(tag("*"), factor)(i)?; Ok((i, (Oper::Mul, mul))) @@ -106,7 +106,7 @@ fn term(i: &str) -> IResult<&str, Expr> { fn expr(i: &str) -> IResult<&str, Expr> { let (i, initial) = term(i)?; - let (i, remainder) = many0(alt(( + let (i, remainder) = many(0.., alt(( |i| { let (i, add) = preceded(tag("+"), term)(i)?; Ok((i, (Oper::Add, add))) diff --git a/tests/fnmut.rs b/tests/fnmut.rs index b1486cbe6..0b678b6eb 100644 --- a/tests/fnmut.rs +++ b/tests/fnmut.rs @@ -1,6 +1,6 @@ use nom::{ bytes::complete::tag, - multi::{many0, many0_count}, + multi::{many, many0_count}, }; #[test] @@ -8,7 +8,7 @@ fn parse() { let mut counter = 0; let res = { - let mut parser = many0::<_, _, (), _>(|i| { + let mut parser = many::<_, _, (), _, _, _>(0.., |i| { counter += 1; tag("abc")(i) }); diff --git a/tests/ini.rs b/tests/ini.rs index e556f44a3..f74c4c9e3 100644 --- a/tests/ini.rs +++ b/tests/ini.rs @@ -4,7 +4,7 @@ use nom::{ alphanumeric1 as alphanumeric, char, multispace0 as multispace, space0 as space, }, combinator::{map, map_res, opt}, - multi::many0, + multi::many, sequence::{delimited, pair, separated_pair, terminated, tuple}, IResult, }; @@ -28,7 +28,7 @@ fn key_value(i: &[u8]) -> IResult<&[u8], (&str, &str)> { } fn keys_and_values(i: &[u8]) -> IResult<&[u8], HashMap<&str, &str>> { - map(many0(terminated(key_value, opt(multispace))), |vec| { + map(many(0.., terminated(key_value, opt(multispace))), |vec| { vec.into_iter().collect() })(i) } @@ -41,11 +41,11 @@ fn category_and_keys(i: &[u8]) -> IResult<&[u8], (&str, HashMap<&str, &str>)> { fn categories(i: &[u8]) -> IResult<&[u8], HashMap<&str, HashMap<&str, &str>>> { map( - many0(separated_pair( + many(0.., separated_pair( category, opt(multispace), map( - many0(terminated(key_value, opt(multispace))), + many(0.., terminated(key_value, opt(multispace))), |vec: Vec<_>| vec.into_iter().collect(), ), )), diff --git a/tests/ini_str.rs b/tests/ini_str.rs index 370230352..6a9c14257 100644 --- a/tests/ini_str.rs +++ b/tests/ini_str.rs @@ -2,7 +2,7 @@ use nom::{ bytes::complete::{is_a, tag, take_till, take_while}, character::complete::{alphanumeric1 as alphanumeric, char, space0 as space}, combinator::opt, - multi::many0, + multi::many, sequence::{delimited, pair, terminated, tuple}, IResult, }; @@ -40,7 +40,7 @@ fn key_value(i: &str) -> IResult<&str, (&str, &str)> { } fn keys_and_values_aggregator(i: &str) -> IResult<&str, Vec<(&str, &str)>> { - many0(key_value)(i) + many(0.., key_value)(i) } fn keys_and_values(input: &str) -> IResult<&str, HashMap<&str, &str>> { @@ -55,7 +55,7 @@ fn category_and_keys(i: &str) -> IResult<&str, (&str, HashMap<&str, &str>)> { } fn categories_aggregator(i: &str) -> IResult<&str, Vec<(&str, HashMap<&str, &str>)>> { - many0(category_and_keys)(i) + many(0.., category_and_keys)(i) } fn categories(input: &str) -> IResult<&str, HashMap<&str, HashMap<&str, &str>>> { diff --git a/tests/issues.rs b/tests/issues.rs index 79c3493b7..16ce39095 100644 --- a/tests/issues.rs +++ b/tests/issues.rs @@ -24,13 +24,13 @@ mod parse_int { use nom::{ character::streaming::{digit1 as digit, space1 as space}, combinator::{complete, map, opt}, - multi::many0, + multi::many, IResult, }; use std::str; fn parse_ints(input: &[u8]) -> IResult<&[u8], Vec> { - many0(spaces_or_int)(input) + many(0.., spaces_or_int)(input) } fn spaces_or_int(input: &[u8]) -> IResult<&[u8], i32> { @@ -170,8 +170,8 @@ fn issue_942() { #[test] fn issue_many_m_n_with_zeros() { use nom::character::complete::char; - use nom::multi::many_m_n; - let mut parser = many_m_n::<_, _, (), _>(0, 0, char('a')); + use nom::multi::many; + let mut parser = many::<_, _, (), _, _, _>(0..=0, char('a')); assert_eq!(parser("aaa"), Ok(("aaa", vec!()))); } diff --git a/tests/json.rs b/tests/json.rs index e8a06fd77..417fe4bbc 100644 --- a/tests/json.rs +++ b/tests/json.rs @@ -6,7 +6,7 @@ use nom::{ character::complete::{anychar, char, multispace0, none_of}, combinator::{map, map_opt, map_res, value, verify}, error::ParseError, - multi::{fold_many0, separated_list0}, + multi::{fold, separated_list0}, number::complete::double, sequence::{delimited, preceded, separated_pair}, IResult, Parser, @@ -82,7 +82,7 @@ fn character(input: &str) -> IResult<&str, char> { fn string(input: &str) -> IResult<&str, String> { delimited( char('"'), - fold_many0(character, String::new, |mut string, c| { + fold(0.., character, String::new, |mut string, c| { string.push(c); string }), diff --git a/tests/mp4.rs b/tests/mp4.rs index 852bf2955..024929f91 100644 --- a/tests/mp4.rs +++ b/tests/mp4.rs @@ -5,7 +5,7 @@ use nom::{ bytes::streaming::{tag, take}, combinator::{map, map_res}, error::ErrorKind, - multi::many0, + multi::many, number::streaming::{be_f32, be_u16, be_u32, be_u64}, Err, IResult, Needed, }; @@ -250,7 +250,7 @@ fn brand_name(input: &[u8]) -> IResult<&[u8], &str> { fn filetype_parser(input: &[u8]) -> IResult<&[u8], FileType<'_>> { let (i, name) = brand_name(input)?; let (i, version) = take(4_usize)(i)?; - let (i, brands) = many0(brand_name)(i)?; + let (i, brands) = many(0.., brand_name)(i)?; let ft = FileType { major_brand: name, diff --git a/tests/multiline.rs b/tests/multiline.rs index 7378b9e3b..b5d3c1f32 100644 --- a/tests/multiline.rs +++ b/tests/multiline.rs @@ -1,6 +1,6 @@ use nom::{ character::complete::{alphanumeric1 as alphanumeric, line_ending as eol}, - multi::many0, + multi::many, sequence::terminated, IResult, }; @@ -18,7 +18,7 @@ pub fn read_line(input: &str) -> IResult<&str, &str> { } pub fn read_lines(input: &str) -> IResult<&str, Vec<&str>> { - many0(read_line)(input) + many(0.., read_line)(input) } #[cfg(feature = "alloc")] diff --git a/tests/overflow.rs b/tests/overflow.rs index ea513bb39..7043c3320 100644 --- a/tests/overflow.rs +++ b/tests/overflow.rs @@ -3,7 +3,7 @@ use nom::bytes::streaming::take; #[cfg(feature = "alloc")] -use nom::multi::{length_data, many0}; +use nom::multi::{length_data, many}; #[cfg(feature = "alloc")] use nom::number::streaming::be_u64; use nom::sequence::tuple; @@ -28,7 +28,7 @@ fn overflow_incomplete_tuple() { #[cfg(feature = "alloc")] fn overflow_incomplete_length_bytes() { fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - many0(length_data(be_u64))(i) + many(0.., length_data(be_u64))(i) } // Trigger an overflow in length_data @@ -42,7 +42,7 @@ fn overflow_incomplete_length_bytes() { #[cfg(feature = "alloc")] fn overflow_incomplete_many0() { fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - many0(length_data(be_u64))(i) + many(0.., length_data(be_u64))(i) } // Trigger an overflow in many0 @@ -55,10 +55,8 @@ fn overflow_incomplete_many0() { #[test] #[cfg(feature = "alloc")] fn overflow_incomplete_many1() { - use nom::multi::many1; - fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - many1(length_data(be_u64))(i) + many(1.., length_data(be_u64))(i) } // Trigger an overflow in many1 @@ -87,10 +85,8 @@ fn overflow_incomplete_many_till() { #[test] #[cfg(feature = "alloc")] fn overflow_incomplete_many_m_n() { - use nom::multi::many_m_n; - fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - many_m_n(2, 4, length_data(be_u64))(i) + many(2..=4, length_data(be_u64))(i) } // Trigger an overflow in many_m_n @@ -135,7 +131,7 @@ fn overflow_incomplete_length_count() { #[cfg(feature = "alloc")] fn overflow_incomplete_length_data() { fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - many0(length_data(be_u64))(i) + many(0.., length_data(be_u64))(i) } assert_eq!( diff --git a/tests/reborrow_fold.rs b/tests/reborrow_fold.rs index 486617e42..62d7519c6 100644 --- a/tests/reborrow_fold.rs +++ b/tests/reborrow_fold.rs @@ -6,7 +6,7 @@ use std::str; use nom::bytes::complete::is_not; use nom::character::complete::char; use nom::combinator::{map, map_res}; -use nom::multi::fold_many0; +use nom::multi::fold; use nom::sequence::delimited; use nom::IResult; @@ -23,7 +23,7 @@ fn atom<'a>(_tomb: &'a mut ()) -> impl FnMut(&'a [u8]) -> IResult<&'a [u8], Stri fn list<'a>(i: &'a [u8], tomb: &'a mut ()) -> IResult<&'a [u8], String> { delimited( char('('), - fold_many0(atom(tomb), String::new, |acc: String, next: String| { + fold(0.., atom(tomb), String::new, |acc: String, next: String| { acc + next.as_str() }), char(')'), From bc7a40324246b9683b0528077228180f332fa752 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 18 Sep 2021 16:34:07 +0200 Subject: [PATCH 13/38] Offload range iteration to a seperate struct --- src/multi/mod.rs | 70 ++------------------------ src/traits.rs | 124 ++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 127 insertions(+), 67 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 9b13339c5..a5744060c 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -8,7 +8,7 @@ use crate::error::ParseError; use crate::internal::{Err, IResult, Needed, Parser}; #[cfg(feature = "alloc")] use crate::lib::std::vec::Vec; -use crate::traits::{InputLength, InputTake, ToUsize, IntoRangeBounds}; +use crate::traits::{InputLength, InputTake, ToUsize, IntoRangeBounds, RangeIterator}; use core::num::NonZeroUsize; use core::ops::{RangeBounds, Bound}; @@ -1047,44 +1047,8 @@ where let mut res = crate::lib::std::vec::Vec::with_capacity(start.unwrap_or(0)); - let mut count: usize = 0; - let mut exhausted = false; - loop { - if match (count.saturating_add(1), range.end_bound()) { - (count, Bound::Included(end)) => { - if count > *end { - true - } else { - if (count == usize::MAX) && !exhausted { - if !exhausted { - exhausted = true; - false - } else { - true - } - } else { - false - } - } - }, - (count, Bound::Excluded(end)) => count >= *end, - (count, Bound::Unbounded)=> { - if count == usize::MAX { - if !exhausted { - exhausted = true; - false - } else { - true - } - } else { - false - } - } - } { - break; - } - + for count in range.saturating_iter() { let len = input.input_len(); match parse.parse(input.clone()) { Ok((tail, value)) => { @@ -1095,7 +1059,6 @@ where res.push(value); input = tail; - count = count.saturating_add(1); } Err(Err::Error(e)) => { if !range.contains(&count) { @@ -1174,32 +1137,8 @@ where } let mut acc = init(); - let mut count: usize = 0; - let mut exhausted = false; - loop { - if match (count.saturating_add(1), range.end_bound()) { - (count, Bound::Included(end)) => { - if count > *end { - true - } else { - if (count == usize::MAX) && !exhausted { - if !exhausted { - exhausted = true; - false - } else { - true - } - } else { - false - } - } - }, - (count, Bound::Excluded(end)) => count >= *end, - _ => false, - } { - break; - } - + + for count in range.unbounded_iter() { let len = input.input_len(); match parse.parse(input.clone()) { Ok((tail, value)) => { @@ -1210,7 +1149,6 @@ where acc = fold(acc, value); input = tail; - count = count.saturating_add(1); } //FInputXMError: handle failure properly Err(Err::Error(err)) => { diff --git a/src/traits.rs b/src/traits.rs index 28ca9190b..64be0036d 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -9,7 +9,7 @@ use crate::lib::std::str::CharIndices; use crate::lib::std::str::Chars; use crate::lib::std::str::FromStr; -use core::ops::RangeBounds; +use core::ops::{RangeBounds, Bound}; #[cfg(feature = "alloc")] use crate::lib::std::string::String; @@ -1417,6 +1417,128 @@ impl IntoRangeBounds> for usize { fn convert(self) -> std::ops::RangeInclusive {self..=self} } +/// +pub trait RangeIterator { + /// + fn saturating_iter(&self) -> SaturatingIterator; + /// + fn unbounded_iter(&self) -> UnboundedIterator; +} + +impl RangeIterator for T +where + T: RangeBounds +{ + fn saturating_iter(&self) -> SaturatingIterator { + SaturatingIterator{ + end: match self.end_bound() { + Bound::Included(e) => Bound::Included(*e), + Bound::Excluded(e) => Bound::Excluded(*e), + Bound::Unbounded => Bound::Unbounded, + }, + count: 0, + exhausted: false, + } + } + + fn unbounded_iter(&self) -> UnboundedIterator { + UnboundedIterator{ + end: match self.end_bound() { + Bound::Included(e) => Bound::Included(*e), + Bound::Excluded(e) => Bound::Excluded(*e), + Bound::Unbounded => Bound::Unbounded, + }, + count: 0, + exhausted: false, + } + } +} + +/// +pub struct SaturatingIterator { + end: Bound, + count: usize, + exhausted: bool, +} + +impl Iterator for SaturatingIterator { + type Item = usize; + + fn next(&mut self) -> Option { + let old_count = self.count; + self.count = self.count.saturating_add(1); + match (self.count, self.end) { + (count, Bound::Included(end)) => { + if count > end { + None + } else { + if (count == usize::MAX) && !self.exhausted { + if !self.exhausted { + self.exhausted = true; + Some(old_count) + } else { + None + } + } else { + Some(old_count) + } + } + }, + (count, Bound::Unbounded)=> { + if count == usize::MAX { + if !self.exhausted { + self.exhausted = true; + Some(old_count) + } else { + None + } + } else { + Some(old_count) + } + } + (count, Bound::Excluded(end)) if count >= end => None, + (_, Bound::Excluded(_)) => Some(old_count), + } + } +} + +/// +pub struct UnboundedIterator { + end: Bound, + count: usize, + exhausted: bool, +} + +impl Iterator for UnboundedIterator { + type Item = usize; + + fn next(&mut self) -> Option { + let old_count = self.count; + self.count = self.count.saturating_add(1); + match (self.count, self.end) { + (count, Bound::Included(end)) => { + if count > end { + None + } else { + if (count == usize::MAX) && !self.exhausted { + if !self.exhausted { + self.exhausted = true; + Some(old_count) + } else { + None + } + } else { + Some(old_count) + } + } + }, + (_, Bound::Unbounded) => Some(old_count), + (count, Bound::Excluded(end)) if count >= end => None, + (_, Bound::Excluded(_)) => Some(old_count), + } + } +} + #[cfg(test)] mod tests { use super::*; From d62f02e3a49fd05a669d6dcee6d041fc0a952afb Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 18 Sep 2021 16:43:23 +0200 Subject: [PATCH 14/38] Rename range iterators and add proper documentation --- src/multi/mod.rs | 4 ++-- src/traits.rs | 43 +++++++++++++++++++++++++++++-------------- 2 files changed, 31 insertions(+), 16 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index a5744060c..06665e1df 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -1048,7 +1048,7 @@ where let mut res = crate::lib::std::vec::Vec::with_capacity(start.unwrap_or(0)); - for count in range.saturating_iter() { + for count in range.bounded_iter() { let len = input.input_len(); match parse.parse(input.clone()) { Ok((tail, value)) => { @@ -1138,7 +1138,7 @@ where let mut acc = init(); - for count in range.unbounded_iter() { + for count in range.saturating_iter() { let len = input.input_len(); match parse.parse(input.clone()) { Ok((tail, value)) => { diff --git a/src/traits.rs b/src/traits.rs index 64be0036d..9662cb049 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1417,20 +1417,29 @@ impl IntoRangeBounds> for usize { fn convert(self) -> std::ops::RangeInclusive {self..=self} } -/// +/// Allows iteration over ranges. All iterators start at 0 and +/// count towards the end of the range. Handling of ranges with +/// an unbounded upper limit is dependent on the specific iterator. pub trait RangeIterator { - /// + + /// A bounded iterator. + /// Iterating an unbounded range is equivalent to iterating over a + /// range of `value..=usize::MAX`. + fn bounded_iter(&self) -> BoundedIterator; + + /// A saturating iterator. + /// If the iterator is unbounded and the end of the representable size + /// of `usize` has been reached, this iterator will return usize::MAX + /// infinitely. fn saturating_iter(&self) -> SaturatingIterator; - /// - fn unbounded_iter(&self) -> UnboundedIterator; } impl RangeIterator for T where T: RangeBounds { - fn saturating_iter(&self) -> SaturatingIterator { - SaturatingIterator{ + fn bounded_iter(&self) -> BoundedIterator { + BoundedIterator{ end: match self.end_bound() { Bound::Included(e) => Bound::Included(*e), Bound::Excluded(e) => Bound::Excluded(*e), @@ -1441,8 +1450,8 @@ where } } - fn unbounded_iter(&self) -> UnboundedIterator { - UnboundedIterator{ + fn saturating_iter(&self) -> SaturatingIterator { + SaturatingIterator{ end: match self.end_bound() { Bound::Included(e) => Bound::Included(*e), Bound::Excluded(e) => Bound::Excluded(*e), @@ -1454,14 +1463,17 @@ where } } -/// -pub struct SaturatingIterator { +/// A bounded iterator. +/// Iterates until the end of a `usize` range is reached. +/// If the upper limit is unbounded, this iterator will end when +/// the next element would be greater than `usize::MAX`. +pub struct BoundedIterator { end: Bound, count: usize, exhausted: bool, } -impl Iterator for SaturatingIterator { +impl Iterator for BoundedIterator { type Item = usize; fn next(&mut self) -> Option { @@ -1502,14 +1514,17 @@ impl Iterator for SaturatingIterator { } } -/// -pub struct UnboundedIterator { +/// A saturating iterator. +/// Iterates until the end of a `usize` range is reached. +/// If upper limit is unbounded, this iterator saturates at +/// `usize::MAX`. +pub struct SaturatingIterator { end: Bound, count: usize, exhausted: bool, } -impl Iterator for UnboundedIterator { +impl Iterator for SaturatingIterator { type Item = usize; fn next(&mut self) -> Option { From 617a84751ec86de5ecbd5fde7effff51e160a9e7 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 18 Sep 2021 17:30:51 +0200 Subject: [PATCH 15/38] Fix edge case when Bound::Included(usize::MAX) --- src/traits.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 9662cb049..752b17578 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1484,7 +1484,7 @@ impl Iterator for BoundedIterator { if count > end { None } else { - if (count == usize::MAX) && !self.exhausted { + if (old_count == usize::MAX) && !self.exhausted { if !self.exhausted { self.exhausted = true; Some(old_count) @@ -1497,7 +1497,7 @@ impl Iterator for BoundedIterator { } }, (count, Bound::Unbounded)=> { - if count == usize::MAX { + if old_count == usize::MAX { if !self.exhausted { self.exhausted = true; Some(old_count) @@ -1535,7 +1535,7 @@ impl Iterator for SaturatingIterator { if count > end { None } else { - if (count == usize::MAX) && !self.exhausted { + if (old_count == usize::MAX) && !self.exhausted { if !self.exhausted { self.exhausted = true; Some(old_count) From b103e072af8fd85114313450501d05cd80201242 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 18 Sep 2021 17:38:26 +0200 Subject: [PATCH 16/38] Fix warning and add test for exclusive ranges --- src/multi/tests.rs | 11 +++++++++++ src/traits.rs | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/src/multi/tests.rs b/src/multi/tests.rs index 85e6bcf08..50e336f69 100644 --- a/src/multi/tests.rs +++ b/src/multi/tests.rs @@ -757,4 +757,15 @@ fn fold_test() { let res2 = vec![&b"Abcd"[..], &b"Abcd"[..]]; assert_eq!(multi_fixed(c), Ok((&b"AbcdAbcdefgh"[..], res2))); assert_eq!(multi_fixed(d), Err(Err::Incomplete(Needed::new(2)))); + + fn multi_exclusive(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fold(0..2, tag("Abcd"), Vec::new, fold_into_vec)(i) + } + + let a = &b"AbcdAbcdAbcd"[..]; + let b = &b"AAA"[..]; + let res1 = vec![&b"Abcd"[..]]; + assert_eq!(multi_exclusive(a), Ok((&b"AbcdAbcd"[..], res1))); + let res2 = vec![]; + assert_eq!(multi_exclusive(b), Ok((&b"AAA"[..], res2))); } diff --git a/src/traits.rs b/src/traits.rs index 752b17578..e8141039c 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1496,7 +1496,7 @@ impl Iterator for BoundedIterator { } } }, - (count, Bound::Unbounded)=> { + (_, Bound::Unbounded)=> { if old_count == usize::MAX { if !self.exhausted { self.exhausted = true; From 9ad22e887b814af0202b69fa4cab42147e1d2db6 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sun, 19 Sep 2021 00:44:26 +0200 Subject: [PATCH 17/38] Use core instead of std, Use deprecated version of usize::MAX to remain compatible with MSRV --- src/traits.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index e8141039c..ddc5561e3 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1413,8 +1413,8 @@ where fn convert(self) -> T {self} } -impl IntoRangeBounds> for usize { - fn convert(self) -> std::ops::RangeInclusive {self..=self} +impl IntoRangeBounds> for usize { + fn convert(self) -> core::ops::RangeInclusive {self..=self} } /// Allows iteration over ranges. All iterators start at 0 and @@ -1484,7 +1484,7 @@ impl Iterator for BoundedIterator { if count > end { None } else { - if (old_count == usize::MAX) && !self.exhausted { + if (old_count == core::usize::MAX) && !self.exhausted { if !self.exhausted { self.exhausted = true; Some(old_count) @@ -1497,7 +1497,7 @@ impl Iterator for BoundedIterator { } }, (_, Bound::Unbounded)=> { - if old_count == usize::MAX { + if old_count == core::usize::MAX { if !self.exhausted { self.exhausted = true; Some(old_count) @@ -1535,7 +1535,7 @@ impl Iterator for SaturatingIterator { if count > end { None } else { - if (old_count == usize::MAX) && !self.exhausted { + if (old_count == core::usize::MAX) && !self.exhausted { if !self.exhausted { self.exhausted = true; Some(old_count) From 5c0fb7f01cbeb097fd243bbe8776e00b9c08f8cd Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sun, 19 Sep 2021 00:52:46 +0200 Subject: [PATCH 18/38] Add alloc feature flag for fold tests --- src/multi/tests.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/multi/tests.rs b/src/multi/tests.rs index 50e336f69..eda93a291 100644 --- a/src/multi/tests.rs +++ b/src/multi/tests.rs @@ -552,7 +552,7 @@ fn many1_count_test() { } #[test] -#[cfg(feature= "alloc")] +#[cfg(feature = "alloc")] fn many_test() { fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { many(0.., tag("abcd"))(i) @@ -666,6 +666,7 @@ fn many_test() { } #[test] +#[cfg(feature = "alloc")] fn fold_test() { fn fold_into_vec(mut acc: Vec, item: T) -> Vec { acc.push(item); From de0d6ec72c67b1d9ca95bfa48e5fc00e829322da Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sun, 19 Sep 2021 00:57:13 +0200 Subject: [PATCH 19/38] Remove println macros --- src/multi/tests.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/multi/tests.rs b/src/multi/tests.rs index eda93a291..bcbffe028 100644 --- a/src/multi/tests.rs +++ b/src/multi/tests.rs @@ -195,7 +195,6 @@ fn many_till_test() { #[allow(deprecated)] fn infinite_many() { fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { - println!("input: {:?}", input); Err(Err::Error(error_position!(input, ErrorKind::Tag))) } @@ -600,7 +599,6 @@ fn many_test() { fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { - println!("input: {:?}", input); Err(Err::Error(error_position!(input, ErrorKind::Tag))) } From a37a7288c64e2132e03173c74b6e944b96032b9e Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sun, 19 Sep 2021 03:57:47 +0200 Subject: [PATCH 20/38] Better documentation for the range parameter --- src/multi/mod.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 06665e1df..03732456d 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -1003,8 +1003,10 @@ where /// Fails if the amount of time the embedded parser is run is not /// within the specified range. /// # Arguments -/// * `range` The amount of times to apply the parser. A range without -/// an upper bound is the same as `(lower..=usize::MAX)`. +/// * `range` The amount of times to apply the parser. +/// * A range with an upper bound `a..=b` limits the parser to run at most `b` times. +/// * A range without an upper bound `a..` is equivalent to a range of `a..=usize::MAX`. +/// * An empty range is invalid. /// * `parse` The parser to apply. /// ```rust /// # #[macro_use] extern crate nom; @@ -1083,8 +1085,10 @@ where /// within the specified range. /// /// # Arguments -/// * `range` The amount of times to apply the parser. A range without -/// an upper bound means the parser can run infinitely. +/// * `range` The amount of times to apply the parser. +/// * A range with an upper bound `a..=b` limits the parser to run at most `b` times. +/// * A range without an upper bound `a..` allows the parser to run until it fails. +/// * An empty range is invalid. /// * `parse` The parser to apply. /// * `init` A function returning the initial value. /// * `fold` The function that combines a result of `f` with From b2121cac07042e6839ddf46724401ee55d544cfd Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sun, 19 Sep 2021 22:49:08 +0200 Subject: [PATCH 21/38] Use explicit for loops instead of iterators --- src/multi/mod.rs | 62 ++++++++++++++++++++++++++++++++-------------- src/multi/tests.rs | 10 ++++++++ 2 files changed, 53 insertions(+), 19 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 03732456d..ab5758aee 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -1047,32 +1047,56 @@ where _ => None, }; - let mut res = crate::lib::std::vec::Vec::with_capacity(start.unwrap_or(0)); - for count in range.bounded_iter() { + let mut parser = |count: usize| -> Option>> { let len = input.input_len(); - match parse.parse(input.clone()) { - Ok((tail, value)) => { - // infinite loop check: the parser must always consume - if tail.input_len() == len { - return Err(Err::Error(E::from_error_kind(input, ErrorKind::Many))); - } + match parse.parse(input.clone()) { + Ok((tail, value)) => { + // infinite loop check: the parser must always consume + if tail.input_len() == len { + return Some(Err(Err::Error(E::from_error_kind(input.clone(), ErrorKind::Many)))); + } - res.push(value); - input = tail; - } - Err(Err::Error(e)) => { - if !range.contains(&count) { - return Err(Err::Error(E::append(input, ErrorKind::Many, e))); - } else { - return Ok((input, res)); + res.push(value); + input = tail; + None + } + Err(Err::Error(e)) => { + if !range.contains(&count) { + return Some(Err(Err::Error(E::append(input.clone(), ErrorKind::Many, e)))); + } else { + return Some(Ok(input.clone())); + } + } + Err(e) => { + return Some(Err(e)); } } - Err(e) => { - return Err(e); + }; + + match range.end_bound() { + Bound::Unbounded => for count in (1..=core::usize::MAX).map(|x| x - 1) { + match parser(count) { + Some(Ok(input)) => return Ok((input, res)), + Some(Err(e)) => return Err(e), + _ => {}, } - } + }, + Bound::Included(x) => for count in (1..=*x).map(|x| x - 1) { + match parser(count) { + Some(Ok(input)) => return Ok((input, res)), + Some(Err(e)) => return Err(e), + _ => {}, + } + }, + Bound::Excluded(x) => for count in (1..*x).map(|x| x - 1) { + match parser(count) { + Some(Ok(input)) => return Ok((input, res)), + Some(Err(e)) => return Err(e), + _ => {}, + } + }, } Ok((input, res)) diff --git a/src/multi/tests.rs b/src/multi/tests.rs index bcbffe028..34f567148 100644 --- a/src/multi/tests.rs +++ b/src/multi/tests.rs @@ -661,6 +661,16 @@ fn many_test() { let res2 = vec![&b"Abcd"[..], &b"Abcd"[..]]; assert_eq!(multi_fixed(c), Ok((&b"AbcdAbcdefgh"[..], res2))); assert_eq!(multi_fixed(d), Err(Err::Incomplete(Needed::new(2)))); + + fn multi_test(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + many(0..=0, tag("A"))(i) + } + + let a = &b"AA"[..]; + let b = &b"B"[..]; + + assert_eq!(multi_test(a), Ok((&b"AA"[..], Vec::new()))); + assert_eq!(multi_test(b), Ok((&b"B"[..], Vec::new()))); } #[test] From d5b1d1c364e46f8d0501382068c202ea217c56b6 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Wed, 22 Sep 2021 00:14:40 +0200 Subject: [PATCH 22/38] Use monomorphisation instead of generic RangeBounds --- src/multi/mod.rs | 14 ++-- src/multi/tests.rs | 16 ++++- src/traits.rs | 171 ++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 188 insertions(+), 13 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index ab5758aee..3736e2b5a 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -8,7 +8,7 @@ use crate::error::ParseError; use crate::internal::{Err, IResult, Needed, Parser}; #[cfg(feature = "alloc")] use crate::lib::std::vec::Vec; -use crate::traits::{InputLength, InputTake, ToUsize, IntoRangeBounds, RangeIterator}; +use crate::{NomRange, traits::{InputLength, InputTake, ToUsize, IntoRangeBounds}}; use core::num::NonZeroUsize; use core::ops::{RangeBounds, Bound}; @@ -1141,7 +1141,7 @@ where /// assert_eq!(parser(""), Ok(("", vec![]))); /// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); /// ``` -pub fn fold( +pub fn fold( range: J, mut parse: F, mut init: H, @@ -1153,15 +1153,11 @@ where G: FnMut(R, O) -> R, H: FnMut() -> R, E: ParseError, - J: IntoRangeBounds, - K: RangeBounds, + J: NomRange, { - let range = range.convert(); move |mut input: I| { - match range.start_bound() { - Bound::Included(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::Fold))), - Bound::Excluded(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::Fold))), - _ => {}, + if range.is_inverted() { + return Err(Err::Failure(E::from_error_kind(input, ErrorKind::Fold))); } let mut acc = init(); diff --git a/src/multi/tests.rs b/src/multi/tests.rs index 34f567148..7fc2e3de1 100644 --- a/src/multi/tests.rs +++ b/src/multi/tests.rs @@ -662,15 +662,15 @@ fn many_test() { assert_eq!(multi_fixed(c), Ok((&b"AbcdAbcdefgh"[..], res2))); assert_eq!(multi_fixed(d), Err(Err::Incomplete(Needed::new(2)))); - fn multi_test(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fn multi_never(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { many(0..=0, tag("A"))(i) } let a = &b"AA"[..]; let b = &b"B"[..]; - assert_eq!(multi_test(a), Ok((&b"AA"[..], Vec::new()))); - assert_eq!(multi_test(b), Ok((&b"B"[..], Vec::new()))); + assert_eq!(multi_never(a), Ok((&b"AA"[..], Vec::new()))); + assert_eq!(multi_never(b), Ok((&b"B"[..], Vec::new()))); } #[test] @@ -777,4 +777,14 @@ fn fold_test() { assert_eq!(multi_exclusive(a), Ok((&b"AbcdAbcd"[..], res1))); let res2 = vec![]; assert_eq!(multi_exclusive(b), Ok((&b"AAA"[..], res2))); + + fn fold_never(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fold(0..=0, tag("A"), Vec::new, fold_into_vec)(i) + } + + let a = &b"AAA"[..]; + let b = &b"B"[..]; + + assert_eq!(fold_never(a), Ok((&b"AA"[..], Vec::new()))); + assert_eq!(fold_never(b), Ok((&b"B"[..], Vec::new()))); } diff --git a/src/traits.rs b/src/traits.rs index ddc5561e3..ebbae20ae 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -2,7 +2,7 @@ use crate::error::{ErrorKind, ParseError}; use crate::internal::{Err, IResult, Needed}; use crate::lib::std::iter::{Copied, Enumerate}; -use crate::lib::std::ops::{Range, RangeFrom, RangeFull, RangeTo}; +use crate::lib::std::ops::{Range, RangeFrom, RangeFull, RangeTo, RangeInclusive, RangeToInclusive}; use crate::lib::std::slice::Iter; use crate::lib::std::str::from_utf8; use crate::lib::std::str::CharIndices; @@ -1397,6 +1397,175 @@ impl HexDisplay for str { } } +/// +pub struct SaturatingIter2 { + count: usize, +} + +impl Iterator for SaturatingIter2 { + type Item = usize; + + fn next(&mut self) -> Option { + let old_count = self.count; + self.count = self.count.saturating_add(1); + Some(old_count) + } +} + +/// trait description +pub trait NomRange { + /// + type Iter1: Iterator; + /// + type Iter2: Iterator; + + /// + fn bounds(&self) -> (Bound, Bound); + + /// + fn contains(&self, item: &Idx) -> bool; + /// + fn is_inverted(&self) -> bool; + + /// + fn saturating_iter(&self) -> Self::Iter1; + /// + fn bounded_iter(&self) -> Self::Iter2; +} + +impl NomRange for Range { + type Iter1 = Range; + type Iter2 = Range; + + fn bounds(&self) -> (Bound, Bound) {(Bound::Included(self.start), Bound::Excluded(self.end))} + + fn contains(&self, item: &usize) -> bool {RangeBounds::contains(self, item)} + + fn is_inverted(&self) -> bool {Range::is_empty(self)} + + fn saturating_iter(&self) -> Self::Iter1 { + 0..self.end.saturating_sub(1) + } + + fn bounded_iter(&self) -> Self::Iter2 { + 0..self.end.saturating_sub(1) + } +} + +impl NomRange for RangeInclusive { + type Iter1 = RangeInclusive; + type Iter2 = RangeInclusive; + + fn bounds(&self) -> (Bound, Bound) {(Bound::Included(*self.start()), Bound::Included(*self.end()))} + + fn contains(&self, item: &usize) -> bool {RangeBounds::contains(self, item)} + + fn is_inverted(&self) -> bool {RangeInclusive::is_empty(self)} + + fn saturating_iter(&self) -> Self::Iter1 { + 0..=self.end().saturating_sub(1) + } + + fn bounded_iter(&self) -> Self::Iter2 { + 0..=self.end().saturating_sub(1) + } +} + +impl NomRange for RangeFrom { + type Iter1 = SaturatingIter2; + type Iter2 = RangeInclusive; + + fn bounds(&self) -> (Bound, Bound) {(Bound::Included(self.start), Bound::Unbounded)} + + fn contains(&self, item: &usize) -> bool {RangeBounds::contains(self, item)} + + fn is_inverted(&self) -> bool {false} + + fn saturating_iter(&self) -> Self::Iter1 { + SaturatingIter2 {count: 0} + } + + fn bounded_iter(&self) -> Self::Iter2 { + 0..=usize::MAX-1 + } +} + +impl NomRange for RangeTo { + type Iter1 = Range; + type Iter2 = Range; + + fn bounds(&self) -> (Bound, Bound) {(Bound::Unbounded, Bound::Excluded(self.end))} + + fn contains(&self, item: &usize) -> bool {RangeBounds::contains(self, item)} + + fn is_inverted(&self) -> bool {false} + + fn saturating_iter(&self) -> Self::Iter1 { + 0..self.end.saturating_sub(1) + } + + fn bounded_iter(&self) -> Self::Iter2 { + 0..self.end.saturating_sub(1) + } +} + +impl NomRange for RangeToInclusive { + type Iter1 = RangeInclusive; + type Iter2 = RangeInclusive; + + fn bounds(&self) -> (Bound, Bound) {(Bound::Unbounded, Bound::Included(self.end))} + + fn contains(&self, item: &usize) -> bool {RangeBounds::contains(self, item)} + + fn is_inverted(&self) -> bool {false} + + fn saturating_iter(&self) -> Self::Iter1 { + 0..=self.end.saturating_sub(1) + } + + fn bounded_iter(&self) -> Self::Iter2 { + 0..=self.end.saturating_sub(1) + } +} + +impl NomRange for RangeFull { + type Iter1 = SaturatingIter2; + type Iter2 = RangeInclusive; + + fn bounds(&self) -> (Bound, Bound) {(Bound::Unbounded, Bound::Unbounded)} + + fn contains(&self, item: &usize) -> bool {RangeBounds::contains(self, item)} + + fn is_inverted(&self) -> bool {false} + + fn saturating_iter(&self) -> Self::Iter1 { + SaturatingIter2{count: 0} + } + + fn bounded_iter(&self) -> Self::Iter2 { + 0..=usize::MAX-1 + } +} + +impl NomRange for usize { + type Iter1 = RangeInclusive; + type Iter2 = RangeInclusive; + + fn bounds(&self) -> (Bound, Bound) {(Bound::Included(*self), Bound::Included(*self))} + + fn contains(&self, item: &usize) -> bool {self == item} + + fn is_inverted(&self) -> bool {false} + + fn saturating_iter(&self) -> Self::Iter1 { + 0..=self.saturating_sub(1) + } + + fn bounded_iter(&self) -> Self::Iter2 { + 0..=self.saturating_sub(1) + } +} + /// Allows conversion of a type into a RangeBound. pub trait IntoRangeBounds where From 207b714d09d5ca75110ee6374d35c62138f9e5d3 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Wed, 22 Sep 2021 09:46:30 +0200 Subject: [PATCH 23/38] Fix some edge cases, Add documentation --- src/multi/mod.rs | 2 +- src/multi/tests.rs | 2 +- src/traits.rs | 63 +++++++++++++++++++++++++--------------------- 3 files changed, 37 insertions(+), 30 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 3736e2b5a..7316e7804 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -1162,7 +1162,7 @@ where let mut acc = init(); - for count in range.saturating_iter() { + for count in range.saturating_iter().map(|x| x - 1) { let len = input.input_len(); match parse.parse(input.clone()) { Ok((tail, value)) => { diff --git a/src/multi/tests.rs b/src/multi/tests.rs index 7fc2e3de1..faf0d7481 100644 --- a/src/multi/tests.rs +++ b/src/multi/tests.rs @@ -785,6 +785,6 @@ fn fold_test() { let a = &b"AAA"[..]; let b = &b"B"[..]; - assert_eq!(fold_never(a), Ok((&b"AA"[..], Vec::new()))); + assert_eq!(fold_never(a), Ok((&b"AAA"[..], Vec::new()))); assert_eq!(fold_never(b), Ok((&b"B"[..], Vec::new()))); } diff --git a/src/traits.rs b/src/traits.rs index ebbae20ae..9b22c2afa 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1397,12 +1397,12 @@ impl HexDisplay for str { } } -/// -pub struct SaturatingIter2 { +/// A saturating iterator for usize. +pub struct SaturatingIter { count: usize, } -impl Iterator for SaturatingIter2 { +impl Iterator for SaturatingIter { type Item = usize; fn next(&mut self) -> Option { @@ -1412,24 +1412,31 @@ impl Iterator for SaturatingIter2 { } } -/// trait description +/// Abstractions for range-like types. pub trait NomRange { - /// + /// The saturating iterator type. type Iter1: Iterator; - /// + /// The bounded iterator type. type Iter2: Iterator; - /// + /// `true` if `item` is contained in the range. + fn contains(&self, item: &Idx) -> bool; + + /// Returns the bounds of this range. fn bounds(&self) -> (Bound, Bound); - /// - fn contains(&self, item: &Idx) -> bool; - /// + /// `true` if the range is inverted. fn is_inverted(&self) -> bool; - /// + /// Creates a saturating iterator. + /// A saturating iterator counts the number of iterations starting from 1 up to the upper bound of this range. + /// If the upper bound is infinite the iterator saturates at the largest representable value of its type and + /// returns it for all further elements. fn saturating_iter(&self) -> Self::Iter1; - /// + /// Creates a bounded iterator. + /// A bounded iterator counts the number of iterations starting from 1 up to the upper bound of this range. + /// If the upper bounds is infinite the iterator counts up to the largest representable value of its type and + /// returns `None` for all further elements. fn bounded_iter(&self) -> Self::Iter2; } @@ -1444,11 +1451,11 @@ impl NomRange for Range { fn is_inverted(&self) -> bool {Range::is_empty(self)} fn saturating_iter(&self) -> Self::Iter1 { - 0..self.end.saturating_sub(1) + 1..self.end } fn bounded_iter(&self) -> Self::Iter2 { - 0..self.end.saturating_sub(1) + 1..self.end } } @@ -1463,16 +1470,16 @@ impl NomRange for RangeInclusive { fn is_inverted(&self) -> bool {RangeInclusive::is_empty(self)} fn saturating_iter(&self) -> Self::Iter1 { - 0..=self.end().saturating_sub(1) + 1..=*self.end() } fn bounded_iter(&self) -> Self::Iter2 { - 0..=self.end().saturating_sub(1) + 1..=*self.end() } } impl NomRange for RangeFrom { - type Iter1 = SaturatingIter2; + type Iter1 = SaturatingIter; type Iter2 = RangeInclusive; fn bounds(&self) -> (Bound, Bound) {(Bound::Included(self.start), Bound::Unbounded)} @@ -1482,11 +1489,11 @@ impl NomRange for RangeFrom { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - SaturatingIter2 {count: 0} + SaturatingIter {count: 1} } fn bounded_iter(&self) -> Self::Iter2 { - 0..=usize::MAX-1 + 1..=usize::MAX } } @@ -1501,11 +1508,11 @@ impl NomRange for RangeTo { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - 0..self.end.saturating_sub(1) + 1..self.end } fn bounded_iter(&self) -> Self::Iter2 { - 0..self.end.saturating_sub(1) + 1..self.end } } @@ -1520,16 +1527,16 @@ impl NomRange for RangeToInclusive { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - 0..=self.end.saturating_sub(1) + 1..=self.end } fn bounded_iter(&self) -> Self::Iter2 { - 0..=self.end.saturating_sub(1) + 1..=self.end } } impl NomRange for RangeFull { - type Iter1 = SaturatingIter2; + type Iter1 = SaturatingIter; type Iter2 = RangeInclusive; fn bounds(&self) -> (Bound, Bound) {(Bound::Unbounded, Bound::Unbounded)} @@ -1539,11 +1546,11 @@ impl NomRange for RangeFull { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - SaturatingIter2{count: 0} + SaturatingIter{count: 1} } fn bounded_iter(&self) -> Self::Iter2 { - 0..=usize::MAX-1 + 1..=usize::MAX } } @@ -1558,11 +1565,11 @@ impl NomRange for usize { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - 0..=self.saturating_sub(1) + 1..=*self } fn bounded_iter(&self) -> Self::Iter2 { - 0..=self.saturating_sub(1) + 1..=*self } } From 8f5da0543af884c6db218b89afb9fabdd65203b9 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Wed, 22 Sep 2021 20:42:48 +0200 Subject: [PATCH 24/38] Use core::usize::MAX because of MSRV --- src/traits.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 9b22c2afa..15a1694d0 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1493,7 +1493,7 @@ impl NomRange for RangeFrom { } fn bounded_iter(&self) -> Self::Iter2 { - 1..=usize::MAX + 1..=core::usize::MAX } } @@ -1550,7 +1550,7 @@ impl NomRange for RangeFull { } fn bounded_iter(&self) -> Self::Iter2 { - 1..=usize::MAX + 1..=core::usize::MAX } } From b9960583c2e5f6dde764e6656dc178ebbc8669ff Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Wed, 22 Sep 2021 20:53:41 +0200 Subject: [PATCH 25/38] Disambiguate range methods --- src/traits.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 15a1694d0..1fdf60c44 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1448,7 +1448,7 @@ impl NomRange for Range { fn contains(&self, item: &usize) -> bool {RangeBounds::contains(self, item)} - fn is_inverted(&self) -> bool {Range::is_empty(self)} + fn is_inverted(&self) -> bool {>::is_empty(self)} fn saturating_iter(&self) -> Self::Iter1 { 1..self.end @@ -1467,7 +1467,7 @@ impl NomRange for RangeInclusive { fn contains(&self, item: &usize) -> bool {RangeBounds::contains(self, item)} - fn is_inverted(&self) -> bool {RangeInclusive::is_empty(self)} + fn is_inverted(&self) -> bool {>::is_empty(self)} fn saturating_iter(&self) -> Self::Iter1 { 1..=*self.end() From ea2162e1b74cf1a707b5018ab791b73882bd869e Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Thu, 23 Sep 2021 01:12:30 +0200 Subject: [PATCH 26/38] Use NomRange trait for many --- src/multi/mod.rs | 86 +++++++++--------------- src/traits.rs | 170 ++--------------------------------------------- 2 files changed, 37 insertions(+), 219 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 7316e7804..8a9f5fb9b 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -8,9 +8,9 @@ use crate::error::ParseError; use crate::internal::{Err, IResult, Needed, Parser}; #[cfg(feature = "alloc")] use crate::lib::std::vec::Vec; -use crate::{NomRange, traits::{InputLength, InputTake, ToUsize, IntoRangeBounds}}; +use crate::{NomRange, traits::{InputLength, InputTake, ToUsize}}; use core::num::NonZeroUsize; -use core::ops::{RangeBounds, Bound}; +use core::ops::Bound; /// Repeats the embedded parser until it fails /// and returns the results in a `Vec`. @@ -1026,7 +1026,7 @@ where /// ``` #[cfg(feature = "alloc")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] -pub fn many( +pub fn many( range: G, mut parse: F, ) -> impl FnMut(I) -> IResult, E> @@ -1034,69 +1034,43 @@ where I: Clone + InputLength, F: Parser, E: ParseError, - G: IntoRangeBounds, - H: RangeBounds, + G: NomRange, { - let range = range.convert(); move |mut input: I| { - let start = match range.start_bound() { - Bound::Included(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::Many))), - Bound::Excluded(start) if !range.contains(start) => return Err(Err::Failure(E::from_error_kind(input, ErrorKind::Many))), - Bound::Included(start) => Some(*start), - Bound::Excluded(start) => Some(*start + 1), + if range.is_inverted() { + return Err(Err::Failure(E::from_error_kind(input, ErrorKind::Many))) + } + + let capacity = match range.bounds() { + (Bound::Included(start), _) => Some(start), + (Bound::Excluded(start), _) => Some(start + 1), _ => None, }; - let mut res = crate::lib::std::vec::Vec::with_capacity(start.unwrap_or(0)); - - let mut parser = |count: usize| -> Option>> { + let mut res = crate::lib::std::vec::Vec::with_capacity(capacity.unwrap_or(0)); + for count in range.bounded_iter().map(|x| x - 1) { let len = input.input_len(); - match parse.parse(input.clone()) { - Ok((tail, value)) => { - // infinite loop check: the parser must always consume - if tail.input_len() == len { - return Some(Err(Err::Error(E::from_error_kind(input.clone(), ErrorKind::Many)))); - } - - res.push(value); - input = tail; - None - } - Err(Err::Error(e)) => { - if !range.contains(&count) { - return Some(Err(Err::Error(E::append(input.clone(), ErrorKind::Many, e)))); - } else { - return Some(Ok(input.clone())); - } - } - Err(e) => { - return Some(Err(e)); + match parse.parse(input.clone()) { + Ok((tail, value)) => { + // infinite loop check: the parser must always consume + if tail.input_len() == len { + return Err(Err::Error(E::from_error_kind(input, ErrorKind::Many))); } + + res.push(value); + input = tail; } - }; - - match range.end_bound() { - Bound::Unbounded => for count in (1..=core::usize::MAX).map(|x| x - 1) { - match parser(count) { - Some(Ok(input)) => return Ok((input, res)), - Some(Err(e)) => return Err(e), - _ => {}, - } - }, - Bound::Included(x) => for count in (1..=*x).map(|x| x - 1) { - match parser(count) { - Some(Ok(input)) => return Ok((input, res)), - Some(Err(e)) => return Err(e), - _ => {}, + Err(Err::Error(e)) => { + if !range.contains(&count) { + return Err(Err::Error(E::append(input, ErrorKind::Many, e))); + } else { + return Ok((input, res)); + } } - }, - Bound::Excluded(x) => for count in (1..*x).map(|x| x - 1) { - match parser(count) { - Some(Ok(input)) => return Ok((input, res)), - Some(Err(e)) => return Err(e), - _ => {}, + Err(e) => { + return Err(e); } - }, + } } Ok((input, res)) diff --git a/src/traits.rs b/src/traits.rs index 1fdf60c44..28191a752 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1398,11 +1398,11 @@ impl HexDisplay for str { } /// A saturating iterator for usize. -pub struct SaturatingIter { +pub struct SaturatingIterator { count: usize, } -impl Iterator for SaturatingIter { +impl Iterator for SaturatingIterator { type Item = usize; fn next(&mut self) -> Option { @@ -1433,6 +1433,7 @@ pub trait NomRange { /// If the upper bound is infinite the iterator saturates at the largest representable value of its type and /// returns it for all further elements. fn saturating_iter(&self) -> Self::Iter1; + /// Creates a bounded iterator. /// A bounded iterator counts the number of iterations starting from 1 up to the upper bound of this range. /// If the upper bounds is infinite the iterator counts up to the largest representable value of its type and @@ -1479,7 +1480,7 @@ impl NomRange for RangeInclusive { } impl NomRange for RangeFrom { - type Iter1 = SaturatingIter; + type Iter1 = SaturatingIterator; type Iter2 = RangeInclusive; fn bounds(&self) -> (Bound, Bound) {(Bound::Included(self.start), Bound::Unbounded)} @@ -1489,7 +1490,7 @@ impl NomRange for RangeFrom { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - SaturatingIter {count: 1} + SaturatingIterator {count: 1} } fn bounded_iter(&self) -> Self::Iter2 { @@ -1536,7 +1537,7 @@ impl NomRange for RangeToInclusive { } impl NomRange for RangeFull { - type Iter1 = SaturatingIter; + type Iter1 = SaturatingIterator; type Iter2 = RangeInclusive; fn bounds(&self) -> (Bound, Bound) {(Bound::Unbounded, Bound::Unbounded)} @@ -1546,7 +1547,7 @@ impl NomRange for RangeFull { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - SaturatingIter{count: 1} + SaturatingIterator{count: 1} } fn bounded_iter(&self) -> Self::Iter2 { @@ -1573,163 +1574,6 @@ impl NomRange for usize { } } -/// Allows conversion of a type into a RangeBound. -pub trait IntoRangeBounds -where - T: RangeBounds -{ - /// Convert to a RangeBound - fn convert(self) -> T; -} - -impl IntoRangeBounds for T -where - T: RangeBounds -{ - fn convert(self) -> T {self} -} - -impl IntoRangeBounds> for usize { - fn convert(self) -> core::ops::RangeInclusive {self..=self} -} - -/// Allows iteration over ranges. All iterators start at 0 and -/// count towards the end of the range. Handling of ranges with -/// an unbounded upper limit is dependent on the specific iterator. -pub trait RangeIterator { - - /// A bounded iterator. - /// Iterating an unbounded range is equivalent to iterating over a - /// range of `value..=usize::MAX`. - fn bounded_iter(&self) -> BoundedIterator; - - /// A saturating iterator. - /// If the iterator is unbounded and the end of the representable size - /// of `usize` has been reached, this iterator will return usize::MAX - /// infinitely. - fn saturating_iter(&self) -> SaturatingIterator; -} - -impl RangeIterator for T -where - T: RangeBounds -{ - fn bounded_iter(&self) -> BoundedIterator { - BoundedIterator{ - end: match self.end_bound() { - Bound::Included(e) => Bound::Included(*e), - Bound::Excluded(e) => Bound::Excluded(*e), - Bound::Unbounded => Bound::Unbounded, - }, - count: 0, - exhausted: false, - } - } - - fn saturating_iter(&self) -> SaturatingIterator { - SaturatingIterator{ - end: match self.end_bound() { - Bound::Included(e) => Bound::Included(*e), - Bound::Excluded(e) => Bound::Excluded(*e), - Bound::Unbounded => Bound::Unbounded, - }, - count: 0, - exhausted: false, - } - } -} - -/// A bounded iterator. -/// Iterates until the end of a `usize` range is reached. -/// If the upper limit is unbounded, this iterator will end when -/// the next element would be greater than `usize::MAX`. -pub struct BoundedIterator { - end: Bound, - count: usize, - exhausted: bool, -} - -impl Iterator for BoundedIterator { - type Item = usize; - - fn next(&mut self) -> Option { - let old_count = self.count; - self.count = self.count.saturating_add(1); - match (self.count, self.end) { - (count, Bound::Included(end)) => { - if count > end { - None - } else { - if (old_count == core::usize::MAX) && !self.exhausted { - if !self.exhausted { - self.exhausted = true; - Some(old_count) - } else { - None - } - } else { - Some(old_count) - } - } - }, - (_, Bound::Unbounded)=> { - if old_count == core::usize::MAX { - if !self.exhausted { - self.exhausted = true; - Some(old_count) - } else { - None - } - } else { - Some(old_count) - } - } - (count, Bound::Excluded(end)) if count >= end => None, - (_, Bound::Excluded(_)) => Some(old_count), - } - } -} - -/// A saturating iterator. -/// Iterates until the end of a `usize` range is reached. -/// If upper limit is unbounded, this iterator saturates at -/// `usize::MAX`. -pub struct SaturatingIterator { - end: Bound, - count: usize, - exhausted: bool, -} - -impl Iterator for SaturatingIterator { - type Item = usize; - - fn next(&mut self) -> Option { - let old_count = self.count; - self.count = self.count.saturating_add(1); - match (self.count, self.end) { - (count, Bound::Included(end)) => { - if count > end { - None - } else { - if (old_count == core::usize::MAX) && !self.exhausted { - if !self.exhausted { - self.exhausted = true; - Some(old_count) - } else { - None - } - } else { - Some(old_count) - } - } - }, - (_, Bound::Unbounded) => Some(old_count), - (count, Bound::Excluded(end)) if count >= end => None, - (_, Bound::Excluded(_)) => Some(old_count), - } - } -} - #[cfg(test)] mod tests { use super::*; From eb0f2e28a8c16b91c6c613d59561715eafba6a01 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Thu, 23 Sep 2021 01:19:09 +0200 Subject: [PATCH 27/38] Fix tests --- tests/fnmut.rs | 2 +- tests/issues.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/fnmut.rs b/tests/fnmut.rs index 0b678b6eb..995faefdf 100644 --- a/tests/fnmut.rs +++ b/tests/fnmut.rs @@ -8,7 +8,7 @@ fn parse() { let mut counter = 0; let res = { - let mut parser = many::<_, _, (), _, _, _>(0.., |i| { + let mut parser = many::<_, _, (), _, _>(0.., |i| { counter += 1; tag("abc")(i) }); diff --git a/tests/issues.rs b/tests/issues.rs index 16ce39095..dc5d33d51 100644 --- a/tests/issues.rs +++ b/tests/issues.rs @@ -171,7 +171,7 @@ fn issue_942() { fn issue_many_m_n_with_zeros() { use nom::character::complete::char; use nom::multi::many; - let mut parser = many::<_, _, (), _, _, _>(0..=0, char('a')); + let mut parser = many::<_, _, (), _, _>(0..=0, char('a')); assert_eq!(parser("aaa"), Ok(("aaa", vec!()))); } From acbacc788d09a249477b187717bc97a5ee930f4c Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Thu, 23 Sep 2021 13:35:37 +0200 Subject: [PATCH 28/38] Handle edge cases in trait and remove obsolete map in parsers --- src/multi/mod.rs | 4 +-- src/traits.rs | 72 +++++++++++++++++++++++++++++++++++++----------- 2 files changed, 58 insertions(+), 18 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 8a9f5fb9b..74f16b4c0 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -1048,7 +1048,7 @@ where }; let mut res = crate::lib::std::vec::Vec::with_capacity(capacity.unwrap_or(0)); - for count in range.bounded_iter().map(|x| x - 1) { + for count in range.bounded_iter() { let len = input.input_len(); match parse.parse(input.clone()) { Ok((tail, value)) => { @@ -1136,7 +1136,7 @@ where let mut acc = init(); - for count in range.saturating_iter().map(|x| x - 1) { + for count in range.saturating_iter() { let len = input.input_len(); match parse.parse(input.clone()) { Ok((tail, value)) => { diff --git a/src/traits.rs b/src/traits.rs index 28191a752..ac31d1f31 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1429,13 +1429,13 @@ pub trait NomRange { fn is_inverted(&self) -> bool; /// Creates a saturating iterator. - /// A saturating iterator counts the number of iterations starting from 1 up to the upper bound of this range. + /// A saturating iterator counts the number of iterations starting from 0 up to the upper bound of this range. /// If the upper bound is infinite the iterator saturates at the largest representable value of its type and /// returns it for all further elements. fn saturating_iter(&self) -> Self::Iter1; /// Creates a bounded iterator. - /// A bounded iterator counts the number of iterations starting from 1 up to the upper bound of this range. + /// A bounded iterator counts the number of iterations starting from 0 up to the upper bound of this range. /// If the upper bounds is infinite the iterator counts up to the largest representable value of its type and /// returns `None` for all further elements. fn bounded_iter(&self) -> Self::Iter2; @@ -1452,11 +1452,19 @@ impl NomRange for Range { fn is_inverted(&self) -> bool {>::is_empty(self)} fn saturating_iter(&self) -> Self::Iter1 { - 1..self.end + if self.end == 0 { + 1..0 + } else { + 0..self.end-1 + } } fn bounded_iter(&self) -> Self::Iter2 { - 1..self.end + if self.end == 0 { + 1..0 + } else { + 0..self.end-1 + } } } @@ -1471,11 +1479,19 @@ impl NomRange for RangeInclusive { fn is_inverted(&self) -> bool {>::is_empty(self)} fn saturating_iter(&self) -> Self::Iter1 { - 1..=*self.end() + if *self.end() == 0 { + 1..=0 + } else { + 0..=self.end()-1 + } } fn bounded_iter(&self) -> Self::Iter2 { - 1..=*self.end() + if *self.end() == 0 { + 1..=0 + } else { + 0..=self.end()-1 + } } } @@ -1490,11 +1506,11 @@ impl NomRange for RangeFrom { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - SaturatingIterator {count: 1} + SaturatingIterator {count: 0} } fn bounded_iter(&self) -> Self::Iter2 { - 1..=core::usize::MAX + 0..=core::usize::MAX-1 } } @@ -1509,11 +1525,19 @@ impl NomRange for RangeTo { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - 1..self.end + if self.end == 0 { + 1..0 + } else { + 0..self.end-1 + } } fn bounded_iter(&self) -> Self::Iter2 { - 1..self.end + if self.end == 0 { + 1..0 + } else { + 0..self.end-1 + } } } @@ -1528,11 +1552,19 @@ impl NomRange for RangeToInclusive { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - 1..=self.end + if self.end == 0 { + 1..=0 + } else { + 0..=self.end-1 + } } fn bounded_iter(&self) -> Self::Iter2 { - 1..=self.end + if self.end == 0 { + 1..=0 + } else { + 0..=self.end-1 + } } } @@ -1547,11 +1579,11 @@ impl NomRange for RangeFull { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - SaturatingIterator{count: 1} + SaturatingIterator{count: 0} } fn bounded_iter(&self) -> Self::Iter2 { - 1..=core::usize::MAX + 0..=core::usize::MAX-1 } } @@ -1566,11 +1598,19 @@ impl NomRange for usize { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - 1..=*self + if *self == 0 { + 1..=0 + } else { + 0..=*self-1 + } } fn bounded_iter(&self) -> Self::Iter2 { - 1..=*self + if *self == 0 { + 1..=0 + } else { + 0..=*self-1 + } } } From 01ae1a3be44d65d48c8c5f9f562eecb544c4ce66 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Fri, 24 Sep 2021 16:56:31 +0200 Subject: [PATCH 29/38] Elide subtraction in inclusive ranges --- src/traits.rs | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index ac31d1f31..d589e7cc6 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1469,8 +1469,8 @@ impl NomRange for Range { } impl NomRange for RangeInclusive { - type Iter1 = RangeInclusive; - type Iter2 = RangeInclusive; + type Iter1 = Range; + type Iter2 = Range; fn bounds(&self) -> (Bound, Bound) {(Bound::Included(*self.start()), Bound::Included(*self.end()))} @@ -1479,19 +1479,11 @@ impl NomRange for RangeInclusive { fn is_inverted(&self) -> bool {>::is_empty(self)} fn saturating_iter(&self) -> Self::Iter1 { - if *self.end() == 0 { - 1..=0 - } else { - 0..=self.end()-1 - } + 0..*self.end() } fn bounded_iter(&self) -> Self::Iter2 { - if *self.end() == 0 { - 1..=0 - } else { - 0..=self.end()-1 - } + 0..*self.end() } } From 63cb9304a3226dd686551546066d36271c1f7811 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Fri, 24 Sep 2021 19:03:54 +0200 Subject: [PATCH 30/38] Elide end bound subtraction where possible --- src/traits.rs | 40 ++++++++++++---------------------------- 1 file changed, 12 insertions(+), 28 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index d589e7cc6..8b8bf30fc 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1489,7 +1489,7 @@ impl NomRange for RangeInclusive { impl NomRange for RangeFrom { type Iter1 = SaturatingIterator; - type Iter2 = RangeInclusive; + type Iter2 = Range; fn bounds(&self) -> (Bound, Bound) {(Bound::Included(self.start), Bound::Unbounded)} @@ -1502,7 +1502,7 @@ impl NomRange for RangeFrom { } fn bounded_iter(&self) -> Self::Iter2 { - 0..=core::usize::MAX-1 + 0..core::usize::MAX } } @@ -1534,8 +1534,8 @@ impl NomRange for RangeTo { } impl NomRange for RangeToInclusive { - type Iter1 = RangeInclusive; - type Iter2 = RangeInclusive; + type Iter1 = Range; + type Iter2 = Range; fn bounds(&self) -> (Bound, Bound) {(Bound::Unbounded, Bound::Included(self.end))} @@ -1544,25 +1544,17 @@ impl NomRange for RangeToInclusive { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - if self.end == 0 { - 1..=0 - } else { - 0..=self.end-1 - } + 0..self.end } fn bounded_iter(&self) -> Self::Iter2 { - if self.end == 0 { - 1..=0 - } else { - 0..=self.end-1 - } + 0..self.end } } impl NomRange for RangeFull { type Iter1 = SaturatingIterator; - type Iter2 = RangeInclusive; + type Iter2 = Range; fn bounds(&self) -> (Bound, Bound) {(Bound::Unbounded, Bound::Unbounded)} @@ -1575,13 +1567,13 @@ impl NomRange for RangeFull { } fn bounded_iter(&self) -> Self::Iter2 { - 0..=core::usize::MAX-1 + 0..core::usize::MAX } } impl NomRange for usize { - type Iter1 = RangeInclusive; - type Iter2 = RangeInclusive; + type Iter1 = Range; + type Iter2 = Range; fn bounds(&self) -> (Bound, Bound) {(Bound::Included(*self), Bound::Included(*self))} @@ -1590,19 +1582,11 @@ impl NomRange for usize { fn is_inverted(&self) -> bool {false} fn saturating_iter(&self) -> Self::Iter1 { - if *self == 0 { - 1..=0 - } else { - 0..=*self-1 - } + 0..*self } fn bounded_iter(&self) -> Self::Iter2 { - if *self == 0 { - 1..=0 - } else { - 0..=*self-1 - } + 0..*self } } From f6950a45877470e3d0610b3789e574f31ef135d2 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 25 Sep 2021 00:49:27 +0200 Subject: [PATCH 31/38] Improve and organize tests for many --- src/multi/tests.rs | 135 ++++++++++++++++++++++++++------------------- 1 file changed, 78 insertions(+), 57 deletions(-) diff --git a/src/multi/tests.rs b/src/multi/tests.rs index faf0d7481..2de452cea 100644 --- a/src/multi/tests.rs +++ b/src/multi/tests.rs @@ -553,73 +553,97 @@ fn many1_count_test() { #[test] #[cfg(feature = "alloc")] fn many_test() { - fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - many(0.., tag("abcd"))(i) + // should not go into an infinite loop + fn many_error_0(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { + Err(Err::Error(error_position!(input, ErrorKind::Tag))) + } + many(0.., tst)(i) } - fn multi_empty(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - many(0.., tag(""))(i) + + let a = &b"abcdef"[..]; + assert_eq!(many_error_0(a), Ok((a, Vec::new()))); + + + fn many_error_1(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { + Err(Err::Error(error_position!(input, ErrorKind::Tag))) + } + many(1.., tst)(i) } - - assert_eq!(multi(&b"abcdef"[..]), Ok((&b"ef"[..], vec![&b"abcd"[..]]))); + + let a = &b"abcdef"[..]; assert_eq!( - multi(&b"abcdabcdefgh"[..]), - Ok((&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]])) + many_error_1(a), + Err(Err::Error(error_position!(a, ErrorKind::Tag))) ); - assert_eq!(multi(&b"azerty"[..]), Ok((&b"azerty"[..], Vec::new()))); - assert_eq!(multi(&b"abcdab"[..]), Err(Err::Incomplete(Needed::new(2)))); - assert_eq!(multi(&b"abcd"[..]), Err(Err::Incomplete(Needed::new(4)))); - assert_eq!(multi(&b""[..]), Err(Err::Incomplete(Needed::new(4)))); + + + fn many_error(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + many(0.., tag(""))(i) + } + + let a = &b"abcdef"[..]; assert_eq!( - multi_empty(&b"abcdef"[..]), + many_error(a), Err(Err::Error(error_position!( - &b"abcdef"[..], + a, ErrorKind::Many ))) ); - fn multi1(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - many(1.., tag("abcd"))(i) + fn many_invalid(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + many(2..=1, tag("a"))(i) } - + + let a = &b"a"[..]; + let b = &b"b"[..]; + assert_eq!(many_invalid(a), Err(Err::Failure(error_position!(a, ErrorKind::Many)))); + assert_eq!(many_invalid(b), Err(Err::Failure(error_position!(b, ErrorKind::Many)))); + + + fn many_any(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + many(0.., tag("abcd"))(i) + } + let a = &b"abcdef"[..]; let b = &b"abcdabcdefgh"[..]; let c = &b"azerty"[..]; let d = &b"abcdab"[..]; - - let res1 = vec![&b"abcd"[..]]; - assert_eq!(multi1(a), Ok((&b"ef"[..], res1))); - let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; - assert_eq!(multi1(b), Ok((&b"efgh"[..], res2))); + let e = &b"abcd"[..]; + let f = &b""[..]; + assert_eq!(many_any(a), Ok((&b"ef"[..], vec![&b"abcd"[..]]))); assert_eq!( - multi1(c), - Err(Err::Error(error_position!(c, ErrorKind::Tag))) + many_any(b), + Ok((&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]])) ); - assert_eq!(multi1(d), Err(Err::Incomplete(Needed::new(2)))); + assert_eq!(many_any(c), Ok((&b"azerty"[..], Vec::new()))); + assert_eq!(many_any(d), Err(Err::Incomplete(Needed::new(2)))); + assert_eq!(many_any(e), Err(Err::Incomplete(Needed::new(4)))); + assert_eq!(many_any(f), Err(Err::Incomplete(Needed::new(4)))); - fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { - Err(Err::Error(error_position!(input, ErrorKind::Tag))) - } - - // should not go into an infinite loop - fn multi0(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - many(0.., tst)(i) + fn many_1(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + many(1.., tag("abcd"))(i) } - let a = &b"abcdef"[..]; - assert_eq!(multi0(a), Ok((a, Vec::new()))); - fn multi1_2(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - many(1.., tst)(i) - } let a = &b"abcdef"[..]; + let b = &b"abcdabcdefgh"[..]; + let c = &b"azerty"[..]; + let d = &b"abcdab"[..]; + let res1 = vec![&b"abcd"[..]]; + assert_eq!(many_1(a), Ok((&b"ef"[..], res1))); + let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; + assert_eq!(many_1(b), Ok((&b"efgh"[..], res2))); assert_eq!( - multi1_2(a), - Err(Err::Error(error_position!(a, ErrorKind::Tag))) + many_1(c), + Err(Err::Error(error_position!(c, ErrorKind::Tag))) ); + assert_eq!(many_1(d), Err(Err::Incomplete(Needed::new(2)))); - fn multi_m_n(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fn many_m_n(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { many(2..=4, tag("Abcd"))(i) } @@ -628,21 +652,20 @@ fn many_test() { let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; let e = &b"AbcdAb"[..]; - assert_eq!( - multi_m_n(a), + many_m_n(a), Err(Err::Error(error_position!(&b"ef"[..], ErrorKind::Tag))) ); let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!(multi_m_n(b), Ok((&b"efgh"[..], res1))); + assert_eq!(many_m_n(b), Ok((&b"efgh"[..], res1))); let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!(multi_m_n(c), Ok((&b"efgh"[..], res2))); + assert_eq!(many_m_n(c), Ok((&b"efgh"[..], res2))); let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!(multi_m_n(d), Ok((&b"Abcdefgh"[..], res3))); - assert_eq!(multi_m_n(e), Err(Err::Incomplete(Needed::new(2)))); + assert_eq!(many_m_n(d), Ok((&b"Abcdefgh"[..], res3))); + assert_eq!(many_m_n(e), Err(Err::Incomplete(Needed::new(2)))); - fn multi_fixed(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fn many_fixed(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { many(2, tag("Abcd"))(i) } @@ -650,27 +673,25 @@ fn many_test() { let b = &b"AbcdAbcdefgh"[..]; let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; let d = &b"AbcdAb"[..]; - assert_eq!( - multi_fixed(a), + many_fixed(a), Err(Err::Error(error_position!(&b"ef"[..], ErrorKind::Tag))) ); - let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!(multi_fixed(b), Ok((&b"efgh"[..], res1))); + assert_eq!(many_fixed(b), Ok((&b"efgh"[..], res1))); let res2 = vec![&b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!(multi_fixed(c), Ok((&b"AbcdAbcdefgh"[..], res2))); - assert_eq!(multi_fixed(d), Err(Err::Incomplete(Needed::new(2)))); + assert_eq!(many_fixed(c), Ok((&b"AbcdAbcdefgh"[..], res2))); + assert_eq!(many_fixed(d), Err(Err::Incomplete(Needed::new(2)))); - fn multi_never(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + + fn many_never(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { many(0..=0, tag("A"))(i) } let a = &b"AA"[..]; let b = &b"B"[..]; - - assert_eq!(multi_never(a), Ok((&b"AA"[..], Vec::new()))); - assert_eq!(multi_never(b), Ok((&b"B"[..], Vec::new()))); + assert_eq!(many_never(a), Ok((&b"AA"[..], Vec::new()))); + assert_eq!(many_never(b), Ok((&b"B"[..], Vec::new()))); } #[test] From ecc51eb1c59dd211813f6726502f9f3bb21c16bd Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 25 Sep 2021 13:07:07 +0200 Subject: [PATCH 32/38] Cleanup tests --- src/multi/tests.rs | 133 ++++++++++++++++++++++++++++++++------------- 1 file changed, 95 insertions(+), 38 deletions(-) diff --git a/src/multi/tests.rs b/src/multi/tests.rs index 2de452cea..8f72459cc 100644 --- a/src/multi/tests.rs +++ b/src/multi/tests.rs @@ -684,6 +684,18 @@ fn many_test() { assert_eq!(many_fixed(d), Err(Err::Incomplete(Needed::new(2)))); + fn multi_exclusive(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + many(0..2, tag("Abcd"))(i) + } + + let a = &b"AbcdAbcdAbcd"[..]; + let b = &b"AAA"[..]; + let res1 = vec![&b"Abcd"[..]]; + assert_eq!(multi_exclusive(a), Ok((&b"AbcdAbcd"[..], res1))); + let res2 = vec![]; + assert_eq!(multi_exclusive(b), Ok((&b"AAA"[..], res2))); + + fn many_never(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { many(0..=0, tag("A"))(i) } @@ -701,32 +713,79 @@ fn fold_test() { acc.push(item); acc } - fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - fold(0.., tag("abcd"), Vec::new, fold_into_vec)(i) + + // should not go into an infinite loop + fn fold_error_0(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { + Err(Err::Error(error_position!(input, ErrorKind::Tag))) + } + fold(0.., tst, Vec::new, fold_into_vec)(i) } - fn multi_empty(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { - fold(0.., tag(""), Vec::new, fold_into_vec)(i) + + let a = &b"abcdef"[..]; + assert_eq!(fold_error_0(a), Ok((a, Vec::new()))); + + + fn fold_error_1(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { + Err(Err::Error(error_position!(input, ErrorKind::Tag))) + } + fold(1.., tst, Vec::new, fold_into_vec)(i) } - - assert_eq!(multi(&b"abcdef"[..]), Ok((&b"ef"[..], vec![&b"abcd"[..]]))); + + let a = &b"abcdef"[..]; assert_eq!( - multi(&b"abcdabcdefgh"[..]), - Ok((&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]])) + fold_error_1(a), + Err(Err::Error(error_position!(a, ErrorKind::Tag))) ); - assert_eq!(multi(&b"azerty"[..]), Ok((&b"azerty"[..], Vec::new()))); - assert_eq!(multi(&b"abcdab"[..]), Err(Err::Incomplete(Needed::new(2)))); - assert_eq!(multi(&b"abcd"[..]), Err(Err::Incomplete(Needed::new(4)))); - assert_eq!(multi(&b""[..]), Err(Err::Incomplete(Needed::new(4)))); + + + fn fold_error(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fold(0.., tag(""), Vec::new, fold_into_vec)(i) + } + + let a = &b"abcdef"[..]; assert_eq!( - multi_empty(&b"abcdef"[..]), + fold_error(a), Err(Err::Error(error_position!( - &b"abcdef"[..], + a, ErrorKind::Fold ))) ); - fn multi1(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fn fold_invalid(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fold(2..=1, tag("a"), Vec::new, fold_into_vec)(i) + } + + let a = &b"a"[..]; + let b = &b"b"[..]; + assert_eq!(fold_invalid(a), Err(Err::Failure(error_position!(a, ErrorKind::Fold)))); + assert_eq!(fold_invalid(b), Err(Err::Failure(error_position!(b, ErrorKind::Fold)))); + + + fn fold_any(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fold(0.., tag("abcd"), Vec::new, fold_into_vec)(i) + } + + let a = &b"abcdef"[..]; + let b = &b"abcdabcdefgh"[..]; + let c = &b"azerty"[..]; + let d = &b"abcdab"[..]; + let e = &b"abcd"[..]; + let f = &b""[..]; + assert_eq!(fold_any(a), Ok((&b"ef"[..], vec![&b"abcd"[..]]))); + assert_eq!( + fold_any(b), + Ok((&b"efgh"[..], vec![&b"abcd"[..], &b"abcd"[..]])) + ); + assert_eq!(fold_any(c), Ok((c, Vec::new()))); + assert_eq!(fold_any(d), Err(Err::Incomplete(Needed::new(2)))); + assert_eq!(fold_any(e), Err(Err::Incomplete(Needed::new(4)))); + assert_eq!(fold_any(f), Err(Err::Incomplete(Needed::new(4)))); + + + fn fold_1(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { fold(1.., tag("abcd"), Vec::new, fold_into_vec)(i) } @@ -734,19 +793,18 @@ fn fold_test() { let b = &b"abcdabcdefgh"[..]; let c = &b"azerty"[..]; let d = &b"abcdab"[..]; - let res1 = vec![&b"abcd"[..]]; - assert_eq!(multi1(a), Ok((&b"ef"[..], res1))); + assert_eq!(fold_1(a), Ok((&b"ef"[..], res1))); let res2 = vec![&b"abcd"[..], &b"abcd"[..]]; - assert_eq!(multi1(b), Ok((&b"efgh"[..], res2))); + assert_eq!(fold_1(b), Ok((&b"efgh"[..], res2))); assert_eq!( - multi1(c), + fold_1(c), Err(Err::Error(error_position!(c, ErrorKind::Tag))) ); - assert_eq!(multi1(d), Err(Err::Incomplete(Needed::new(2)))); + assert_eq!(fold_1(d), Err(Err::Incomplete(Needed::new(2)))); - fn multi_m_n(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + fn fold_m_n(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { fold(2..=4, tag("Abcd"), Vec::new, fold_into_vec)(i) } @@ -755,20 +813,20 @@ fn fold_test() { let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; let d = &b"AbcdAbcdAbcdAbcdAbcdefgh"[..]; let e = &b"AbcdAb"[..]; - assert_eq!( - multi_m_n(a), + fold_m_n(a), Err(Err::Error(error_position!(&b"ef"[..], ErrorKind::Tag))) ); let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!(multi_m_n(b), Ok((&b"efgh"[..], res1))); + assert_eq!(fold_m_n(b), Ok((&b"efgh"[..], res1))); let res2 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!(multi_m_n(c), Ok((&b"efgh"[..], res2))); + assert_eq!(fold_m_n(c), Ok((&b"efgh"[..], res2))); let res3 = vec![&b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!(multi_m_n(d), Ok((&b"Abcdefgh"[..], res3))); - assert_eq!(multi_m_n(e), Err(Err::Incomplete(Needed::new(2)))); + assert_eq!(fold_m_n(d), Ok((&b"Abcdefgh"[..], res3))); + assert_eq!(fold_m_n(e), Err(Err::Incomplete(Needed::new(2)))); - fn multi_fixed(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + + fn fold_fixed(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { fold(2, tag("Abcd"), Vec::new, fold_into_vec)(i) } @@ -776,28 +834,28 @@ fn fold_test() { let b = &b"AbcdAbcdefgh"[..]; let c = &b"AbcdAbcdAbcdAbcdefgh"[..]; let d = &b"AbcdAb"[..]; - assert_eq!( - multi_fixed(a), + fold_fixed(a), Err(Err::Error(error_position!(&b"ef"[..], ErrorKind::Tag))) ); - let res1 = vec![&b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!(multi_fixed(b), Ok((&b"efgh"[..], res1))); + assert_eq!(fold_fixed(b), Ok((&b"efgh"[..], res1))); let res2 = vec![&b"Abcd"[..], &b"Abcd"[..]]; - assert_eq!(multi_fixed(c), Ok((&b"AbcdAbcdefgh"[..], res2))); - assert_eq!(multi_fixed(d), Err(Err::Incomplete(Needed::new(2)))); + assert_eq!(fold_fixed(c), Ok((&b"AbcdAbcdefgh"[..], res2))); + assert_eq!(fold_fixed(d), Err(Err::Incomplete(Needed::new(2)))); - fn multi_exclusive(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { + + fn fold_exclusive(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { fold(0..2, tag("Abcd"), Vec::new, fold_into_vec)(i) } let a = &b"AbcdAbcdAbcd"[..]; let b = &b"AAA"[..]; let res1 = vec![&b"Abcd"[..]]; - assert_eq!(multi_exclusive(a), Ok((&b"AbcdAbcd"[..], res1))); + assert_eq!(fold_exclusive(a), Ok((&b"AbcdAbcd"[..], res1))); let res2 = vec![]; - assert_eq!(multi_exclusive(b), Ok((&b"AAA"[..], res2))); + assert_eq!(fold_exclusive(b), Ok((&b"AAA"[..], res2))); + fn fold_never(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { fold(0..=0, tag("A"), Vec::new, fold_into_vec)(i) @@ -805,7 +863,6 @@ fn fold_test() { let a = &b"AAA"[..]; let b = &b"B"[..]; - assert_eq!(fold_never(a), Ok((&b"AAA"[..], Vec::new()))); assert_eq!(fold_never(b), Ok((&b"B"[..], Vec::new()))); } From ca6eee01614a806172a593cdf223a7e8eb4b451e Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 25 Sep 2021 14:55:04 +0200 Subject: [PATCH 33/38] Cleanup --- src/multi/mod.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 74f16b4c0..5db8be3fb 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -1003,9 +1003,9 @@ where /// Fails if the amount of time the embedded parser is run is not /// within the specified range. /// # Arguments -/// * `range` The amount of times to apply the parser. -/// * A range with an upper bound `a..=b` limits the parser to run at most `b` times. +/// * `range` Constrains the number of iterations. /// * A range without an upper bound `a..` is equivalent to a range of `a..=usize::MAX`. +/// * A single `usize` value is equivalent to `value..=value`. /// * An empty range is invalid. /// * `parse` The parser to apply. /// ```rust @@ -1042,12 +1042,12 @@ where } let capacity = match range.bounds() { - (Bound::Included(start), _) => Some(start), - (Bound::Excluded(start), _) => Some(start + 1), - _ => None, + (Bound::Included(start), _) => start, + (Bound::Excluded(start), _) => start + 1, + _ => 4, }; - let mut res = crate::lib::std::vec::Vec::with_capacity(capacity.unwrap_or(0)); + let mut res = crate::lib::std::vec::Vec::with_capacity(capacity); for count in range.bounded_iter() { let len = input.input_len(); match parse.parse(input.clone()) { @@ -1083,9 +1083,9 @@ where /// within the specified range. /// /// # Arguments -/// * `range` The amount of times to apply the parser. -/// * A range with an upper bound `a..=b` limits the parser to run at most `b` times. +/// * `range` Constrains the number of iterations. /// * A range without an upper bound `a..` allows the parser to run until it fails. +/// * A single `usize` value is equivalent to `value..=value`. /// * An empty range is invalid. /// * `parse` The parser to apply. /// * `init` A function returning the initial value. From 9e44ba4b39e9c4f08d576d14a5025238489247ea Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 25 Sep 2021 14:59:40 +0200 Subject: [PATCH 34/38] Replace deprecated parsers in bench tests --- benches/arithmetic.rs | 6 +++--- benches/http.rs | 6 +++--- benches/ini.rs | 8 ++++---- benches/ini_str.rs | 6 +++--- benches/json.rs | 4 ++-- 5 files changed, 15 insertions(+), 15 deletions(-) diff --git a/benches/arithmetic.rs b/benches/arithmetic.rs index 136aca559..e10729d61 100644 --- a/benches/arithmetic.rs +++ b/benches/arithmetic.rs @@ -9,7 +9,7 @@ use nom::{ branch::alt, character::complete::{char, digit1, one_of, space0}, combinator::map_res, - multi::fold_many0, + multi::fold, sequence::{delimited, pair}, IResult, }; @@ -37,7 +37,7 @@ fn factor(input: &[u8]) -> IResult<&[u8], i64> { // the math by folding everything fn term(input: &[u8]) -> IResult<&[u8], i64> { let (input, init) = factor(input)?; - fold_many0( + fold(0.., pair(one_of("*/"), factor), move || init, |acc, (op, val)| { @@ -52,7 +52,7 @@ fn term(input: &[u8]) -> IResult<&[u8], i64> { fn expr(input: &[u8]) -> IResult<&[u8], i64> { let (input, init) = term(input)?; - fold_many0( + fold(0.., pair(one_of("+-"), term), move || init, |acc, (op, val)| { diff --git a/benches/http.rs b/benches/http.rs index 4145d4a7b..fd26893a1 100644 --- a/benches/http.rs +++ b/benches/http.rs @@ -4,7 +4,7 @@ static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc; use criterion::*; -use nom::{IResult, bytes::complete::{tag, take_while1}, character::complete::{line_ending, char}, multi::many1}; +use nom::{IResult, bytes::complete::{tag, take_while1}, character::complete::{line_ending, char}, multi::many}; #[cfg_attr(rustfmt, rustfmt_skip)] #[derive(Debug)] @@ -96,14 +96,14 @@ fn message_header_value(input: &[u8]) -> IResult<&[u8], &[u8]> { fn message_header(input: &[u8]) -> IResult<&[u8], Header<'_>> { let (input, name) = take_while1(is_token)(input)?; let (input, _) = char(':')(input)?; - let (input, value) = many1(message_header_value)(input)?; + let (input, value) = many(1.., message_header_value)(input)?; Ok((input, Header{ name, value })) } fn request(input: &[u8]) -> IResult<&[u8], (Request<'_>, Vec>)> { let (input, req) = request_line(input)?; - let (input, h) = many1(message_header)(input)?; + let (input, h) = many(1.., message_header)(input)?; let (input, _) = line_ending(input)?; Ok((input, (req, h))) diff --git a/benches/ini.rs b/benches/ini.rs index b2f651b41..55ea5a39a 100644 --- a/benches/ini.rs +++ b/benches/ini.rs @@ -9,7 +9,7 @@ use nom::{ alphanumeric1 as alphanumeric, char, multispace1 as multispace, space1 as space, }, combinator::{map, map_res, opt}, - multi::many0, + multi::many, sequence::{delimited, pair, separated_pair, terminated, tuple}, IResult, }; @@ -33,11 +33,11 @@ fn key_value(i: &[u8]) -> IResult<&[u8], (&str, &str)> { fn categories(i: &[u8]) -> IResult<&[u8], HashMap<&str, HashMap<&str, &str>>> { map( - many0(separated_pair( + many(0.., separated_pair( category, opt(multispace), map( - many0(terminated(key_value, opt(multispace))), + many(0.., terminated(key_value, opt(multispace))), |vec: Vec<_>| vec.into_iter().collect(), ), )), @@ -70,7 +70,7 @@ file=payroll.dat \0"; fn acc(i: &[u8]) -> IResult<&[u8], Vec<(&str, &str)>> { - many0(key_value)(i) + many(0.., key_value)(i) } let mut group = c.benchmark_group("ini keys and values"); diff --git a/benches/ini_str.rs b/benches/ini_str.rs index 7df62194a..82dce2efa 100644 --- a/benches/ini_str.rs +++ b/benches/ini_str.rs @@ -7,7 +7,7 @@ use nom::{ bytes::complete::{is_a, tag, take_till, take_while}, character::complete::{alphanumeric1 as alphanumeric, char, not_line_ending, space0 as space}, combinator::opt, - multi::many0, + multi::many, sequence::{delimited, pair, terminated, tuple}, IResult, }; @@ -40,7 +40,7 @@ fn key_value(i: &str) -> IResult<&str, (&str, &str)> { } fn keys_and_values_aggregator(i: &str) -> IResult<&str, Vec<(&str, &str)>> { - many0(key_value)(i) + many(0.., key_value)(i) } fn keys_and_values(input: &str) -> IResult<&str, HashMap<&str, &str>> { @@ -55,7 +55,7 @@ fn category_and_keys(i: &str) -> IResult<&str, (&str, HashMap<&str, &str>)> { } fn categories_aggregator(i: &str) -> IResult<&str, Vec<(&str, HashMap<&str, &str>)>> { - many0(category_and_keys)(i) + many(0.., category_and_keys)(i) } fn categories(input: &str) -> IResult<&str, HashMap<&str, HashMap<&str, &str>>> { diff --git a/benches/json.rs b/benches/json.rs index 7dd3f5a18..3d4f44a74 100644 --- a/benches/json.rs +++ b/benches/json.rs @@ -11,7 +11,7 @@ use nom::{ character::complete::{anychar, char, multispace0, none_of}, combinator::{map, map_opt, map_res, value, verify}, error::{ErrorKind, ParseError}, - multi::{fold_many0, separated_list0}, + multi::{fold, separated_list0}, number::complete::{double, recognize_float}, sequence::{delimited, preceded, separated_pair}, IResult, Parser, @@ -87,7 +87,7 @@ fn character(input: &str) -> IResult<&str, char> { fn string(input: &str) -> IResult<&str, String> { delimited( char('"'), - fold_many0(character, String::new, |mut string, c| { + fold(0.., character, String::new, |mut string, c| { string.push(c); string }), From 1a4c2b345ed69e79e59f19dac86dd84e4d71128d Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 25 Sep 2021 15:01:05 +0200 Subject: [PATCH 35/38] Add feature flag to bounds import --- src/multi/mod.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 5db8be3fb..9bc905f2d 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -10,6 +10,7 @@ use crate::internal::{Err, IResult, Needed, Parser}; use crate::lib::std::vec::Vec; use crate::{NomRange, traits::{InputLength, InputTake, ToUsize}}; use core::num::NonZeroUsize; +#[cfg(feature="alloc")] use core::ops::Bound; /// Repeats the embedded parser until it fails From 52d801fea55906e46b52b45155614fdfbf7fb118 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 25 Sep 2021 15:04:06 +0200 Subject: [PATCH 36/38] Correct iterator documentation --- src/traits.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index 8b8bf30fc..f61a89a71 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1436,8 +1436,8 @@ pub trait NomRange { /// Creates a bounded iterator. /// A bounded iterator counts the number of iterations starting from 0 up to the upper bound of this range. - /// If the upper bounds is infinite the iterator counts up to the largest representable value of its type and - /// returns `None` for all further elements. + /// If the upper bounds is infinite the iterator counts up until the amount of iterations has reached the + /// largest representable value of its type and then returns `None` for all further elements. fn bounded_iter(&self) -> Self::Iter2; } From 9e6629125ee60d98a407818e765461bd67dd1f63 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 25 Sep 2021 17:54:40 +0200 Subject: [PATCH 37/38] Change inversion check to remain compatible with rust 1.41.1 --- src/traits.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/traits.rs b/src/traits.rs index f61a89a71..6c60fd9f6 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -1449,7 +1449,7 @@ impl NomRange for Range { fn contains(&self, item: &usize) -> bool {RangeBounds::contains(self, item)} - fn is_inverted(&self) -> bool {>::is_empty(self)} + fn is_inverted(&self) -> bool {!(self.start < self.end)} fn saturating_iter(&self) -> Self::Iter1 { if self.end == 0 { @@ -1476,7 +1476,7 @@ impl NomRange for RangeInclusive { fn contains(&self, item: &usize) -> bool {RangeBounds::contains(self, item)} - fn is_inverted(&self) -> bool {>::is_empty(self)} + fn is_inverted(&self) -> bool {!RangeInclusive::contains(self, self.start())} fn saturating_iter(&self) -> Self::Iter1 { 0..*self.end() From fdd720fcc2aea5e954c14ee67b0f9444c86e9d05 Mon Sep 17 00:00:00 2001 From: cenodis <57576911+cenodis@users.noreply.github.com> Date: Sat, 25 Sep 2021 18:07:06 +0200 Subject: [PATCH 38/38] Remove deprecation warning --- src/multi/mod.rs | 6 ------ src/multi/tests.rs | 8 -------- 2 files changed, 14 deletions(-) diff --git a/src/multi/mod.rs b/src/multi/mod.rs index 9bc905f2d..dca64095d 100644 --- a/src/multi/mod.rs +++ b/src/multi/mod.rs @@ -39,7 +39,6 @@ use core::ops::Bound; /// ``` #[cfg(feature = "alloc")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] -#[deprecated = "Replaced with `many`"] pub fn many0(mut f: F) -> impl FnMut(I) -> IResult, E> where I: Clone + InputLength, @@ -95,7 +94,6 @@ where /// ``` #[cfg(feature = "alloc")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] -#[deprecated = "Replaced with `many`"] pub fn many1(mut f: F) -> impl FnMut(I) -> IResult, E> where I: Clone + InputLength, @@ -353,7 +351,6 @@ where /// ``` #[cfg(feature = "alloc")] #[cfg_attr(feature = "docsrs", doc(cfg(feature = "alloc")))] -#[deprecated = "Replaced with `many`"] pub fn many_m_n( min: usize, max: usize, @@ -642,7 +639,6 @@ where /// assert_eq!(parser("123123"), Ok(("123123", vec![]))); /// assert_eq!(parser(""), Ok(("", vec![]))); /// ``` -#[deprecated = "Replaced with `fold`"] pub fn fold_many0( mut f: F, mut init: H, @@ -714,7 +710,6 @@ where /// assert_eq!(parser("123123"), Err(Err::Error(Error::new("123123", ErrorKind::Many1)))); /// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Many1)))); /// ``` -#[deprecated = "Replaced with `fold`"] pub fn fold_many1( mut f: F, mut init: H, @@ -799,7 +794,6 @@ where /// assert_eq!(parser(""), Ok(("", vec![]))); /// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"]))); /// ``` -#[deprecated = "Replaced with `fold`"] pub fn fold_many_m_n( min: usize, max: usize, diff --git a/src/multi/tests.rs b/src/multi/tests.rs index 8f72459cc..0f294bbae 100644 --- a/src/multi/tests.rs +++ b/src/multi/tests.rs @@ -9,7 +9,6 @@ use crate::{ sequence::{pair, tuple}, }; #[cfg(feature = "alloc")] -#[allow(deprecated)] use crate::{ lib::std::vec::Vec, multi::{ @@ -104,7 +103,6 @@ fn separated_list1_test() { #[test] #[cfg(feature = "alloc")] -#[allow(deprecated)] fn many0_test() { fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { many0(tag("abcd"))(i) @@ -143,7 +141,6 @@ fn many0_bench(b: &mut Bencher) { #[test] #[cfg(feature = "alloc")] -#[allow(deprecated)] fn many1_test() { fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { many1(tag("abcd"))(i) @@ -192,7 +189,6 @@ fn many_till_test() { #[test] #[cfg(feature = "std")] -#[allow(deprecated)] fn infinite_many() { fn tst(input: &[u8]) -> IResult<&[u8], &[u8]> { Err(Err::Error(error_position!(input, ErrorKind::Tag))) @@ -217,7 +213,6 @@ fn infinite_many() { #[test] #[cfg(feature = "alloc")] -#[allow(deprecated)] fn many_m_n_test() { fn multi(i: &[u8]) -> IResult<&[u8], Vec<&[u8]>> { many_m_n(2, 4, tag("Abcd"))(i) @@ -420,7 +415,6 @@ fn length_value_test() { #[test] #[cfg(feature = "alloc")] -#[allow(deprecated)] fn fold_many0_test() { fn fold_into_vec(mut acc: Vec, item: T) -> Vec { acc.push(item); @@ -453,7 +447,6 @@ fn fold_many0_test() { #[test] #[cfg(feature = "alloc")] -#[allow(deprecated)] fn fold_many1_test() { fn fold_into_vec(mut acc: Vec, item: T) -> Vec { acc.push(item); @@ -481,7 +474,6 @@ fn fold_many1_test() { #[test] #[cfg(feature = "alloc")] -#[allow(deprecated)] fn fold_many_m_n_test() { fn fold_into_vec(mut acc: Vec, item: T) -> Vec { acc.push(item);