diff --git a/src/character/complete.rs b/src/character/complete.rs index 5b73c1467..8f4fc419d 100644 --- a/src/character/complete.rs +++ b/src/character/complete.rs @@ -11,7 +11,7 @@ use crate::lib::std::ops::{Range, RangeFrom, RangeTo}; use crate::traits::{ AsChar, FindToken, InputIter, InputLength, InputTake, InputTakeAtPosition, Slice, }; -use crate::traits::{Compare, CompareResult}; +use crate::traits::{Compare, CompareResult, InputSplit}; /// Recognizes one character. /// @@ -308,16 +308,13 @@ where /// ``` pub fn anychar>(input: T) -> IResult where - T: InputIter + InputLength + Slice>, - ::Item: AsChar, + T: InputSplit, + ::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())), - }, + if let Some((first, tail)) = input.split_first() { + Ok((tail, first.as_char())) + } else { + Err(Err::Error(E::from_error_kind(input, ErrorKind::Eof))) } } diff --git a/src/character/streaming.rs b/src/character/streaming.rs index 88aabba35..88c129d66 100644 --- a/src/character/streaming.rs +++ b/src/character/streaming.rs @@ -11,7 +11,7 @@ use crate::lib::std::ops::{Range, RangeFrom, RangeTo}; use crate::traits::{ AsChar, FindToken, InputIter, InputLength, InputTake, InputTakeAtPosition, Slice, }; -use crate::traits::{Compare, CompareResult}; +use crate::traits::{Compare, CompareResult, InputSplit}; /// Recognizes one character. /// @@ -288,16 +288,13 @@ where /// ``` pub fn anychar>(input: T) -> IResult where - T: InputIter + InputLength + Slice>, - ::Item: AsChar, + T: InputSplit, + ::Item: AsChar, { - let mut it = input.iter_indices(); - match it.next() { - None => Err(Err::Incomplete(Needed::new(1))), - Some((_, c)) => match it.next() { - None => Ok((input.slice(input.input_len()..), c.as_char())), - Some((idx, _)) => Ok((input.slice(idx..), c.as_char())), - }, + if let Some((first, tail)) = input.split_first() { + Ok((tail, first.as_char())) + } else { + Err(Err::Incomplete(Needed::new(1))) } } diff --git a/src/traits.rs b/src/traits/mod.rs similarity index 99% rename from src/traits.rs rename to src/traits/mod.rs index 3c3053e89..123d74202 100644 --- a/src/traits.rs +++ b/src/traits/mod.rs @@ -1,4 +1,9 @@ //! Traits input types have to implement to work with nom combinators + +mod split_first; + +pub use split_first::InputSplit; + use crate::error::{ErrorKind, ParseError}; use crate::internal::{Err, IResult, Needed}; use crate::lib::std::iter::{Copied, Enumerate}; @@ -369,7 +374,7 @@ impl<'a> InputTake for &'a [u8] { } #[inline] fn take_split(&self, count: usize) -> (Self, Self) { - let (prefix, suffix) = self.split_at(count); + let (prefix, suffix) = <[u8]>::split_at(self, count); (suffix, prefix) } } @@ -422,7 +427,7 @@ impl<'a> InputTake for &'a str { // return byte index #[inline] fn take_split(&self, count: usize) -> (Self, Self) { - let (prefix, suffix) = self.split_at(count); + let (prefix, suffix) = str::split_at(self, count); (suffix, prefix) } } diff --git a/src/traits/split_first.rs b/src/traits/split_first.rs new file mode 100755 index 000000000..6bde3425b --- /dev/null +++ b/src/traits/split_first.rs @@ -0,0 +1,70 @@ +use crate::Needed; + +/// Abstracts split_first +pub trait InputSplit: Sized { + /// The current input type is a sequence of that `Item` type. + /// + /// Example: `u8` for `&[u8]` or `char` for `&str` + type Item; + + /// Divides one input into two at an index. + /// + /// Return the head first then the tail `Ok((head, tail))` + fn split_at(&self, mid: usize) -> Result<(Self, Self), Needed>; + + /// Returns the first and all the rest of the elements of the slice, or None if it is empty. + fn split_first(&self) -> Option<(Self::Item, Self)>; + + /// Returns the last and all the rest of the elements of the slice, or None if it is empty. + fn split_last(&self) -> Option<(Self::Item, Self)>; +} + +impl<'a> InputSplit for &'a str { + type Item = char; + + fn split_at(&self, mid: usize) -> Result<(Self, Self), Needed> { + if mid <= self.len() { + Ok(str::split_at(self, mid)) + } else { + Err(Needed::new(mid - self.len())) + } + } + + fn split_first(&self) -> Option<(Self::Item, Self)> { + let mut chars = self.chars(); + chars.next().map(|c| (c, chars.as_str())) + } + + fn split_last(&self) -> Option<(Self::Item, Self)> { + let mut chars = self.chars(); + chars.next_back().map(|c| (c, chars.as_str())) + } +} + +impl<'a> InputSplit for &'a [u8] { + type Item = u8; + + fn split_at(&self, mid: usize) -> Result<(Self, Self), Needed> { + if mid <= self.len() { + Ok(<[u8]>::split_at(self, mid)) + } else { + Err(Needed::new(mid - self.len())) + } + } + + fn split_first(&self) -> Option<(Self::Item, Self)> { + if let [first, tail @ ..] = *self { + Some((*first, tail)) + } else { + None + } + } + + fn split_last(&self) -> Option<(Self::Item, Self)> { + if let [last, tail @ ..] = *self { + Some((*last, tail)) + } else { + None + } + } +}