use nom::{ error::ErrorKind, error::ParseError, IResult, InputIter, InputLength, InputTake, Parser, }; /// Returns the shortest input slice till it matches the parser. /// /// It doesn't consume the input to the parser. It will return `Err(Err::Error((_, ErrorKind::TakeUntilParserMatches)))` /// if the pattern wasn't met /// /// The performance of this parser depends HEAVILY on the inner parser /// failing early. For each step on the input, this will run the inner /// parser against the remaining input, so if the inner parser does /// not fail fast then you will end up re-parsing the remaining input /// repeatedly. /// /// If you are looking to match until a string /// (`take_until_parser_matches(tag("foo"))`) it would be faster to /// use `take_until("foo")`. /// /// # Simple Example /// ```ignore /// # #[macro_use] extern crate nom; /// # use nom::{Err, error::ErrorKind, IResult}; /// use nom::bytes::complete::{take_until_parser_matches, tag}; /// /// fn until_eof(s: &str) -> IResult<&str, &str> { /// take_until_parser_matches(tag("eof"))(s) /// } /// /// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world"))); /// assert_eq!(until_eof("hello, world"), Err(Err::Error(error_position!("hello, world", ErrorKind::TakeUntilParserMatches)))); /// assert_eq!(until_eof(""), Err(Err::Error(error_position!("", ErrorKind::TakeUntilParserMatches)))); /// ``` /// /// # Powerful Example /// To show the power of this parser we will parse a line containing /// a set of flags at the end surrounded by brackets. Example: /// "Submit a PR [inprogress]" /// ```ignore /// # #[macro_use] extern crate nom; /// # use nom::{Err, error::ErrorKind, IResult}; /// use nom::bytes::complete::{is_not, take_until_parser_matches, tag}; /// use nom::sequence::{delimited, tuple}; /// use nom::multi::separated_list1; /// /// fn flag(i: &str) -> IResult<&str, &str> { /// delimited(tag("["), is_not("]\r\n"), tag("]"))(i) /// } /// /// fn line_ending_with_flags(i: &str) -> IResult<&str, (&str, std::vec::Vec<&str>)> { /// tuple(( /// take_until_parser_matches(flag), /// separated_list1(tag(" "), flag), /// ))(i) /// } /// /// assert_eq!(line_ending_with_flags("Parsing Seminar [important] [presentation]"), Ok(("", ("Parsing Seminar ", vec!["important", "presentation"])))); /// ``` pub fn take_until_parser_matches( mut f: F, ) -> impl FnMut(Input) -> IResult where Input: InputTake + InputIter + InputLength + Clone, F: Parser, Error: ParseError, { move |input: Input| { let i = input.clone(); for (ind, _) in i.iter_indices() { let (remaining, _taken) = i.take_split(ind); match f.parse(remaining) { Err(_) => (), Ok(_) => { let res: IResult = Ok(i.take_split(ind)); return res; } } } // Attempt to match one last time past the end of the input. This // allows for 0-length combinators to be used (for example, an eof // combinator). let (remaining, _taken) = i.take_split(i.input_len()); match f.parse(remaining) { Err(_) => (), Ok(_) => { let res: IResult = Ok(i.take_split(i.input_len())); return res; } } Err(nom::Err::Error(Error::from_error_kind( i, // Normally this would be `ErrorKind::TakeUntilParserMatches` but I cannot extend ErrorKind in this project. ErrorKind::TakeUntil, ))) } }