Skip to content

Commit

Permalink
Merge 5a75405 into 02433c2
Browse files Browse the repository at this point in the history
  • Loading branch information
Stargateur committed Oct 30, 2021
2 parents 02433c2 + 5a75405 commit 9f0994a
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 22 deletions.
17 changes: 7 additions & 10 deletions src/character/complete.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -308,16 +308,13 @@ where
/// ```
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,
T: InputSplit,
<T as 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)))
}
}

Expand Down
17 changes: 7 additions & 10 deletions src/character/streaming.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down Expand Up @@ -288,16 +288,13 @@ where
/// ```
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,
T: InputSplit,
<T as 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)))
}
}

Expand Down
9 changes: 7 additions & 2 deletions src/traits.rs → src/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand Down Expand Up @@ -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)
}
}
Expand Down Expand Up @@ -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)
}
}
Expand Down
70 changes: 70 additions & 0 deletions src/traits/split_first.rs
Original file line number Diff line number Diff line change
@@ -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
}
}
}

0 comments on commit 9f0994a

Please sign in to comment.