use std::collections::HashMap; use std::iter::Iterator; use winnow::ascii::alphanumeric1; use winnow::combinator::iterator; use winnow::combinator::{separated_pair, terminated}; use winnow::prelude::*; fn main() { let mut data = "abcabcabcabc"; fn parser(i: &str) -> IResult<&str, &str> { "abc".parse_next(i) } // `from_fn` (available from Rust 1.34) can create an iterator // from a closure let it = std::iter::from_fn(move || { match parser(data) { // when successful, a parser returns a tuple of // the remaining input and the output value. // So we replace the captured input data with the // remaining input, to be parsed on the next call Ok((i, o)) => { data = i; Some(o) } _ => None, } }); for value in it { println!("parser returned: {}", value); } println!("\n********************\n"); let data = "abcabcabcabc"; // if `from_fn` is not available, it is possible to fold // over an iterator of functions let res = std::iter::repeat(parser).take(3).try_fold( (data, Vec::new()), |(data, mut acc), parser| { parser(data).map(|(i, o)| { acc.push(o); (i, acc) }) }, ); // will print "parser iterator returned: Ok(("abc", ["abc", "abc", "abc"]))" println!("\nparser iterator returned: {:?}", res); println!("\n********************\n"); let data = "key1:value1,key2:value2,key3:value3,;"; // `winnow::combinator::iterator` will return an iterator // producing the parsed values. Compared to the previous // solutions: // - we can work with a normal iterator like `from_fn` // - we can get the remaining input afterwards, like with the `try_fold` trick let mut winnow_it = iterator( data, terminated(separated_pair(alphanumeric1, ":", alphanumeric1), ","), ); let res = winnow_it .map(|(k, v)| (k.to_uppercase(), v)) .collect::>(); let parser_result: IResult<_, _> = winnow_it.finish(); let (remaining_input, ()) = parser_result.unwrap(); // will print "iterator returned {"key1": "value1", "key3": "value3", "key2": "value2"}, remaining input is ';'" println!( "iterator returned {:?}, remaining input is '{}'", res, remaining_input ); }