extern crate ascii;
use crate::lib::marker::PhantomData;
use self::ascii::AsciiChar;
use crate::combinator::{satisfy, skip_many, token, Expected, Satisfy, SkipMany, Token};
use crate::error::{Info, ParseError, ParseResult, Tracked};
use crate::parser::item::tokens_cmp;
use crate::parser::range::{take_fn, TakeRange};
use crate::parser::sequence::With;
use crate::stream::{FullRangeStream, RangeStream, Stream, StreamOnce};
use crate::Parser;
use crate::error::ParseResult::*;
#[inline(always)]
pub fn byte<I>(c: u8) -> Token<I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
token(c)
}
impl_token_parser! { Digit(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
macro_rules! byte_parser {
($name:ident, $ty:ident, $f:ident) => {{
let f = static_fn! {
(c, u8) -> bool { AsciiChar::from(c).map(|c| c.$f()).unwrap_or(false) }
};
$ty(satisfy(f).expected(stringify!($name)), PhantomData)
}};
}
#[inline(always)]
pub fn digit<I>() -> Digit<I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
byte_parser!(digit, Digit, is_digit)
}
impl_token_parser! { Space(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
#[inline(always)]
pub fn space<I>() -> Space<I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
byte_parser!(space, Space, is_whitespace)
}
impl_token_parser! { Spaces(), u8, Expected<SkipMany<Space<I>>> }
#[inline(always)]
pub fn spaces<I>() -> Spaces<I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
Spaces(skip_many(space()).expected("whitespaces"), PhantomData)
}
impl_token_parser! { Newline(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
#[inline(always)]
pub fn newline<I>() -> Newline<I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
Newline(
satisfy(static_fn!((ch, u8) -> bool { ch == b'\n' })).expected("lf newline"),
PhantomData,
)
}
impl_token_parser! { CrLf(), u8, Expected<With<Satisfy<I, fn (u8) -> bool>, Newline<I>>> }
#[inline(always)]
pub fn crlf<I>() -> CrLf<I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
CrLf(
satisfy(static_fn!((ch, u8) -> bool { ch == b'\r' }))
.with(newline())
.expected("crlf newline"),
PhantomData,
)
}
impl_token_parser! { Tab(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
#[inline(always)]
pub fn tab<I>() -> Tab<I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
Tab(
satisfy(static_fn!((ch, u8) -> bool { ch == b'\t' })).expected("tab"),
PhantomData,
)
}
impl_token_parser! { Upper(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
#[inline(always)]
pub fn upper<I>() -> Upper<I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
byte_parser!(upper, Upper, is_uppercase)
}
impl_token_parser! { Lower(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
#[inline(always)]
pub fn lower<I>() -> Lower<I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
byte_parser!(lower, Lower, is_lowercase)
}
impl_token_parser! { AlphaNum(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
#[inline(always)]
pub fn alpha_num<I>() -> AlphaNum<I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
byte_parser!(alpha_num, AlphaNum, is_alphanumeric)
}
impl_token_parser! { Letter(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
#[inline(always)]
pub fn letter<I>() -> Letter<I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
byte_parser!(letter, Letter, is_alphabetic)
}
impl_token_parser! { OctDigit(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
#[inline(always)]
pub fn oct_digit<I>() -> OctDigit<I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
OctDigit(
satisfy(static_fn!((ch, u8) -> bool { ch >= b'0' && ch <= b'7' })).expected("octal digit"),
PhantomData,
)
}
impl_token_parser! { HexDigit(), u8, Expected<Satisfy<I, fn (u8) -> bool>> }
#[inline(always)]
pub fn hex_digit<I>() -> HexDigit<I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
byte_parser!(hex_digit, HexDigit, is_hex)
}
#[inline(always)]
pub fn bytes<'a, 'b, I>(s: &'static [u8]) -> impl Parser<Input = I, Output = &'a [u8]>
where
I: Stream<Item = u8, Range = &'b [u8]>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
bytes_cmp(s, |l: u8, r: u8| l == r)
}
#[inline(always)]
pub fn bytes_cmp<'a, 'b, C, I>(
s: &'static [u8],
cmp: C,
) -> impl Parser<Input = I, Output = &'a [u8]>
where
C: FnMut(u8, u8) -> bool,
I: Stream<Item = u8, Range = &'b [u8]>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
tokens_cmp(s.iter().cloned(), cmp)
.map(move |_| s)
.expected(Info::Range(s))
}
macro_rules! take_until {
(
$(#[$attr:meta])*
$type_name: ident, $func_name: ident, $memchr: ident, $($param: ident),+
) => {
parser!{
#[derive(Clone)]
pub struct $type_name;
#[inline(always)]
$(#[$attr])*
pub fn $func_name[I]($($param : u8),*)(I) -> I::Range
where [
I: RangeStream + FullRangeStream,
I::Range: AsRef<[u8]> + crate::stream::Range,
]
{
take_fn(move |haystack: I::Range| {
let haystack = haystack.as_ref();
match ::memchr::$memchr( $(*$param),+ , haystack) {
Some(i) => TakeRange::Found(i),
None => TakeRange::NotFound(haystack.len()),
}
})
}
}
}
}
take_until! {
TakeUntilByte, take_until_byte, memchr, a
}
take_until! {
TakeUntilByte2, take_until_byte2, memchr2, a, b
}
take_until! {
TakeUntilByte3, take_until_byte3, memchr3, a, b, c
}
parser! {
#[inline(always)]
pub fn take_until_bytes['a, I](needle: &'a [u8])(I) -> I::Range
where [
I: RangeStream + FullRangeStream,
I::Range: AsRef<[u8]> + crate::stream::Range,
]
{
take_fn(move |haystack: I::Range| {
let haystack = haystack.as_ref();
match memslice(needle, haystack) {
Some(i) => TakeRange::Found(i),
None => TakeRange::NotFound(haystack.len().saturating_sub(needle.len() - 1)),
}
})
}
}
fn memslice(needle: &[u8], haystack: &[u8]) -> Option<usize> {
let (&prefix, suffix) = match needle.split_first() {
Some(x) => x,
None => return Some(0),
};
let mut iter = ::memchr::memchr_iter(prefix, haystack);
while let Some(i) = iter.next() {
if haystack[i + 1..].starts_with(suffix) {
return Some(i);
}
}
None
}
pub mod num {
use super::*;
use crate::stream::uncons;
use byteorder::{ByteOrder, BE, LE};
use crate::lib::mem::size_of;
macro_rules! integer_parser {
(
$(#[$attr:meta])*
pub $type_name: ident,
$func_name: ident, $be_name: ident, $le_name: ident, $read_name: ident
) => {
#[derive(Clone)]
pub struct $type_name<B, I>(PhantomData<(B, I)>);
impl<'a, B, I> Parser for $type_name<B, I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
B: ByteOrder,
{
type Input = I;
type Output = $func_name;
type PartialState = ();
#[inline]
fn parse_lazy(
&mut self,
input: &mut Self::Input
) -> ParseResult<Self::Output, <Self::Input as StreamOnce>::Error> {
let buffer = &mut [0u8; 8][..size_of::<Self::Output>()];
for elem in &mut *buffer {
*elem = ctry!(uncons(input)).0;
}
ConsumedOk(B::$read_name(buffer))
}
}
$(#[$attr])*
#[inline(always)]
pub fn $func_name<'a, B, I>() -> $type_name<B, I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
B: ByteOrder,
{
$type_name(PhantomData)
}
$(#[$attr])*
#[inline(always)]
pub fn $be_name<'a, I>() -> $type_name<BE, I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
$func_name()
}
$(#[$attr])*
#[inline(always)]
pub fn $le_name<'a, I>() -> $type_name<LE, I>
where
I: Stream<Item = u8>,
I::Error: ParseError<I::Item, I::Range, I::Position>,
{
$func_name()
}
}
}
integer_parser!(
pub U16, u16, be_u16, le_u16, read_u16
);
integer_parser!(
pub U32, u32, be_u32, le_u32, read_u32
);
integer_parser!(
pub U64, u64, be_u64, le_u64, read_u64
);
integer_parser!(
pub I16, i16, be_i16, le_i16, read_i16
);
integer_parser!(
pub I32, i32, be_i32, le_i32, read_i32
);
integer_parser!(
pub I64, i64, be_i64, le_i64, read_i64
);
integer_parser!(
pub F32, f32, be_f32, le_f32, read_f32
);
integer_parser!(
pub F64, f64, be_f64, le_f64, read_f64
);
#[cfg(test)]
mod tests {
use super::*;
use crate::stream::buffered;
use crate::stream::state::State;
use crate::stream::IteratorStream;
#[test]
fn no_rangestream() {
let mut buf = [0; 8];
LE::write_f64(&mut buf, 123.45);
assert_eq!(
f64::<LE, _>()
.parse(buffered::Stream::new(
State::new(IteratorStream::new(buf.iter().cloned())),
1
))
.map(|(t, _)| t),
Ok(123.45)
);
assert_eq!(
le_f64()
.parse(buffered::Stream::new(
State::new(IteratorStream::new(buf.iter().cloned())),
1
))
.map(|(t, _)| t),
Ok(123.45)
);
let mut buf = [0; 8];
BE::write_f64(&mut buf, 123.45);
assert_eq!(
be_f64()
.parse(buffered::Stream::new(
State::new(IteratorStream::new(buf.iter().cloned())),
1
))
.map(|(t, _)| t),
Ok(123.45)
);
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn memslice_basic() {
let haystack = b"abc123";
assert_eq!(memslice(b"", haystack), Some(0));
assert_eq!(memslice(b"a", haystack), Some(0));
assert_eq!(memslice(b"ab", haystack), Some(0));
assert_eq!(memslice(b"c12", haystack), Some(2));
let haystack2 = b"abcab2";
assert_eq!(memslice(b"abc", haystack2), Some(0));
assert_eq!(memslice(b"ab2", haystack2), Some(3));
let haystack3 = b"aaabaaaa";
assert_eq!(memslice(b"aaaa", haystack3), Some(4));
}
}