summaryrefslogtreecommitdiffstats
path: root/third_party/rust/nom/src/character/complete.rs
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /third_party/rust/nom/src/character/complete.rs
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'third_party/rust/nom/src/character/complete.rs')
-rw-r--r--third_party/rust/nom/src/character/complete.rs1227
1 files changed, 1227 insertions, 0 deletions
diff --git a/third_party/rust/nom/src/character/complete.rs b/third_party/rust/nom/src/character/complete.rs
new file mode 100644
index 0000000000..7cb760a683
--- /dev/null
+++ b/third_party/rust/nom/src/character/complete.rs
@@ -0,0 +1,1227 @@
+//! Character specific parsers and combinators, complete input version.
+//!
+//! Functions recognizing specific characters.
+
+use crate::branch::alt;
+use crate::combinator::opt;
+use crate::error::ErrorKind;
+use crate::error::ParseError;
+use crate::internal::{Err, IResult};
+use crate::lib::std::ops::{Range, RangeFrom, RangeTo};
+use crate::traits::{
+ AsChar, FindToken, InputIter, InputLength, InputTake, InputTakeAtPosition, Slice,
+};
+use crate::traits::{Compare, CompareResult};
+
+/// Recognizes one character.
+///
+/// *Complete version*: Will return an error if there's not enough input data.
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{ErrorKind, Error}, IResult};
+/// # use nom::character::complete::char;
+/// fn parser(i: &str) -> IResult<&str, char> {
+/// char('a')(i)
+/// }
+/// assert_eq!(parser("abc"), Ok(("bc", 'a')));
+/// assert_eq!(parser(" abc"), Err(Err::Error(Error::new(" abc", ErrorKind::Char))));
+/// assert_eq!(parser("bc"), Err(Err::Error(Error::new("bc", ErrorKind::Char))));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Char))));
+/// ```
+pub fn char<I, Error: ParseError<I>>(c: char) -> impl Fn(I) -> IResult<I, char, Error>
+where
+ I: Slice<RangeFrom<usize>> + InputIter,
+ <I as InputIter>::Item: AsChar,
+{
+ move |i: I| match (i).iter_elements().next().map(|t| {
+ let b = t.as_char() == c;
+ (&c, b)
+ }) {
+ Some((c, true)) => Ok((i.slice(c.len()..), c.as_char())),
+ _ => Err(Err::Error(Error::from_char(i, c))),
+ }
+}
+
+/// Recognizes one character and checks that it satisfies a predicate
+///
+/// *Complete version*: Will return an error if there's not enough input data.
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{ErrorKind, Error}, Needed, IResult};
+/// # use nom::character::complete::satisfy;
+/// fn parser(i: &str) -> IResult<&str, char> {
+/// satisfy(|c| c == 'a' || c == 'b')(i)
+/// }
+/// assert_eq!(parser("abc"), Ok(("bc", 'a')));
+/// assert_eq!(parser("cd"), Err(Err::Error(Error::new("cd", ErrorKind::Satisfy))));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Satisfy))));
+/// ```
+pub fn satisfy<F, I, Error: ParseError<I>>(cond: F) -> impl Fn(I) -> IResult<I, char, Error>
+where
+ I: Slice<RangeFrom<usize>> + InputIter,
+ <I as InputIter>::Item: AsChar,
+ F: Fn(char) -> bool,
+{
+ move |i: I| match (i).iter_elements().next().map(|t| {
+ let c = t.as_char();
+ let b = cond(c);
+ (c, b)
+ }) {
+ Some((c, true)) => Ok((i.slice(c.len()..), c)),
+ _ => Err(Err::Error(Error::from_error_kind(i, ErrorKind::Satisfy))),
+ }
+}
+
+/// Recognizes one of the provided characters.
+///
+/// *Complete version*: Will return an error if there's not enough input data.
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::ErrorKind};
+/// # use nom::character::complete::one_of;
+/// assert_eq!(one_of::<_, _, (&str, ErrorKind)>("abc")("b"), Ok(("", 'b')));
+/// assert_eq!(one_of::<_, _, (&str, ErrorKind)>("a")("bc"), Err(Err::Error(("bc", ErrorKind::OneOf))));
+/// assert_eq!(one_of::<_, _, (&str, ErrorKind)>("a")(""), Err(Err::Error(("", ErrorKind::OneOf))));
+/// ```
+pub fn one_of<I, T, Error: ParseError<I>>(list: T) -> impl Fn(I) -> IResult<I, char, Error>
+where
+ I: Slice<RangeFrom<usize>> + InputIter,
+ <I as InputIter>::Item: AsChar + Copy,
+ T: FindToken<<I as InputIter>::Item>,
+{
+ move |i: I| match (i).iter_elements().next().map(|c| (c, list.find_token(c))) {
+ Some((c, true)) => Ok((i.slice(c.len()..), c.as_char())),
+ _ => Err(Err::Error(Error::from_error_kind(i, ErrorKind::OneOf))),
+ }
+}
+
+/// Recognizes a character that is not in the provided characters.
+///
+/// *Complete version*: Will return an error if there's not enough input data.
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::ErrorKind};
+/// # use nom::character::complete::none_of;
+/// assert_eq!(none_of::<_, _, (&str, ErrorKind)>("abc")("z"), Ok(("", 'z')));
+/// assert_eq!(none_of::<_, _, (&str, ErrorKind)>("ab")("a"), Err(Err::Error(("a", ErrorKind::NoneOf))));
+/// assert_eq!(none_of::<_, _, (&str, ErrorKind)>("a")(""), Err(Err::Error(("", ErrorKind::NoneOf))));
+/// ```
+pub fn none_of<I, T, Error: ParseError<I>>(list: T) -> impl Fn(I) -> IResult<I, char, Error>
+where
+ I: Slice<RangeFrom<usize>> + InputIter,
+ <I as InputIter>::Item: AsChar + Copy,
+ T: FindToken<<I as InputIter>::Item>,
+{
+ move |i: I| match (i).iter_elements().next().map(|c| (c, !list.find_token(c))) {
+ Some((c, true)) => Ok((i.slice(c.len()..), c.as_char())),
+ _ => Err(Err::Error(Error::from_error_kind(i, ErrorKind::NoneOf))),
+ }
+}
+
+/// Recognizes the string "\r\n".
+///
+/// *Complete version*: Will return an error if there's not enough input data.
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{Error, ErrorKind}, IResult};
+/// # use nom::character::complete::crlf;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// crlf(input)
+/// }
+///
+/// assert_eq!(parser("\r\nc"), Ok(("c", "\r\n")));
+/// assert_eq!(parser("ab\r\nc"), Err(Err::Error(Error::new("ab\r\nc", ErrorKind::CrLf))));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::CrLf))));
+/// ```
+pub fn crlf<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: Slice<Range<usize>> + Slice<RangeFrom<usize>>,
+ T: InputIter,
+ T: Compare<&'static str>,
+{
+ match input.compare("\r\n") {
+ //FIXME: is this the right index?
+ CompareResult::Ok => Ok((input.slice(2..), input.slice(0..2))),
+ _ => {
+ let e: ErrorKind = ErrorKind::CrLf;
+ Err(Err::Error(E::from_error_kind(input, e)))
+ }
+ }
+}
+
+//FIXME: there's still an incomplete
+/// Recognizes a string of any char except '\r\n' or '\n'.
+///
+/// *Complete version*: Will return an error if there's not enough input data.
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{Error, ErrorKind}, IResult, Needed};
+/// # use nom::character::complete::not_line_ending;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// not_line_ending(input)
+/// }
+///
+/// assert_eq!(parser("ab\r\nc"), Ok(("\r\nc", "ab")));
+/// assert_eq!(parser("ab\nc"), Ok(("\nc", "ab")));
+/// assert_eq!(parser("abc"), Ok(("", "abc")));
+/// assert_eq!(parser(""), Ok(("", "")));
+/// assert_eq!(parser("a\rb\nc"), Err(Err::Error(Error { input: "a\rb\nc", code: ErrorKind::Tag })));
+/// assert_eq!(parser("a\rbc"), Err(Err::Error(Error { input: "a\rbc", code: ErrorKind::Tag })));
+/// ```
+pub fn not_line_ending<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: Slice<Range<usize>> + Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
+ T: InputIter + InputLength,
+ T: Compare<&'static str>,
+ <T as InputIter>::Item: AsChar,
+ <T as InputIter>::Item: AsChar,
+{
+ match input.position(|item| {
+ let c = item.as_char();
+ c == '\r' || c == '\n'
+ }) {
+ None => Ok((input.slice(input.input_len()..), input)),
+ Some(index) => {
+ let mut it = input.slice(index..).iter_elements();
+ let nth = it.next().unwrap().as_char();
+ if nth == '\r' {
+ let sliced = input.slice(index..);
+ let comp = sliced.compare("\r\n");
+ match comp {
+ //FIXME: calculate the right index
+ CompareResult::Ok => Ok((input.slice(index..), input.slice(..index))),
+ _ => {
+ let e: ErrorKind = ErrorKind::Tag;
+ Err(Err::Error(E::from_error_kind(input, e)))
+ }
+ }
+ } else {
+ Ok((input.slice(index..), input.slice(..index)))
+ }
+ }
+ }
+}
+
+/// Recognizes an end of line (both '\n' and '\r\n').
+///
+/// *Complete version*: Will return an error if there's not enough input data.
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{Error, ErrorKind}, IResult, Needed};
+/// # use nom::character::complete::line_ending;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// line_ending(input)
+/// }
+///
+/// assert_eq!(parser("\r\nc"), Ok(("c", "\r\n")));
+/// assert_eq!(parser("ab\r\nc"), Err(Err::Error(Error::new("ab\r\nc", ErrorKind::CrLf))));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::CrLf))));
+/// ```
+pub fn line_ending<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: Slice<Range<usize>> + Slice<RangeFrom<usize>> + Slice<RangeTo<usize>>,
+ T: InputIter + InputLength,
+ T: Compare<&'static str>,
+{
+ match input.compare("\n") {
+ CompareResult::Ok => Ok((input.slice(1..), input.slice(0..1))),
+ CompareResult::Incomplete => Err(Err::Error(E::from_error_kind(input, ErrorKind::CrLf))),
+ CompareResult::Error => {
+ match input.compare("\r\n") {
+ //FIXME: is this the right index?
+ CompareResult::Ok => Ok((input.slice(2..), input.slice(0..2))),
+ _ => Err(Err::Error(E::from_error_kind(input, ErrorKind::CrLf))),
+ }
+ }
+ }
+}
+
+/// Matches a newline character '\n'.
+///
+/// *Complete version*: Will return an error if there's not enough input data.
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{Error, ErrorKind}, IResult, Needed};
+/// # use nom::character::complete::newline;
+/// fn parser(input: &str) -> IResult<&str, char> {
+/// newline(input)
+/// }
+///
+/// assert_eq!(parser("\nc"), Ok(("c", '\n')));
+/// assert_eq!(parser("\r\nc"), Err(Err::Error(Error::new("\r\nc", ErrorKind::Char))));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Char))));
+/// ```
+pub fn newline<I, Error: ParseError<I>>(input: I) -> IResult<I, char, Error>
+where
+ I: Slice<RangeFrom<usize>> + InputIter,
+ <I as InputIter>::Item: AsChar,
+{
+ char('\n')(input)
+}
+
+/// Matches a tab character '\t'.
+///
+/// *Complete version*: Will return an error if there's not enough input data.
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{Error, ErrorKind}, IResult, Needed};
+/// # use nom::character::complete::tab;
+/// fn parser(input: &str) -> IResult<&str, char> {
+/// tab(input)
+/// }
+///
+/// assert_eq!(parser("\tc"), Ok(("c", '\t')));
+/// assert_eq!(parser("\r\nc"), Err(Err::Error(Error::new("\r\nc", ErrorKind::Char))));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Char))));
+/// ```
+pub fn tab<I, Error: ParseError<I>>(input: I) -> IResult<I, char, Error>
+where
+ I: Slice<RangeFrom<usize>> + InputIter,
+ <I as InputIter>::Item: AsChar,
+{
+ char('\t')(input)
+}
+
+/// Matches one byte as a character. Note that the input type will
+/// accept a `str`, but not a `&[u8]`, unlike many other nom parsers.
+///
+/// *Complete version*: Will return an error if there's not enough input data.
+/// # Example
+///
+/// ```
+/// # use nom::{character::complete::anychar, Err, error::{Error, ErrorKind}, IResult};
+/// fn parser(input: &str) -> IResult<&str, char> {
+/// anychar(input)
+/// }
+///
+/// assert_eq!(parser("abc"), Ok(("bc",'a')));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Eof))));
+/// ```
+pub fn anychar<T, E: ParseError<T>>(input: T) -> IResult<T, char, E>
+where
+ T: InputIter + InputLength + Slice<RangeFrom<usize>>,
+ <T as InputIter>::Item: AsChar,
+{
+ let mut it = input.iter_indices();
+ match it.next() {
+ None => Err(Err::Error(E::from_error_kind(input, ErrorKind::Eof))),
+ Some((_, c)) => match it.next() {
+ None => Ok((input.slice(input.input_len()..), c.as_char())),
+ Some((idx, _)) => Ok((input.slice(idx..), c.as_char())),
+ },
+ }
+}
+
+/// Recognizes zero or more lowercase and uppercase ASCII alphabetic characters: a-z, A-Z
+///
+/// *Complete version*: Will return the whole input if no terminating token is found (a non
+/// alphabetic character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::ErrorKind, IResult, Needed};
+/// # use nom::character::complete::alpha0;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// alpha0(input)
+/// }
+///
+/// assert_eq!(parser("ab1c"), Ok(("1c", "ab")));
+/// assert_eq!(parser("1c"), Ok(("1c", "")));
+/// assert_eq!(parser(""), Ok(("", "")));
+/// ```
+pub fn alpha0<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar,
+{
+ input.split_at_position_complete(|item| !item.is_alpha())
+}
+
+/// Recognizes one or more lowercase and uppercase ASCII alphabetic characters: a-z, A-Z
+///
+/// *Complete version*: Will return an error if there's not enough input data,
+/// or the whole input if no terminating token is found (a non alphabetic character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{Error, ErrorKind}, IResult, Needed};
+/// # use nom::character::complete::alpha1;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// alpha1(input)
+/// }
+///
+/// assert_eq!(parser("aB1c"), Ok(("1c", "aB")));
+/// assert_eq!(parser("1c"), Err(Err::Error(Error::new("1c", ErrorKind::Alpha))));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Alpha))));
+/// ```
+pub fn alpha1<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar,
+{
+ input.split_at_position1_complete(|item| !item.is_alpha(), ErrorKind::Alpha)
+}
+
+/// Recognizes zero or more ASCII numerical characters: 0-9
+///
+/// *Complete version*: Will return an error if there's not enough input data,
+/// or the whole input if no terminating token is found (a non digit character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::ErrorKind, IResult, Needed};
+/// # use nom::character::complete::digit0;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// digit0(input)
+/// }
+///
+/// assert_eq!(parser("21c"), Ok(("c", "21")));
+/// assert_eq!(parser("21"), Ok(("", "21")));
+/// assert_eq!(parser("a21c"), Ok(("a21c", "")));
+/// assert_eq!(parser(""), Ok(("", "")));
+/// ```
+pub fn digit0<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar,
+{
+ input.split_at_position_complete(|item| !item.is_dec_digit())
+}
+
+/// Recognizes one or more ASCII numerical characters: 0-9
+///
+/// *Complete version*: Will return an error if there's not enough input data,
+/// or the whole input if no terminating token is found (a non digit character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{Error, ErrorKind}, IResult, Needed};
+/// # use nom::character::complete::digit1;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// digit1(input)
+/// }
+///
+/// assert_eq!(parser("21c"), Ok(("c", "21")));
+/// assert_eq!(parser("c1"), Err(Err::Error(Error::new("c1", ErrorKind::Digit))));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Digit))));
+/// ```
+///
+/// ## Parsing an integer
+/// You can use `digit1` in combination with [`map_res`] to parse an integer:
+///
+/// ```
+/// # use nom::{Err, error::{Error, ErrorKind}, IResult, Needed};
+/// # use nom::combinator::map_res;
+/// # use nom::character::complete::digit1;
+/// fn parser(input: &str) -> IResult<&str, u32> {
+/// map_res(digit1, str::parse)(input)
+/// }
+///
+/// assert_eq!(parser("416"), Ok(("", 416)));
+/// assert_eq!(parser("12b"), Ok(("b", 12)));
+/// assert!(parser("b").is_err());
+/// ```
+///
+/// [`map_res`]: crate::combinator::map_res
+pub fn digit1<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar,
+{
+ input.split_at_position1_complete(|item| !item.is_dec_digit(), ErrorKind::Digit)
+}
+
+/// Recognizes zero or more ASCII hexadecimal numerical characters: 0-9, A-F, a-f
+///
+/// *Complete version*: Will return the whole input if no terminating token is found (a non hexadecimal digit character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::ErrorKind, IResult, Needed};
+/// # use nom::character::complete::hex_digit0;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// hex_digit0(input)
+/// }
+///
+/// assert_eq!(parser("21cZ"), Ok(("Z", "21c")));
+/// assert_eq!(parser("Z21c"), Ok(("Z21c", "")));
+/// assert_eq!(parser(""), Ok(("", "")));
+/// ```
+pub fn hex_digit0<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar,
+{
+ input.split_at_position_complete(|item| !item.is_hex_digit())
+}
+/// Recognizes one or more ASCII hexadecimal numerical characters: 0-9, A-F, a-f
+///
+/// *Complete version*: Will return an error if there's not enough input data,
+/// or the whole input if no terminating token is found (a non hexadecimal digit character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{Error, ErrorKind}, IResult, Needed};
+/// # use nom::character::complete::hex_digit1;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// hex_digit1(input)
+/// }
+///
+/// assert_eq!(parser("21cZ"), Ok(("Z", "21c")));
+/// assert_eq!(parser("H2"), Err(Err::Error(Error::new("H2", ErrorKind::HexDigit))));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::HexDigit))));
+/// ```
+pub fn hex_digit1<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar,
+{
+ input.split_at_position1_complete(|item| !item.is_hex_digit(), ErrorKind::HexDigit)
+}
+
+/// Recognizes zero or more octal characters: 0-7
+///
+/// *Complete version*: Will return the whole input if no terminating token is found (a non octal
+/// digit character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::ErrorKind, IResult, Needed};
+/// # use nom::character::complete::oct_digit0;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// oct_digit0(input)
+/// }
+///
+/// assert_eq!(parser("21cZ"), Ok(("cZ", "21")));
+/// assert_eq!(parser("Z21c"), Ok(("Z21c", "")));
+/// assert_eq!(parser(""), Ok(("", "")));
+/// ```
+pub fn oct_digit0<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar,
+{
+ input.split_at_position_complete(|item| !item.is_oct_digit())
+}
+
+/// Recognizes one or more octal characters: 0-7
+///
+/// *Complete version*: Will return an error if there's not enough input data,
+/// or the whole input if no terminating token is found (a non octal digit character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{Error, ErrorKind}, IResult, Needed};
+/// # use nom::character::complete::oct_digit1;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// oct_digit1(input)
+/// }
+///
+/// assert_eq!(parser("21cZ"), Ok(("cZ", "21")));
+/// assert_eq!(parser("H2"), Err(Err::Error(Error::new("H2", ErrorKind::OctDigit))));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::OctDigit))));
+/// ```
+pub fn oct_digit1<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar,
+{
+ input.split_at_position1_complete(|item| !item.is_oct_digit(), ErrorKind::OctDigit)
+}
+
+/// Recognizes zero or more ASCII numerical and alphabetic characters: 0-9, a-z, A-Z
+///
+/// *Complete version*: Will return the whole input if no terminating token is found (a non
+/// alphanumerical character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::ErrorKind, IResult, Needed};
+/// # use nom::character::complete::alphanumeric0;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// alphanumeric0(input)
+/// }
+///
+/// assert_eq!(parser("21cZ%1"), Ok(("%1", "21cZ")));
+/// assert_eq!(parser("&Z21c"), Ok(("&Z21c", "")));
+/// assert_eq!(parser(""), Ok(("", "")));
+/// ```
+pub fn alphanumeric0<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar,
+{
+ input.split_at_position_complete(|item| !item.is_alphanum())
+}
+
+/// Recognizes one or more ASCII numerical and alphabetic characters: 0-9, a-z, A-Z
+///
+/// *Complete version*: Will return an error if there's not enough input data,
+/// or the whole input if no terminating token is found (a non alphanumerical character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{Error, ErrorKind}, IResult, Needed};
+/// # use nom::character::complete::alphanumeric1;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// alphanumeric1(input)
+/// }
+///
+/// assert_eq!(parser("21cZ%1"), Ok(("%1", "21cZ")));
+/// assert_eq!(parser("&H2"), Err(Err::Error(Error::new("&H2", ErrorKind::AlphaNumeric))));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::AlphaNumeric))));
+/// ```
+pub fn alphanumeric1<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar,
+{
+ input.split_at_position1_complete(|item| !item.is_alphanum(), ErrorKind::AlphaNumeric)
+}
+
+/// Recognizes zero or more spaces and tabs.
+///
+/// *Complete version*: Will return the whole input if no terminating token is found (a non space
+/// character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::ErrorKind, IResult, Needed};
+/// # use nom::character::complete::space0;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// space0(input)
+/// }
+///
+/// assert_eq!(parser(" \t21c"), Ok(("21c", " \t")));
+/// assert_eq!(parser("Z21c"), Ok(("Z21c", "")));
+/// assert_eq!(parser(""), Ok(("", "")));
+/// ```
+pub fn space0<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar + Clone,
+{
+ input.split_at_position_complete(|item| {
+ let c = item.as_char();
+ !(c == ' ' || c == '\t')
+ })
+}
+
+/// Recognizes one or more spaces and tabs.
+///
+/// *Complete version*: Will return an error if there's not enough input data,
+/// or the whole input if no terminating token is found (a non space character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{Error, ErrorKind}, IResult, Needed};
+/// # use nom::character::complete::space1;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// space1(input)
+/// }
+///
+/// assert_eq!(parser(" \t21c"), Ok(("21c", " \t")));
+/// assert_eq!(parser("H2"), Err(Err::Error(Error::new("H2", ErrorKind::Space))));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::Space))));
+/// ```
+pub fn space1<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar + Clone,
+{
+ input.split_at_position1_complete(
+ |item| {
+ let c = item.as_char();
+ !(c == ' ' || c == '\t')
+ },
+ ErrorKind::Space,
+ )
+}
+
+/// Recognizes zero or more spaces, tabs, carriage returns and line feeds.
+///
+/// *Complete version*: will return the whole input if no terminating token is found (a non space
+/// character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::ErrorKind, IResult, Needed};
+/// # use nom::character::complete::multispace0;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// multispace0(input)
+/// }
+///
+/// assert_eq!(parser(" \t\n\r21c"), Ok(("21c", " \t\n\r")));
+/// assert_eq!(parser("Z21c"), Ok(("Z21c", "")));
+/// assert_eq!(parser(""), Ok(("", "")));
+/// ```
+pub fn multispace0<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar + Clone,
+{
+ input.split_at_position_complete(|item| {
+ let c = item.as_char();
+ !(c == ' ' || c == '\t' || c == '\r' || c == '\n')
+ })
+}
+
+/// Recognizes one or more spaces, tabs, carriage returns and line feeds.
+///
+/// *Complete version*: will return an error if there's not enough input data,
+/// or the whole input if no terminating token is found (a non space character).
+/// # Example
+///
+/// ```
+/// # use nom::{Err, error::{Error, ErrorKind}, IResult, Needed};
+/// # use nom::character::complete::multispace1;
+/// fn parser(input: &str) -> IResult<&str, &str> {
+/// multispace1(input)
+/// }
+///
+/// assert_eq!(parser(" \t\n\r21c"), Ok(("21c", " \t\n\r")));
+/// assert_eq!(parser("H2"), Err(Err::Error(Error::new("H2", ErrorKind::MultiSpace))));
+/// assert_eq!(parser(""), Err(Err::Error(Error::new("", ErrorKind::MultiSpace))));
+/// ```
+pub fn multispace1<T, E: ParseError<T>>(input: T) -> IResult<T, T, E>
+where
+ T: InputTakeAtPosition,
+ <T as InputTakeAtPosition>::Item: AsChar + Clone,
+{
+ input.split_at_position1_complete(
+ |item| {
+ let c = item.as_char();
+ !(c == ' ' || c == '\t' || c == '\r' || c == '\n')
+ },
+ ErrorKind::MultiSpace,
+ )
+}
+
+pub(crate) fn sign<T, E: ParseError<T>>(input: T) -> IResult<T, bool, E>
+where
+ T: Clone + InputTake,
+ T: for<'a> Compare<&'a [u8]>,
+{
+ use crate::bytes::complete::tag;
+ use crate::combinator::value;
+
+ let (i, opt_sign) = opt(alt((
+ value(false, tag(&b"-"[..])),
+ value(true, tag(&b"+"[..])),
+ )))(input)?;
+ let sign = opt_sign.unwrap_or(true);
+
+ Ok((i, sign))
+}
+
+#[doc(hidden)]
+macro_rules! ints {
+ ($($t:tt)+) => {
+ $(
+ /// will parse a number in text form to a number
+ ///
+ /// *Complete version*: can parse until the end of input.
+ pub fn $t<T, E: ParseError<T>>(input: T) -> IResult<T, $t, E>
+ where
+ T: InputIter + Slice<RangeFrom<usize>> + InputLength + InputTake + Clone,
+ <T as InputIter>::Item: AsChar,
+ T: for <'a> Compare<&'a[u8]>,
+ {
+ let (i, sign) = sign(input.clone())?;
+
+ if i.input_len() == 0 {
+ return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit)));
+ }
+
+ let mut value: $t = 0;
+ if sign {
+ for (pos, c) in i.iter_indices() {
+ match c.as_char().to_digit(10) {
+ None => {
+ if pos == 0 {
+ return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit)));
+ } else {
+ return Ok((i.slice(pos..), value));
+ }
+ },
+ Some(d) => match value.checked_mul(10).and_then(|v| v.checked_add(d as $t)) {
+ None => return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit))),
+ Some(v) => value = v,
+ }
+ }
+ }
+ } else {
+ for (pos, c) in i.iter_indices() {
+ match c.as_char().to_digit(10) {
+ None => {
+ if pos == 0 {
+ return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit)));
+ } else {
+ return Ok((i.slice(pos..), value));
+ }
+ },
+ Some(d) => match value.checked_mul(10).and_then(|v| v.checked_sub(d as $t)) {
+ None => return Err(Err::Error(E::from_error_kind(input, ErrorKind::Digit))),
+ Some(v) => value = v,
+ }
+ }
+ }
+ }
+
+ Ok((i.slice(i.input_len()..), value))
+ }
+ )+
+ }
+}
+
+ints! { i8 i16 i32 i64 i128 }
+
+#[doc(hidden)]
+macro_rules! uints {
+ ($($t:tt)+) => {
+ $(
+ /// will parse a number in text form to a number
+ ///
+ /// *Complete version*: can parse until the end of input.
+ pub fn $t<T, E: ParseError<T>>(input: T) -> IResult<T, $t, E>
+ where
+ T: InputIter + Slice<RangeFrom<usize>> + InputLength,
+ <T as InputIter>::Item: AsChar,
+ {
+ let i = input;
+
+ if i.input_len() == 0 {
+ return Err(Err::Error(E::from_error_kind(i, ErrorKind::Digit)));
+ }
+
+ let mut value: $t = 0;
+ for (pos, c) in i.iter_indices() {
+ match c.as_char().to_digit(10) {
+ None => {
+ if pos == 0 {
+ return Err(Err::Error(E::from_error_kind(i, ErrorKind::Digit)));
+ } else {
+ return Ok((i.slice(pos..), value));
+ }
+ },
+ Some(d) => match value.checked_mul(10).and_then(|v| v.checked_add(d as $t)) {
+ None => return Err(Err::Error(E::from_error_kind(i, ErrorKind::Digit))),
+ Some(v) => value = v,
+ }
+ }
+ }
+
+ Ok((i.slice(i.input_len()..), value))
+ }
+ )+
+ }
+}
+
+uints! { u8 u16 u32 u64 u128 }
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+ use crate::internal::Err;
+ use crate::traits::ParseTo;
+ use proptest::prelude::*;
+
+ macro_rules! assert_parse(
+ ($left: expr, $right: expr) => {
+ let res: $crate::IResult<_, _, (_, ErrorKind)> = $left;
+ assert_eq!(res, $right);
+ };
+ );
+
+ #[test]
+ fn character() {
+ let empty: &[u8] = b"";
+ let a: &[u8] = b"abcd";
+ let b: &[u8] = b"1234";
+ let c: &[u8] = b"a123";
+ let d: &[u8] = "azé12".as_bytes();
+ let e: &[u8] = b" ";
+ let f: &[u8] = b" ;";
+ //assert_eq!(alpha1::<_, (_, ErrorKind)>(a), Err(Err::Incomplete(Needed::Size(1))));
+ assert_parse!(alpha1(a), Ok((empty, a)));
+ assert_eq!(alpha1(b), Err(Err::Error((b, ErrorKind::Alpha))));
+ assert_eq!(alpha1::<_, (_, ErrorKind)>(c), Ok((&c[1..], &b"a"[..])));
+ assert_eq!(
+ alpha1::<_, (_, ErrorKind)>(d),
+ Ok(("é12".as_bytes(), &b"az"[..]))
+ );
+ assert_eq!(digit1(a), Err(Err::Error((a, ErrorKind::Digit))));
+ assert_eq!(digit1::<_, (_, ErrorKind)>(b), Ok((empty, b)));
+ assert_eq!(digit1(c), Err(Err::Error((c, ErrorKind::Digit))));
+ assert_eq!(digit1(d), Err(Err::Error((d, ErrorKind::Digit))));
+ assert_eq!(hex_digit1::<_, (_, ErrorKind)>(a), Ok((empty, a)));
+ assert_eq!(hex_digit1::<_, (_, ErrorKind)>(b), Ok((empty, b)));
+ assert_eq!(hex_digit1::<_, (_, ErrorKind)>(c), Ok((empty, c)));
+ assert_eq!(
+ hex_digit1::<_, (_, ErrorKind)>(d),
+ Ok(("zé12".as_bytes(), &b"a"[..]))
+ );
+ assert_eq!(hex_digit1(e), Err(Err::Error((e, ErrorKind::HexDigit))));
+ assert_eq!(oct_digit1(a), Err(Err::Error((a, ErrorKind::OctDigit))));
+ assert_eq!(oct_digit1::<_, (_, ErrorKind)>(b), Ok((empty, b)));
+ assert_eq!(oct_digit1(c), Err(Err::Error((c, ErrorKind::OctDigit))));
+ assert_eq!(oct_digit1(d), Err(Err::Error((d, ErrorKind::OctDigit))));
+ assert_eq!(alphanumeric1::<_, (_, ErrorKind)>(a), Ok((empty, a)));
+ //assert_eq!(fix_error!(b,(), alphanumeric), Ok((empty, b)));
+ assert_eq!(alphanumeric1::<_, (_, ErrorKind)>(c), Ok((empty, c)));
+ assert_eq!(
+ alphanumeric1::<_, (_, ErrorKind)>(d),
+ Ok(("é12".as_bytes(), &b"az"[..]))
+ );
+ assert_eq!(space1::<_, (_, ErrorKind)>(e), Ok((empty, e)));
+ assert_eq!(space1::<_, (_, ErrorKind)>(f), Ok((&b";"[..], &b" "[..])));
+ }
+
+ #[cfg(feature = "alloc")]
+ #[test]
+ fn character_s() {
+ let empty = "";
+ let a = "abcd";
+ let b = "1234";
+ let c = "a123";
+ let d = "azé12";
+ let e = " ";
+ assert_eq!(alpha1::<_, (_, ErrorKind)>(a), Ok((empty, a)));
+ assert_eq!(alpha1(b), Err(Err::Error((b, ErrorKind::Alpha))));
+ assert_eq!(alpha1::<_, (_, ErrorKind)>(c), Ok((&c[1..], &"a"[..])));
+ assert_eq!(alpha1::<_, (_, ErrorKind)>(d), Ok(("é12", &"az"[..])));
+ assert_eq!(digit1(a), Err(Err::Error((a, ErrorKind::Digit))));
+ assert_eq!(digit1::<_, (_, ErrorKind)>(b), Ok((empty, b)));
+ assert_eq!(digit1(c), Err(Err::Error((c, ErrorKind::Digit))));
+ assert_eq!(digit1(d), Err(Err::Error((d, ErrorKind::Digit))));
+ assert_eq!(hex_digit1::<_, (_, ErrorKind)>(a), Ok((empty, a)));
+ assert_eq!(hex_digit1::<_, (_, ErrorKind)>(b), Ok((empty, b)));
+ assert_eq!(hex_digit1::<_, (_, ErrorKind)>(c), Ok((empty, c)));
+ assert_eq!(hex_digit1::<_, (_, ErrorKind)>(d), Ok(("zé12", &"a"[..])));
+ assert_eq!(hex_digit1(e), Err(Err::Error((e, ErrorKind::HexDigit))));
+ assert_eq!(oct_digit1(a), Err(Err::Error((a, ErrorKind::OctDigit))));
+ assert_eq!(oct_digit1::<_, (_, ErrorKind)>(b), Ok((empty, b)));
+ assert_eq!(oct_digit1(c), Err(Err::Error((c, ErrorKind::OctDigit))));
+ assert_eq!(oct_digit1(d), Err(Err::Error((d, ErrorKind::OctDigit))));
+ assert_eq!(alphanumeric1::<_, (_, ErrorKind)>(a), Ok((empty, a)));
+ //assert_eq!(fix_error!(b,(), alphanumeric), Ok((empty, b)));
+ assert_eq!(alphanumeric1::<_, (_, ErrorKind)>(c), Ok((empty, c)));
+ assert_eq!(alphanumeric1::<_, (_, ErrorKind)>(d), Ok(("é12", "az")));
+ assert_eq!(space1::<_, (_, ErrorKind)>(e), Ok((empty, e)));
+ }
+
+ use crate::traits::Offset;
+ #[test]
+ fn offset() {
+ let a = &b"abcd;"[..];
+ let b = &b"1234;"[..];
+ let c = &b"a123;"[..];
+ let d = &b" \t;"[..];
+ let e = &b" \t\r\n;"[..];
+ let f = &b"123abcDEF;"[..];
+
+ match alpha1::<_, (_, ErrorKind)>(a) {
+ Ok((i, _)) => {
+ assert_eq!(a.offset(i) + i.len(), a.len());
+ }
+ _ => panic!("wrong return type in offset test for alpha"),
+ }
+ match digit1::<_, (_, ErrorKind)>(b) {
+ Ok((i, _)) => {
+ assert_eq!(b.offset(i) + i.len(), b.len());
+ }
+ _ => panic!("wrong return type in offset test for digit"),
+ }
+ match alphanumeric1::<_, (_, ErrorKind)>(c) {
+ Ok((i, _)) => {
+ assert_eq!(c.offset(i) + i.len(), c.len());
+ }
+ _ => panic!("wrong return type in offset test for alphanumeric"),
+ }
+ match space1::<_, (_, ErrorKind)>(d) {
+ Ok((i, _)) => {
+ assert_eq!(d.offset(i) + i.len(), d.len());
+ }
+ _ => panic!("wrong return type in offset test for space"),
+ }
+ match multispace1::<_, (_, ErrorKind)>(e) {
+ Ok((i, _)) => {
+ assert_eq!(e.offset(i) + i.len(), e.len());
+ }
+ _ => panic!("wrong return type in offset test for multispace"),
+ }
+ match hex_digit1::<_, (_, ErrorKind)>(f) {
+ Ok((i, _)) => {
+ assert_eq!(f.offset(i) + i.len(), f.len());
+ }
+ _ => panic!("wrong return type in offset test for hex_digit"),
+ }
+ match oct_digit1::<_, (_, ErrorKind)>(f) {
+ Ok((i, _)) => {
+ assert_eq!(f.offset(i) + i.len(), f.len());
+ }
+ _ => panic!("wrong return type in offset test for oct_digit"),
+ }
+ }
+
+ #[test]
+ fn is_not_line_ending_bytes() {
+ let a: &[u8] = b"ab12cd\nefgh";
+ assert_eq!(
+ not_line_ending::<_, (_, ErrorKind)>(a),
+ Ok((&b"\nefgh"[..], &b"ab12cd"[..]))
+ );
+
+ let b: &[u8] = b"ab12cd\nefgh\nijkl";
+ assert_eq!(
+ not_line_ending::<_, (_, ErrorKind)>(b),
+ Ok((&b"\nefgh\nijkl"[..], &b"ab12cd"[..]))
+ );
+
+ let c: &[u8] = b"ab12cd\r\nefgh\nijkl";
+ assert_eq!(
+ not_line_ending::<_, (_, ErrorKind)>(c),
+ Ok((&b"\r\nefgh\nijkl"[..], &b"ab12cd"[..]))
+ );
+
+ let d: &[u8] = b"ab12cd";
+ assert_eq!(
+ not_line_ending::<_, (_, ErrorKind)>(d),
+ Ok((&[][..], &d[..]))
+ );
+ }
+
+ #[test]
+ fn is_not_line_ending_str() {
+ /*
+ let a: &str = "ab12cd\nefgh";
+ assert_eq!(not_line_ending(a), Ok((&"\nefgh"[..], &"ab12cd"[..])));
+
+ let b: &str = "ab12cd\nefgh\nijkl";
+ assert_eq!(not_line_ending(b), Ok((&"\nefgh\nijkl"[..], &"ab12cd"[..])));
+
+ let c: &str = "ab12cd\r\nefgh\nijkl";
+ assert_eq!(not_line_ending(c), Ok((&"\r\nefgh\nijkl"[..], &"ab12cd"[..])));
+
+ let d = "βèƒôřè\nÂßÇáƒƭèř";
+ assert_eq!(not_line_ending(d), Ok((&"\nÂßÇáƒƭèř"[..], &"βèƒôřè"[..])));
+
+ let e = "βèƒôřè\r\nÂßÇáƒƭèř";
+ assert_eq!(not_line_ending(e), Ok((&"\r\nÂßÇáƒƭèř"[..], &"βèƒôřè"[..])));
+ */
+
+ let f = "βèƒôřè\rÂßÇáƒƭèř";
+ assert_eq!(not_line_ending(f), Err(Err::Error((f, ErrorKind::Tag))));
+
+ let g2: &str = "ab12cd";
+ assert_eq!(not_line_ending::<_, (_, ErrorKind)>(g2), Ok(("", g2)));
+ }
+
+ #[test]
+ fn hex_digit_test() {
+ let i = &b"0123456789abcdefABCDEF;"[..];
+ assert_parse!(hex_digit1(i), Ok((&b";"[..], &i[..i.len() - 1])));
+
+ let i = &b"g"[..];
+ assert_parse!(
+ hex_digit1(i),
+ Err(Err::Error(error_position!(i, ErrorKind::HexDigit)))
+ );
+
+ let i = &b"G"[..];
+ assert_parse!(
+ hex_digit1(i),
+ Err(Err::Error(error_position!(i, ErrorKind::HexDigit)))
+ );
+
+ assert!(crate::character::is_hex_digit(b'0'));
+ assert!(crate::character::is_hex_digit(b'9'));
+ assert!(crate::character::is_hex_digit(b'a'));
+ assert!(crate::character::is_hex_digit(b'f'));
+ assert!(crate::character::is_hex_digit(b'A'));
+ assert!(crate::character::is_hex_digit(b'F'));
+ assert!(!crate::character::is_hex_digit(b'g'));
+ assert!(!crate::character::is_hex_digit(b'G'));
+ assert!(!crate::character::is_hex_digit(b'/'));
+ assert!(!crate::character::is_hex_digit(b':'));
+ assert!(!crate::character::is_hex_digit(b'@'));
+ assert!(!crate::character::is_hex_digit(b'\x60'));
+ }
+
+ #[test]
+ fn oct_digit_test() {
+ let i = &b"01234567;"[..];
+ assert_parse!(oct_digit1(i), Ok((&b";"[..], &i[..i.len() - 1])));
+
+ let i = &b"8"[..];
+ assert_parse!(
+ oct_digit1(i),
+ Err(Err::Error(error_position!(i, ErrorKind::OctDigit)))
+ );
+
+ assert!(crate::character::is_oct_digit(b'0'));
+ assert!(crate::character::is_oct_digit(b'7'));
+ assert!(!crate::character::is_oct_digit(b'8'));
+ assert!(!crate::character::is_oct_digit(b'9'));
+ assert!(!crate::character::is_oct_digit(b'a'));
+ assert!(!crate::character::is_oct_digit(b'A'));
+ assert!(!crate::character::is_oct_digit(b'/'));
+ assert!(!crate::character::is_oct_digit(b':'));
+ assert!(!crate::character::is_oct_digit(b'@'));
+ assert!(!crate::character::is_oct_digit(b'\x60'));
+ }
+
+ #[test]
+ fn full_line_windows() {
+ use crate::sequence::pair;
+ fn take_full_line(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> {
+ pair(not_line_ending, line_ending)(i)
+ }
+ let input = b"abc\r\n";
+ let output = take_full_line(input);
+ assert_eq!(output, Ok((&b""[..], (&b"abc"[..], &b"\r\n"[..]))));
+ }
+
+ #[test]
+ fn full_line_unix() {
+ use crate::sequence::pair;
+ fn take_full_line(i: &[u8]) -> IResult<&[u8], (&[u8], &[u8])> {
+ pair(not_line_ending, line_ending)(i)
+ }
+ let input = b"abc\n";
+ let output = take_full_line(input);
+ assert_eq!(output, Ok((&b""[..], (&b"abc"[..], &b"\n"[..]))));
+ }
+
+ #[test]
+ fn check_windows_lineending() {
+ let input = b"\r\n";
+ let output = line_ending(&input[..]);
+ assert_parse!(output, Ok((&b""[..], &b"\r\n"[..])));
+ }
+
+ #[test]
+ fn check_unix_lineending() {
+ let input = b"\n";
+ let output = line_ending(&input[..]);
+ assert_parse!(output, Ok((&b""[..], &b"\n"[..])));
+ }
+
+ #[test]
+ fn cr_lf() {
+ assert_parse!(crlf(&b"\r\na"[..]), Ok((&b"a"[..], &b"\r\n"[..])));
+ assert_parse!(
+ crlf(&b"\r"[..]),
+ Err(Err::Error(error_position!(&b"\r"[..], ErrorKind::CrLf)))
+ );
+ assert_parse!(
+ crlf(&b"\ra"[..]),
+ Err(Err::Error(error_position!(&b"\ra"[..], ErrorKind::CrLf)))
+ );
+
+ assert_parse!(crlf("\r\na"), Ok(("a", "\r\n")));
+ assert_parse!(
+ crlf("\r"),
+ Err(Err::Error(error_position!(&"\r"[..], ErrorKind::CrLf)))
+ );
+ assert_parse!(
+ crlf("\ra"),
+ Err(Err::Error(error_position!("\ra", ErrorKind::CrLf)))
+ );
+ }
+
+ #[test]
+ fn end_of_line() {
+ assert_parse!(line_ending(&b"\na"[..]), Ok((&b"a"[..], &b"\n"[..])));
+ assert_parse!(line_ending(&b"\r\na"[..]), Ok((&b"a"[..], &b"\r\n"[..])));
+ assert_parse!(
+ line_ending(&b"\r"[..]),
+ Err(Err::Error(error_position!(&b"\r"[..], ErrorKind::CrLf)))
+ );
+ assert_parse!(
+ line_ending(&b"\ra"[..]),
+ Err(Err::Error(error_position!(&b"\ra"[..], ErrorKind::CrLf)))
+ );
+
+ assert_parse!(line_ending("\na"), Ok(("a", "\n")));
+ assert_parse!(line_ending("\r\na"), Ok(("a", "\r\n")));
+ assert_parse!(
+ line_ending("\r"),
+ Err(Err::Error(error_position!(&"\r"[..], ErrorKind::CrLf)))
+ );
+ assert_parse!(
+ line_ending("\ra"),
+ Err(Err::Error(error_position!("\ra", ErrorKind::CrLf)))
+ );
+ }
+
+ fn digit_to_i16(input: &str) -> IResult<&str, i16> {
+ let i = input;
+ let (i, opt_sign) = opt(alt((char('+'), char('-'))))(i)?;
+ let sign = match opt_sign {
+ Some('+') => true,
+ Some('-') => false,
+ _ => true,
+ };
+
+ let (i, s) = match digit1::<_, crate::error::Error<_>>(i) {
+ Ok((i, s)) => (i, s),
+ Err(_) => {
+ return Err(Err::Error(crate::error::Error::from_error_kind(
+ input,
+ ErrorKind::Digit,
+ )))
+ }
+ };
+
+ match s.parse_to() {
+ Some(n) => {
+ if sign {
+ Ok((i, n))
+ } else {
+ Ok((i, -n))
+ }
+ }
+ None => Err(Err::Error(crate::error::Error::from_error_kind(
+ i,
+ ErrorKind::Digit,
+ ))),
+ }
+ }
+
+ fn digit_to_u32(i: &str) -> IResult<&str, u32> {
+ let (i, s) = digit1(i)?;
+ match s.parse_to() {
+ Some(n) => Ok((i, n)),
+ None => Err(Err::Error(crate::error::Error::from_error_kind(
+ i,
+ ErrorKind::Digit,
+ ))),
+ }
+ }
+
+ proptest! {
+ #[test]
+ fn ints(s in "\\PC*") {
+ let res1 = digit_to_i16(&s);
+ let res2 = i16(s.as_str());
+ assert_eq!(res1, res2);
+ }
+
+ #[test]
+ fn uints(s in "\\PC*") {
+ let res1 = digit_to_u32(&s);
+ let res2 = u32(s.as_str());
+ assert_eq!(res1, res2);
+ }
+ }
+}