Skip to content

Commit

Permalink
feat(multi): Switch from Vec to impl Accumulate
Browse files Browse the repository at this point in the history
I went with a custom trait so we could cover `()` and `usize` as well as
support custom capacities.

This comes at the cost of supporting any container possible.  We could
possibly do that with a `Extendable(T: Default + Extend)` newtype.

As an alternative to `()` and `usize` is GATs.  The main difference is
who drives the types.

Fixes winnow-rs#122
  • Loading branch information
epage committed Feb 3, 2023
1 parent 64d46e3 commit ff14fe5
Show file tree
Hide file tree
Showing 10 changed files with 61 additions and 81 deletions.
3 changes: 1 addition & 2 deletions examples/ini/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,8 @@ pub fn categories(i: Input<'_>) -> IResult<Input<'_>, HashMap<&str, HashMap<&str
many0(separated_pair(
category,
opt(multispace),
many0(terminated(key_value, opt(multispace))).map(|vec: Vec<_>| vec.into_iter().collect()),
many0(terminated(key_value, opt(multispace))),
))
.map(|vec: Vec<_>| vec.into_iter().collect())
.parse_next(i)
}

Expand Down
19 changes: 2 additions & 17 deletions examples/ini/parser_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,7 @@ use winnow::{
pub type Input<'i> = &'i str;

pub fn categories(input: Input<'_>) -> IResult<Input<'_>, HashMap<&str, HashMap<&str, &str>>> {
match categories_aggregator(input) {
Ok((i, tuple_vec)) => Ok((i, tuple_vec.into_iter().collect())),
Err(e) => Err(e),
}
}

#[allow(clippy::type_complexity)]
fn categories_aggregator(i: Input<'_>) -> IResult<Input<'_>, Vec<(&str, HashMap<&str, &str>)>> {
many0(category_and_keys)(i)
many0(category_and_keys)(input)
}

fn category_and_keys(i: Input<'_>) -> IResult<Input<'_>, (&str, HashMap<&str, &str>)> {
Expand All @@ -35,14 +27,7 @@ fn category(i: Input<'_>) -> IResult<Input<'_>, &str> {
}

fn keys_and_values(input: Input<'_>) -> IResult<Input<'_>, HashMap<&str, &str>> {
match keys_and_values_aggregator(input) {
Ok((i, tuple_vec)) => Ok((i, tuple_vec.into_iter().collect())),
Err(e) => Err(e),
}
}

fn keys_and_values_aggregator(i: Input<'_>) -> IResult<Input<'_>, Vec<(&str, &str)>> {
many0(key_value)(i)
many0(key_value)(input)
}

fn key_value(i: Input<'_>) -> IResult<Input<'_>, (&str, &str)> {
Expand Down
3 changes: 1 addition & 2 deletions examples/json/parser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,8 +175,7 @@ fn object<'i, E: ParseError<Input<'i>> + ContextError<Input<'i>, &'static str>>(
preceded(
('{', ws),
cut_err(terminated(
separated_list0((ws, ',', ws), key_value)
.map(|tuple_vec| tuple_vec.into_iter().map(|(k, v)| (k, v)).collect()),
separated_list0((ws, ',', ws), key_value),
(ws, '}'),
)),
)
Expand Down
3 changes: 1 addition & 2 deletions examples/json/parser_dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,7 @@ fn object<'i, E: ParseError<Input<'i>> + ContextError<Input<'i>, &'static str>>(
preceded(
('{', ws),
cut_err(terminated(
separated_list0((ws, ',', ws), key_value)
.map(|tuple_vec| tuple_vec.into_iter().map(|(k, v)| (k, v)).collect()),
separated_list0((ws, ',', ws), key_value),
(ws, '}'),
)),
)
Expand Down
3 changes: 1 addition & 2 deletions examples/json/parser_streaming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,8 +184,7 @@ fn object<'i, E: ParseError<Input<'i>> + ContextError<Input<'i>, &'static str>>(
preceded(
(one_of('{'), ws),
cut_err(terminated(
separated_list0((ws, one_of(','), ws), key_value)
.map(|tuple_vec| tuple_vec.into_iter().map(|(k, v)| (k, v)).collect()),
separated_list0((ws, one_of(','), ws), key_value),
(ws, one_of('}')),
)),
)
Expand Down
4 changes: 2 additions & 2 deletions examples/json_iterator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -227,7 +227,7 @@ fn array(i: &str) -> IResult<&str, ()> {
preceded(
'[',
cut_err(terminated(
separated_list0(preceded(sp, ','), value).map(|_| ()),
separated_list0(preceded(sp, ','), value),
preceded(sp, ']'),
)),
)
Expand All @@ -243,7 +243,7 @@ fn hash(i: &str) -> IResult<&str, ()> {
preceded(
'{',
cut_err(terminated(
separated_list0(preceded(sp, ','), key_value).map(|_| ()),
separated_list0(preceded(sp, ','), key_value),
preceded(sp, '}'),
)),
)
Expand Down
84 changes: 39 additions & 45 deletions src/multi/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,8 @@ mod tests;
use crate::error::ErrMode;
use crate::error::ErrorKind;
use crate::error::ParseError;
#[cfg(feature = "alloc")]
use crate::input::clamp_capacity;
use crate::input::Accumulate;
use crate::input::{Input, InputIsStreaming, ToUsize, UpdateSlice};
#[cfg(feature = "alloc")]
use crate::lib::std::vec::Vec;
use crate::{IResult, Parser};

/// Repeats the embedded parser, gathering the results in a `Vec`.
Expand Down Expand Up @@ -38,15 +35,15 @@ use crate::{IResult, Parser};
/// assert_eq!(parser("123123"), Ok(("123123", vec![])));
/// assert_eq!(parser(""), Ok(("", vec![])));
/// ```
#[cfg(feature = "alloc")]
pub fn many0<I, O, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
pub fn many0<I, O, C, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, C, E>
where
I: Input,
C: Accumulate<O>,
F: Parser<I, O, E>,
E: ParseError<I>,
{
move |mut i: I| {
let mut acc = crate::lib::std::vec::Vec::with_capacity(4);
let mut acc = C::initial(None);
loop {
let len = i.input_len();
match f.parse_next(i.clone()) {
Expand All @@ -59,7 +56,7 @@ where
}

i = i1;
acc.push(o);
acc.accumulate(o);
}
}
}
Expand Down Expand Up @@ -92,18 +89,18 @@ where
/// assert_eq!(parser("123123"), Err(ErrMode::Backtrack(Error::new("123123", ErrorKind::Tag))));
/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag))));
/// ```
#[cfg(feature = "alloc")]
pub fn many1<I, O, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
pub fn many1<I, O, C, E, F>(mut f: F) -> impl FnMut(I) -> IResult<I, C, E>
where
I: Input,
C: Accumulate<O>,
F: Parser<I, O, E>,
E: ParseError<I>,
{
move |mut i: I| match f.parse_next(i.clone()) {
Err(e) => Err(e.append(i, ErrorKind::Many1)),
Ok((i1, o)) => {
let mut acc = crate::lib::std::vec::Vec::with_capacity(4);
acc.push(o);
let mut acc = C::initial(None);
acc.accumulate(o);
i = i1;

loop {
Expand All @@ -118,7 +115,7 @@ where
}

i = i1;
acc.push(o);
acc.accumulate(o);
}
}
}
Expand Down Expand Up @@ -147,19 +144,16 @@ where
/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag))));
/// assert_eq!(parser("abcendefg"), Ok(("efg", (vec!["abc"], "end"))));
/// ```
#[cfg(feature = "alloc")]
pub fn many_till<I, O, P, E, F, G>(
mut f: F,
mut g: G,
) -> impl FnMut(I) -> IResult<I, (Vec<O>, P), E>
pub fn many_till<I, O, C, P, E, F, G>(mut f: F, mut g: G) -> impl FnMut(I) -> IResult<I, (C, P), E>
where
I: Input,
C: Accumulate<O>,
F: Parser<I, O, E>,
G: Parser<I, P, E>,
E: ParseError<I>,
{
move |mut i: I| {
let mut res = crate::lib::std::vec::Vec::new();
let mut res = C::initial(None);
loop {
let len = i.input_len();
match g.parse_next(i.clone()) {
Expand All @@ -173,7 +167,7 @@ where
return Err(ErrMode::from_error_kind(i1, ErrorKind::ManyTill));
}

res.push(o);
res.accumulate(o);
i = i1;
}
}
Expand Down Expand Up @@ -208,25 +202,25 @@ where
/// assert_eq!(parser(""), Ok(("", vec![])));
/// assert_eq!(parser("def|abc"), Ok(("def|abc", vec![])));
/// ```
#[cfg(feature = "alloc")]
pub fn separated_list0<I, O, O2, E, F, G>(
pub fn separated_list0<I, O, C, O2, E, F, G>(
mut sep: G,
mut f: F,
) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
) -> impl FnMut(I) -> IResult<I, C, E>
where
I: Input,
C: Accumulate<O>,
F: Parser<I, O, E>,
G: Parser<I, O2, E>,
E: ParseError<I>,
{
move |mut i: I| {
let mut res = Vec::new();
let mut res = C::initial(None);

match f.parse_next(i.clone()) {
Err(ErrMode::Backtrack(_)) => return Ok((i, res)),
Err(e) => return Err(e),
Ok((i1, o)) => {
res.push(o);
res.accumulate(o);
i = i1;
}
}
Expand All @@ -246,7 +240,7 @@ where
Err(ErrMode::Backtrack(_)) => return Ok((i, res)),
Err(e) => return Err(e),
Ok((i2, o)) => {
res.push(o);
res.accumulate(o);
i = i2;
}
}
Expand Down Expand Up @@ -281,25 +275,25 @@ where
/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag))));
/// assert_eq!(parser("def|abc"), Err(ErrMode::Backtrack(Error::new("def|abc", ErrorKind::Tag))));
/// ```
#[cfg(feature = "alloc")]
pub fn separated_list1<I, O, O2, E, F, G>(
pub fn separated_list1<I, O, C, O2, E, F, G>(
mut sep: G,
mut f: F,
) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
) -> impl FnMut(I) -> IResult<I, C, E>
where
I: Input,
C: Accumulate<O>,
F: Parser<I, O, E>,
G: Parser<I, O2, E>,
E: ParseError<I>,
{
move |mut i: I| {
let mut res = Vec::new();
let mut res = C::initial(None);

// Parse the first element
match f.parse_next(i.clone()) {
Err(e) => return Err(e),
Ok((i1, o)) => {
res.push(o);
res.accumulate(o);
i = i1;
}
}
Expand All @@ -319,7 +313,7 @@ where
Err(ErrMode::Backtrack(_)) => return Ok((i, res)),
Err(e) => return Err(e),
Ok((i2, o)) => {
res.push(o);
res.accumulate(o);
i = i2;
}
}
Expand Down Expand Up @@ -358,14 +352,14 @@ where
/// assert_eq!(parser(""), Ok(("", vec![])));
/// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"])));
/// ```
#[cfg(feature = "alloc")]
pub fn many_m_n<I, O, E, F>(
pub fn many_m_n<I, O, C, E, F>(
min: usize,
max: usize,
mut parse: F,
) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
) -> impl FnMut(I) -> IResult<I, C, E>
where
I: Input,
C: Accumulate<O>,
F: Parser<I, O, E>,
E: ParseError<I>,
{
Expand All @@ -374,7 +368,7 @@ where
return Err(ErrMode::Cut(E::from_error_kind(input, ErrorKind::ManyMN)));
}

let mut res = crate::lib::std::vec::Vec::with_capacity(clamp_capacity::<O>(min));
let mut res = C::initial(Some(min));
for count in 0..max {
let len = input.input_len();
match parse.parse_next(input.clone()) {
Expand All @@ -384,7 +378,7 @@ where
return Err(ErrMode::from_error_kind(input, ErrorKind::ManyMN));
}

res.push(value);
res.accumulate(value);
input = tail;
}
Err(ErrMode::Backtrack(e)) => {
Expand Down Expand Up @@ -544,22 +538,22 @@ where
/// assert_eq!(parser(""), Err(ErrMode::Backtrack(Error::new("", ErrorKind::Tag))));
/// assert_eq!(parser("abcabcabc"), Ok(("abc", vec!["abc", "abc"])));
/// ```
#[cfg(feature = "alloc")]
pub fn count<I, O, E, F>(mut f: F, count: usize) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
pub fn count<I, O, C, E, F>(mut f: F, count: usize) -> impl FnMut(I) -> IResult<I, C, E>
where
I: Clone + PartialEq,
C: Accumulate<O>,
F: Parser<I, O, E>,
E: ParseError<I>,
{
move |i: I| {
let mut input = i.clone();
let mut res = crate::lib::std::vec::Vec::with_capacity(clamp_capacity::<O>(count));
let mut res = C::initial(Some(count));

for _ in 0..count {
let input_ = input.clone();
match f.parse_next(input_) {
Ok((i, o)) => {
res.push(o);
res.accumulate(o);
input = i;
}
Err(e) => {
Expand Down Expand Up @@ -979,25 +973,25 @@ where
/// assert_eq!(parser(&b"\x02abcabcabc"[..]), Ok(((&b"abc"[..], vec![&b"abc"[..], &b"abc"[..]]))));
/// assert_eq!(parser(b"\x03123123123"), Err(ErrMode::Backtrack(Error::new(&b"123123123"[..], ErrorKind::Tag))));
/// ```
#[cfg(feature = "alloc")]
pub fn length_count<I, O, N, E, F, G>(mut f: F, mut g: G) -> impl FnMut(I) -> IResult<I, Vec<O>, E>
pub fn length_count<I, O, C, N, E, F, G>(mut f: F, mut g: G) -> impl FnMut(I) -> IResult<I, C, E>
where
I: Clone,
N: ToUsize,
C: Accumulate<O>,
F: Parser<I, N, E>,
G: Parser<I, O, E>,
E: ParseError<I>,
{
move |i: I| {
let (i, count) = f.parse_next(i)?;
let mut input = i.clone();
let mut res = Vec::with_capacity(clamp_capacity::<O>(count.to_usize()));
let mut res = C::initial(Some(count.to_usize()));

for _ in 0..count.to_usize() {
let input_ = input.clone();
match g.parse_next(input_) {
Ok((i, o)) => {
res.push(o);
res.accumulate(o);
input = i;
}
Err(e) => {
Expand Down
11 changes: 6 additions & 5 deletions tests/testsuite/fnmut.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,17 @@
#![cfg(feature = "alloc")]

use winnow::{
bytes::tag,
multi::{many0, many0_count},
};
use winnow::bytes::tag;
#[cfg(feature = "std")]
use winnow::multi::many0;
use winnow::multi::many0_count;

#[test]
#[cfg(feature = "std")]
fn parse() {
let mut counter = 0;

let res = {
let mut parser = many0::<_, _, (), _>(|i| {
let mut parser = many0::<_, _, Vec<_>, (), _>(|i| {
counter += 1;
tag("abc")(i)
});
Expand Down
Loading

0 comments on commit ff14fe5

Please sign in to comment.