| //! parsers recognizing bytes streams, complete input version |
| |
| use crate::error::ErrorKind; |
| use crate::error::ParseError; |
| use crate::internal::{Err, IResult}; |
| use crate::lib::std::ops::RangeFrom; |
| use crate::lib::std::result::Result::*; |
| use crate::traits::{Compare, CompareResult, FindSubstring, FindToken, InputIter, InputLength, InputTake, InputTakeAtPosition, Slice, ToUsize}; |
| |
| /// Recognizes a pattern |
| /// |
| /// The input data will be compared to the tag combinator's argument and will return the part of |
| /// the input that matches the argument |
| /// |
| /// It will return `Err(Err::Error((_, ErrorKind::Tag)))` if the input doesn't match the pattern |
| /// # Example |
| /// ```rust |
| /// # #[macro_use] extern crate nom; |
| /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
| /// use nom::bytes::complete::tag; |
| /// |
| /// fn parser(s: &str) -> IResult<&str, &str> { |
| /// tag("Hello")(s) |
| /// } |
| /// |
| /// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello"))); |
| /// assert_eq!(parser("Something"), Err(Err::Error(("Something", ErrorKind::Tag)))); |
| /// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag)))); |
| /// ``` |
| pub fn tag<'a, T: 'a, Input: 'a, Error: ParseError<Input>>(tag: T) -> impl Fn(Input) -> IResult<Input, Input, Error> |
| where |
| Input: InputTake + Compare<T>, |
| T: InputLength + Clone, |
| { |
| move |i: Input| { |
| let tag_len = tag.input_len(); |
| let t = tag.clone(); |
| let res: IResult<_, _, Error> = match i.compare(t) { |
| CompareResult::Ok => Ok(i.take_split(tag_len)), |
| _ => { |
| let e: ErrorKind = ErrorKind::Tag; |
| Err(Err::Error(Error::from_error_kind(i, e))) |
| } |
| }; |
| res |
| } |
| } |
| |
| /// Recognizes a case insensitive pattern |
| /// |
| /// The input data will be compared to the tag combinator's argument and will return the part of |
| /// the input that matches the argument with no regard to case |
| /// |
| /// It will return `Err(Err::Error((_, ErrorKind::Tag)))` if the input doesn't match the pattern |
| /// # Example |
| /// ```rust |
| /// # #[macro_use] extern crate nom; |
| /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
| /// use nom::bytes::complete::tag_no_case; |
| /// |
| /// fn parser(s: &str) -> IResult<&str, &str> { |
| /// tag_no_case("hello")(s) |
| /// } |
| /// |
| /// assert_eq!(parser("Hello, World!"), Ok((", World!", "Hello"))); |
| /// assert_eq!(parser("hello, World!"), Ok((", World!", "hello"))); |
| /// assert_eq!(parser("HeLlO, World!"), Ok((", World!", "HeLlO"))); |
| /// assert_eq!(parser("Something"), Err(Err::Error(("Something", ErrorKind::Tag)))); |
| /// assert_eq!(parser(""), Err(Err::Error(("", ErrorKind::Tag)))); |
| /// ``` |
| pub fn tag_no_case<T, Input, Error: ParseError<Input>>(tag: T) -> impl Fn(Input) -> IResult<Input, Input, Error> |
| where |
| Input: InputTake + Compare<T>, |
| T: InputLength + Clone, |
| { |
| move |i: Input| { |
| let tag_len = tag.input_len(); |
| let t = tag.clone(); |
| |
| let res: IResult<_, _, Error> = match (i).compare_no_case(t) { |
| CompareResult::Ok => Ok(i.take_split(tag_len)), |
| _ => { |
| let e: ErrorKind = ErrorKind::Tag; |
| Err(Err::Error(Error::from_error_kind(i, e))) |
| } |
| }; |
| res |
| } |
| } |
| |
| /// Parse till certain characters are met |
| /// |
| /// The parser will return the longest slice till one of the characters of the combinator's argument are met. |
| /// |
| /// It doesn't consume the matched character, |
| /// |
| /// It will return a `Err::Error(("", ErrorKind::IsNot))` if the pattern wasn't met |
| /// # Example |
| /// ```rust |
| /// # #[macro_use] extern crate nom; |
| /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
| /// use nom::bytes::complete::is_not; |
| /// |
| /// fn not_space(s: &str) -> IResult<&str, &str> { |
| /// is_not(" \t\r\n")(s) |
| /// } |
| /// |
| /// assert_eq!(not_space("Hello, World!"), Ok((" World!", "Hello,"))); |
| /// assert_eq!(not_space("Sometimes\t"), Ok(("\t", "Sometimes"))); |
| /// assert_eq!(not_space("Nospace"), Ok(("", "Nospace"))); |
| /// assert_eq!(not_space(""), Err(Err::Error(("", ErrorKind::IsNot)))); |
| /// ``` |
| pub fn is_not<T, Input, Error: ParseError<Input>>(arr: T) -> impl Fn(Input) -> IResult<Input, Input, Error> |
| where |
| Input: InputTakeAtPosition, |
| T: InputLength + FindToken<<Input as InputTakeAtPosition>::Item>, |
| { |
| move |i: Input| { |
| let e: ErrorKind = ErrorKind::IsNot; |
| i.split_at_position1_complete(|c| arr.find_token(c), e) |
| } |
| } |
| |
| /// Returns the longest slice of the matches the pattern |
| /// |
| /// The parser will return the longest slice consisting of the characters in provided in the |
| /// combinator's argument |
| /// |
| /// It will return a `Err(Err::Error((_, ErrorKind::IsA)))` if the pattern wasn't met |
| /// |
| /// # Example |
| /// ```rust |
| /// # #[macro_use] extern crate nom; |
| /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
| /// use nom::bytes::complete::is_a; |
| /// |
| /// fn hex(s: &str) -> IResult<&str, &str> { |
| /// is_a("1234567890ABCDEF")(s) |
| /// } |
| /// |
| /// assert_eq!(hex("123 and voila"), Ok((" and voila", "123"))); |
| /// assert_eq!(hex("DEADBEEF and others"), Ok((" and others", "DEADBEEF"))); |
| /// assert_eq!(hex("BADBABEsomething"), Ok(("something", "BADBABE"))); |
| /// assert_eq!(hex("D15EA5E"), Ok(("", "D15EA5E"))); |
| /// assert_eq!(hex(""), Err(Err::Error(("", ErrorKind::IsA)))); |
| /// ``` |
| pub fn is_a<T, Input, Error: ParseError<Input>>(arr: T) -> impl Fn(Input) -> IResult<Input, Input, Error> |
| where |
| Input: InputTakeAtPosition, |
| T: InputLength + FindToken<<Input as InputTakeAtPosition>::Item>, |
| { |
| move |i: Input| { |
| let e: ErrorKind = ErrorKind::IsA; |
| i.split_at_position1_complete(|c| !arr.find_token(c), e) |
| } |
| } |
| |
| /// Returns the longest input slice (if any) that matches the predicate |
| /// |
| /// The parser will return the longest slice that matches the given predicate *(a function that |
| /// takes the input and returns a bool)* |
| /// |
| /// # Example |
| /// ```rust |
| /// # #[macro_use] extern crate nom; |
| /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
| /// use nom::bytes::complete::take_while; |
| /// use nom::character::is_alphabetic; |
| /// |
| /// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { |
| /// take_while(is_alphabetic)(s) |
| /// } |
| /// |
| /// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); |
| /// assert_eq!(alpha(b"12345"), Ok((&b"12345"[..], &b""[..]))); |
| /// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); |
| /// assert_eq!(alpha(b""), Ok((&b""[..], &b""[..]))); |
| /// ``` |
| pub fn take_while<F, Input, Error: ParseError<Input>>(cond: F) -> impl Fn(Input) -> IResult<Input, Input, Error> |
| where |
| Input: InputTakeAtPosition, |
| F: Fn(<Input as InputTakeAtPosition>::Item) -> bool, |
| { |
| move |i: Input| i.split_at_position_complete(|c| !cond(c)) |
| } |
| |
| /// Returns the longest (atleast 1) input slice that matches the predicate |
| /// |
| /// The parser will return the longest slice that matches the given predicate *(a function that |
| /// takes the input and returns a bool)* |
| /// |
| /// It will return an `Err(Err::Error((_, ErrorKind::TakeWhile1)))` if the pattern wasn't met |
| /// |
| /// # Example |
| /// ```rust |
| /// # #[macro_use] extern crate nom; |
| /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
| /// use nom::bytes::complete::take_while1; |
| /// use nom::character::is_alphabetic; |
| /// |
| /// fn alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { |
| /// take_while1(is_alphabetic)(s) |
| /// } |
| /// |
| /// assert_eq!(alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); |
| /// assert_eq!(alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); |
| /// assert_eq!(alpha(b"12345"), Err(Err::Error((&b"12345"[..], ErrorKind::TakeWhile1)))); |
| /// ``` |
| pub fn take_while1<F, Input, Error: ParseError<Input>>(cond: F) -> impl Fn(Input) -> IResult<Input, Input, Error> |
| where |
| Input: InputTakeAtPosition, |
| F: Fn(<Input as InputTakeAtPosition>::Item) -> bool, |
| { |
| move |i: Input| { |
| let e: ErrorKind = ErrorKind::TakeWhile1; |
| i.split_at_position1_complete(|c| !cond(c), e) |
| } |
| } |
| |
| /// Returns the longest (m <= len <= n) input slice that matches the predicate |
| /// |
| /// The parser will return the longest slice that matches the given predicate *(a function that |
| /// takes the input and returns a bool)* |
| /// |
| /// It will return an `Err::Error((_, ErrorKind::TakeWhileMN))` if the pattern wasn't met or is out |
| /// of range (m <= len <= n) |
| /// |
| /// # Example |
| /// ```rust |
| /// # #[macro_use] extern crate nom; |
| /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
| /// use nom::bytes::complete::take_while_m_n; |
| /// use nom::character::is_alphabetic; |
| /// |
| /// fn short_alpha(s: &[u8]) -> IResult<&[u8], &[u8]> { |
| /// take_while_m_n(3, 6, is_alphabetic)(s) |
| /// } |
| /// |
| /// assert_eq!(short_alpha(b"latin123"), Ok((&b"123"[..], &b"latin"[..]))); |
| /// assert_eq!(short_alpha(b"lengthy"), Ok((&b"y"[..], &b"length"[..]))); |
| /// assert_eq!(short_alpha(b"latin"), Ok((&b""[..], &b"latin"[..]))); |
| /// assert_eq!(short_alpha(b"ed"), Err(Err::Error((&b"ed"[..], ErrorKind::TakeWhileMN)))); |
| /// assert_eq!(short_alpha(b"12345"), Err(Err::Error((&b"12345"[..], ErrorKind::TakeWhileMN)))); |
| /// ``` |
| pub fn take_while_m_n<F, Input, Error: ParseError<Input>>(m: usize, n: usize, cond: F) -> impl Fn(Input) -> IResult<Input, Input, Error> |
| where |
| Input: InputTake + InputIter + InputLength + Slice<RangeFrom<usize>>, |
| F: Fn(<Input as InputIter>::Item) -> bool, |
| { |
| move |i: Input| { |
| let input = i; |
| |
| match input.position(|c| !cond(c)) { |
| Some(idx) => { |
| if idx >= m { |
| if idx <= n { |
| let res: IResult<_, _, Error> = if let Some(index) = input.slice_index(idx) { |
| Ok(input.take_split(index)) |
| } else { |
| Err(Err::Error(Error::from_error_kind(input, ErrorKind::TakeWhileMN))) |
| }; |
| res |
| } else { |
| let res: IResult<_, _, Error> = if let Some(index) = input.slice_index(n) { |
| Ok(input.take_split(index)) |
| } else { |
| Err(Err::Error(Error::from_error_kind(input, ErrorKind::TakeWhileMN))) |
| }; |
| res |
| } |
| } else { |
| let e = ErrorKind::TakeWhileMN; |
| Err(Err::Error(Error::from_error_kind(input, e))) |
| } |
| } |
| None => { |
| let len = input.input_len(); |
| if len >= n { |
| let res: IResult<_, _, Error> = Ok(input.take_split(n)); |
| res |
| } else { |
| if len >= m && len <= n { |
| let res: IResult<_, _, Error> = Ok((input.slice(len..), input)); |
| res |
| } else { |
| let e = ErrorKind::TakeWhileMN; |
| Err(Err::Error(Error::from_error_kind(input, e))) |
| } |
| } |
| } |
| } |
| } |
| } |
| |
| /// Returns the longest input slice (if any) till a predicate is met |
| /// |
| /// The parser will return the longest slice till the given predicate *(a function that |
| /// takes the input and returns a bool)* |
| /// |
| /// # Example |
| /// ```rust |
| /// # #[macro_use] extern crate nom; |
| /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
| /// use nom::bytes::complete::take_till; |
| /// |
| /// fn till_colon(s: &str) -> IResult<&str, &str> { |
| /// take_till(|c| c == ':')(s) |
| /// } |
| /// |
| /// assert_eq!(till_colon("latin:123"), Ok((":123", "latin"))); |
| /// assert_eq!(till_colon(":empty matched"), Ok((":empty matched", ""))); //allowed |
| /// assert_eq!(till_colon("12345"), Ok(("", "12345"))); |
| /// assert_eq!(till_colon(""), Ok(("", ""))); |
| /// ``` |
| pub fn take_till<F, Input, Error: ParseError<Input>>(cond: F) -> impl Fn(Input) -> IResult<Input, Input, Error> |
| where |
| Input: InputTakeAtPosition, |
| F: Fn(<Input as InputTakeAtPosition>::Item) -> bool, |
| { |
| move |i: Input| i.split_at_position_complete(|c| cond(c)) |
| } |
| |
| /// Returns the longest (atleast 1) input slice till a predicate is met |
| /// |
| /// The parser will return the longest slice till the given predicate *(a function that |
| /// takes the input and returns a bool)* |
| /// |
| /// It will return `Err(Err::Error((_, ErrorKind::TakeTill1)))` if the input is empty or the |
| /// predicate matches the first input |
| /// |
| /// # Example |
| /// ```rust |
| /// # #[macro_use] extern crate nom; |
| /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
| /// use nom::bytes::complete::take_till1; |
| /// |
| /// fn till_colon(s: &str) -> IResult<&str, &str> { |
| /// take_till1(|c| c == ':')(s) |
| /// } |
| /// |
| /// assert_eq!(till_colon("latin:123"), Ok((":123", "latin"))); |
| /// assert_eq!(till_colon(":empty matched"), Err(Err::Error((":empty matched", ErrorKind::TakeTill1)))); |
| /// assert_eq!(till_colon("12345"), Ok(("", "12345"))); |
| /// assert_eq!(till_colon(""), Err(Err::Error(("", ErrorKind::TakeTill1)))); |
| /// ``` |
| pub fn take_till1<F, Input, Error: ParseError<Input>>(cond: F) -> impl Fn(Input) -> IResult<Input, Input, Error> |
| where |
| Input: InputTakeAtPosition, |
| F: Fn(<Input as InputTakeAtPosition>::Item) -> bool, |
| { |
| move |i: Input| { |
| let e: ErrorKind = ErrorKind::TakeTill1; |
| i.split_at_position1_complete(|c| cond(c), e) |
| } |
| } |
| |
| /// Returns an input slice containing the first N input elements (Input[..N]) |
| /// |
| /// It will return `Err(Err::Error((_, ErrorKind::Eof)))` if the input is shorter than the argument |
| /// |
| /// # Example |
| /// ```rust |
| /// # #[macro_use] extern crate nom; |
| /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
| /// use nom::bytes::complete::take; |
| /// |
| /// fn take6(s: &str) -> IResult<&str, &str> { |
| /// take(6usize)(s) |
| /// } |
| /// |
| /// assert_eq!(take6("1234567"), Ok(("7", "123456"))); |
| /// assert_eq!(take6("things"), Ok(("", "things"))); |
| /// assert_eq!(take6("short"), Err(Err::Error(("short", ErrorKind::Eof)))); |
| /// assert_eq!(take6(""), Err(Err::Error(("", ErrorKind::Eof)))); |
| /// ``` |
| pub fn take<C, Input, Error: ParseError<Input>>(count: C) -> impl Fn(Input) -> IResult<Input, Input, Error> |
| where |
| Input: InputIter + InputTake, |
| C: ToUsize, |
| { |
| let c = count.to_usize(); |
| move |i: Input| match i.slice_index(c) { |
| None => Err(Err::Error(Error::from_error_kind(i, ErrorKind::Eof))), |
| Some(index) => Ok(i.take_split(index)), |
| } |
| } |
| |
| /// Returns the longest input slice till it matches the pattern. |
| /// |
| /// It doesn't consume the pattern. It will return `Err(Err::Error((_, ErrorKind::TakeUntil)))` |
| /// if the pattern wasn't met |
| /// |
| /// # Example |
| /// ```rust |
| /// # #[macro_use] extern crate nom; |
| /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
| /// use nom::bytes::complete::take_until; |
| /// |
| /// fn until_eof(s: &str) -> IResult<&str, &str> { |
| /// take_until("eof")(s) |
| /// } |
| /// |
| /// assert_eq!(until_eof("hello, worldeof"), Ok(("eof", "hello, world"))); |
| /// assert_eq!(until_eof("hello, world"), Err(Err::Error(("hello, world", ErrorKind::TakeUntil)))); |
| /// assert_eq!(until_eof(""), Err(Err::Error(("", ErrorKind::TakeUntil)))); |
| /// ``` |
| pub fn take_until<T, Input, Error: ParseError<Input>>(tag: T) -> impl Fn(Input) -> IResult<Input, Input, Error> |
| where |
| Input: InputTake + FindSubstring<T>, |
| T: InputLength + Clone, |
| { |
| move |i: Input| { |
| let t = tag.clone(); |
| let res: IResult<_, _, Error> = match i.find_substring(t) { |
| None => Err(Err::Error(Error::from_error_kind(i, ErrorKind::TakeUntil))), |
| Some(index) => Ok(i.take_split(index)), |
| }; |
| res |
| } |
| } |
| |
| /// Matches a byte string with escaped characters. |
| /// |
| /// * The first argument matches the normal characters (it must not accept the control character), |
| /// * the second argument is the control character (like `\` in most languages), |
| /// * the third argument matches the escaped characters |
| /// |
| /// # Example |
| /// ``` |
| /// # #[macro_use] extern crate nom; |
| /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
| /// # use nom::character::complete::digit1; |
| /// use nom::bytes::complete::escaped; |
| /// use nom::character::complete::one_of; |
| /// |
| /// fn esc(s: &str) -> IResult<&str, &str> { |
| /// escaped(digit1, '\\', one_of(r#""n\"#))(s) |
| /// } |
| /// |
| /// assert_eq!(esc("123;"), Ok((";", "123"))); |
| /// assert_eq!(esc(r#"12\"34;"#), Ok((";", r#"12\"34"#))); |
| /// ``` |
| /// |
| pub fn escaped<Input, Error, F, G, O1, O2>(normal: F, control_char: char, escapable: G) -> impl Fn(Input) -> IResult<Input, Input, Error> |
| where |
| Input: Clone + crate::traits::Offset + InputLength + InputTake + InputTakeAtPosition + Slice<RangeFrom<usize>> + InputIter, |
| <Input as InputIter>::Item: crate::traits::AsChar, |
| F: Fn(Input) -> IResult<Input, O1, Error>, |
| G: Fn(Input) -> IResult<Input, O2, Error>, |
| Error: ParseError<Input>, |
| { |
| use crate::traits::AsChar; |
| |
| move |input: Input| { |
| let mut i = input.clone(); |
| |
| while i.input_len() > 0 { |
| match normal(i.clone()) { |
| Ok((i2, _)) => { |
| if i2.input_len() == 0 { |
| return Ok((input.slice(input.input_len()..), input)); |
| } else { |
| i = i2; |
| } |
| } |
| Err(Err::Error(_)) => { |
| // unwrap() should be safe here since index < $i.input_len() |
| if i.iter_elements().next().unwrap().as_char() == control_char { |
| let next = control_char.len_utf8(); |
| if next >= i.input_len() { |
| return Err(Err::Error(Error::from_error_kind(input, ErrorKind::Escaped))); |
| } else { |
| match escapable(i.slice(next..)) { |
| Ok((i2, _)) => { |
| if i2.input_len() == 0 { |
| return Ok((input.slice(input.input_len()..), input)); |
| } else { |
| i = i2; |
| } |
| } |
| Err(e) => return Err(e), |
| } |
| } |
| } else { |
| let index = input.offset(&i); |
| if index == 0 { |
| return Err(Err::Error(Error::from_error_kind(input, ErrorKind::Escaped))); |
| } |
| return Ok(input.take_split(index)); |
| } |
| } |
| Err(e) => { |
| return Err(e); |
| } |
| } |
| } |
| |
| Ok((input.slice(input.input_len()..), input)) |
| } |
| } |
| |
| #[doc(hidden)] |
| pub fn escapedc<Input, Error, F, G, O1, O2>(i: Input, normal: F, control_char: char, escapable: G) -> IResult<Input, Input, Error> |
| where |
| Input: Clone + crate::traits::Offset + InputLength + InputTake + InputTakeAtPosition + Slice<RangeFrom<usize>> + InputIter, |
| <Input as InputIter>::Item: crate::traits::AsChar, |
| F: Fn(Input) -> IResult<Input, O1, Error>, |
| G: Fn(Input) -> IResult<Input, O2, Error>, |
| Error: ParseError<Input>, |
| { |
| escaped(normal, control_char, escapable)(i) |
| } |
| |
| /// Matches a byte string with escaped characters. |
| /// |
| /// * The first argument matches the normal characters (it must not match the control character), |
| /// * the second argument is the control character (like `\` in most languages), |
| /// * the third argument matches the escaped characters and transforms them. |
| /// |
| /// As an example, the chain `abc\tdef` could be `abc def` (it also consumes the control character) |
| /// |
| /// ``` |
| /// # #[macro_use] extern crate nom; |
| /// # use nom::{Err, error::ErrorKind, Needed, IResult}; |
| /// # use std::str::from_utf8; |
| /// use nom::bytes::complete::escaped_transform; |
| /// use nom::character::complete::alpha1; |
| /// |
| /// fn parser(input: &str) -> IResult<&str, String> { |
| /// escaped_transform( |
| /// alpha1, |
| /// '\\', |
| /// |i:&str| alt!(i, |
| /// tag!("\\") => { |_| "\\" } |
| /// | tag!("\"") => { |_| "\"" } |
| /// | tag!("n") => { |_| "\n" } |
| /// ) |
| /// )(input) |
| /// } |
| /// |
| /// assert_eq!(parser("ab\\\"cd"), Ok(("", String::from("ab\"cd")))); |
| /// ``` |
| #[cfg(feature = "alloc")] |
| pub fn escaped_transform<Input, Error, F, G, O1, O2, ExtendItem, Output>( |
| normal: F, |
| control_char: char, |
| transform: G, |
| ) -> impl Fn(Input) -> IResult<Input, Output, Error> |
| where |
| Input: Clone + crate::traits::Offset + InputLength + InputTake + InputTakeAtPosition + Slice<RangeFrom<usize>> + InputIter, |
| Input: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>, |
| O1: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>, |
| O2: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>, |
| Output: core::iter::Extend<<Input as crate::traits::ExtendInto>::Item>, |
| Output: core::iter::Extend<<O1 as crate::traits::ExtendInto>::Item>, |
| Output: core::iter::Extend<<O2 as crate::traits::ExtendInto>::Item>, |
| <Input as InputIter>::Item: crate::traits::AsChar, |
| F: Fn(Input) -> IResult<Input, O1, Error>, |
| G: Fn(Input) -> IResult<Input, O2, Error>, |
| Error: ParseError<Input>, |
| { |
| use crate::traits::AsChar; |
| |
| move |input: Input| { |
| let mut index = 0; |
| let mut res = input.new_builder(); |
| |
| let i = input.clone(); |
| |
| while index < i.input_len() { |
| let remainder = i.slice(index..); |
| match normal(remainder.clone()) { |
| Ok((i2, o)) => { |
| o.extend_into(&mut res); |
| if i2.input_len() == 0 { |
| return Ok((i.slice(i.input_len()..), res)); |
| } else { |
| index = input.offset(&i2); |
| } |
| } |
| Err(Err::Error(_)) => { |
| // unwrap() should be safe here since index < $i.input_len() |
| if remainder.iter_elements().next().unwrap().as_char() == control_char { |
| let next = index + control_char.len_utf8(); |
| let input_len = input.input_len(); |
| |
| if next >= input_len { |
| return Err(Err::Error(Error::from_error_kind(remainder, ErrorKind::EscapedTransform))); |
| } else { |
| match transform(i.slice(next..)) { |
| Ok((i2, o)) => { |
| o.extend_into(&mut res); |
| if i2.input_len() == 0 { |
| return Ok((i.slice(i.input_len()..), res)); |
| } else { |
| index = input.offset(&i2); |
| } |
| } |
| Err(e) => return Err(e), |
| } |
| } |
| } else { |
| if index == 0 { |
| return Err(Err::Error(Error::from_error_kind(remainder, ErrorKind::EscapedTransform))); |
| } |
| return Ok((remainder, res)); |
| } |
| } |
| Err(e) => return Err(e), |
| } |
| } |
| Ok((input.slice(index..), res)) |
| } |
| } |
| |
| #[doc(hidden)] |
| #[cfg(feature = "alloc")] |
| pub fn escaped_transformc<Input, Error, F, G, O1, O2, ExtendItem, Output>( |
| i: Input, |
| normal: F, |
| control_char: char, |
| transform: G, |
| ) -> IResult<Input, Output, Error> |
| where |
| Input: Clone + crate::traits::Offset + InputLength + InputTake + InputTakeAtPosition + Slice<RangeFrom<usize>> + InputIter, |
| Input: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>, |
| O1: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>, |
| O2: crate::traits::ExtendInto<Item = ExtendItem, Extender = Output>, |
| Output: core::iter::Extend<<Input as crate::traits::ExtendInto>::Item>, |
| Output: core::iter::Extend<<O1 as crate::traits::ExtendInto>::Item>, |
| Output: core::iter::Extend<<O2 as crate::traits::ExtendInto>::Item>, |
| <Input as InputIter>::Item: crate::traits::AsChar, |
| F: Fn(Input) -> IResult<Input, O1, Error>, |
| G: Fn(Input) -> IResult<Input, O2, Error>, |
| Error: ParseError<Input>, |
| { |
| escaped_transform(normal, control_char, transform)(i) |
| |
| } |