diff --git a/src/bytes/complete.rs b/src/bytes/complete.rs index a5442b53f..e3cc93077 100644 --- a/src/bytes/complete.rs +++ b/src/bytes/complete.rs @@ -6,7 +6,7 @@ use crate::internal::{Err, IResult, Parser}; use crate::lib::std::ops::RangeFrom; use crate::lib::std::result::Result::*; use crate::traits::{ - Compare, CompareResult, FindSubstring, FindToken, InputIter, InputLength, InputTake, + Compare, CompareResult, FindSubstring, FindToken, InputIter, InputLength, InputSkip, InputTake, InputTakeAtPosition, Slice, ToUsize, }; @@ -414,6 +414,37 @@ where } } +/// Skip a slice of N input elements (Input[N..]). +/// +/// It will return `Err(Err::Error((_, ErrorKind::Eof)))` if the input is shorter than the argument. +/// # Example +/// ```rust +/// # use nom::{Err, error::{Error, ErrorKind}, Needed, IResult}; +/// use nom::bytes::complete::skip; +/// +/// fn skip6(s: &str) -> IResult<&str, ()> { +/// skip(6usize)(s) +/// } +/// +/// assert_eq!(skip6("1234567"), Ok(("7", ()))); +/// assert_eq!(skip6("things"), Ok(("", ()))); +/// assert_eq!(skip6("short"), Err(Err::Error(Error::new("short", ErrorKind::Eof)))); +/// assert_eq!(skip6(""), Err(Err::Error(Error::new("", ErrorKind::Eof)))); +/// ``` +pub fn skip>( + count: C, +) -> impl Fn(Input) -> IResult +where + Input: InputIter + InputSkip, + C: ToUsize, +{ + let c = count.to_usize(); + move |i: Input| match i.slice_index(c) { + Err(_needed) => Err(Err::Error(Error::from_error_kind(i, ErrorKind::Eof))), + Ok(index) => Ok((i.skip(index), ())), + } +} + /// Returns the input slice up to the first occurrence of the pattern. /// /// It doesn't consume the pattern. It will return `Err(Err::Error((_, ErrorKind::TakeUntil)))` diff --git a/src/character/complete.rs b/src/character/complete.rs index a98bafbb7..7cb760a68 100644 --- a/src/character/complete.rs +++ b/src/character/complete.rs @@ -414,10 +414,10 @@ where /// 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; @@ -425,12 +425,12 @@ where /// 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>(input: T) -> IResult where diff --git a/src/sequence/tests.rs b/src/sequence/tests.rs index ea662607d..30ad0d678 100644 --- a/src/sequence/tests.rs +++ b/src/sequence/tests.rs @@ -1,6 +1,6 @@ use super::*; use crate::bytes::streaming::{tag, take}; -use crate::error::{ErrorKind, Error}; +use crate::error::{Error, ErrorKind}; use crate::internal::{Err, IResult, Needed}; use crate::number::streaming::be_u16; @@ -275,7 +275,16 @@ fn tuple_test() { #[test] fn unit_type() { - assert_eq!(tuple::<&'static str, (), Error<&'static str>, ()>(())("abxsbsh"), Ok(("abxsbsh", ()))); - assert_eq!(tuple::<&'static str, (), Error<&'static str>, ()>(())("sdfjakdsas"), Ok(("sdfjakdsas", ()))); - assert_eq!(tuple::<&'static str, (), Error<&'static str>, ()>(())(""), Ok(("", ()))); + assert_eq!( + tuple::<&'static str, (), Error<&'static str>, ()>(())("abxsbsh"), + Ok(("abxsbsh", ())) + ); + assert_eq!( + tuple::<&'static str, (), Error<&'static str>, ()>(())("sdfjakdsas"), + Ok(("sdfjakdsas", ())) + ); + assert_eq!( + tuple::<&'static str, (), Error<&'static str>, ()>(())(""), + Ok(("", ())) + ); } diff --git a/src/traits.rs b/src/traits.rs index f6a683cb0..b842c5424 100644 --- a/src/traits.rs +++ b/src/traits.rs @@ -332,6 +332,12 @@ pub trait InputTake: Sized { fn take_split(&self, count: usize) -> (Self, Self); } +/// Abstracts skipping operation +pub trait InputSkip: Sized { + /// Skip a slice of `count` bytes. panics if count > length + fn skip(&self, count: usize) -> Self; +} + impl<'a> InputIter for &'a [u8] { type Item = u8; type Iter = Enumerate; @@ -427,6 +433,20 @@ impl<'a> InputTake for &'a str { } } +impl<'a> InputSkip for &'a [u8] { + #[inline] + fn skip(&self, count: usize) -> Self { + &self[count..] + } +} + +impl<'a> InputSkip for &'a str { + #[inline] + fn skip(&self, count: usize) -> Self { + &self[count..] + } +} + /// Dummy trait used for default implementations (currently only used for `InputTakeAtPosition` and `Compare`). /// /// When implementing a custom input type, it is possible to use directly the