extern crate ascii;
use crate::{
combinator::{no_partial, satisfy, skip_many, token, Token},
error::{
self, ParseError,
ParseResult::{self, *},
},
lib::marker::PhantomData,
parser::{
range::{take_fn, TakeRange},
token::tokens_cmp,
ParseMode,
},
stream::{RangeStream, Stream, StreamOnce},
Parser,
};
use self::ascii::AsciiChar;
#[inline]
pub fn byte<Input>(c: u8) -> Token<Input>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
token(c)
}
macro_rules! byte_parser {
($name:ident, $ty:ident, $f: ident) => {{
satisfy(|c: u8| AsciiChar::from_ascii(c).map(|c| c.$f()).unwrap_or(false))
.expected(stringify!($name))
}};
($name:ident, $ty:ident, $f: ident $($args:tt)+) => {{
satisfy(|c: u8| AsciiChar::from_ascii(c).map(|c| c.$f $($args)+).unwrap_or(false))
.expected(stringify!($name))
}};
}
#[inline]
pub fn digit<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
byte_parser!(digit, Digit, is_digit(10))
}
#[inline]
pub fn space<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
byte_parser!(space, Space, is_whitespace)
}
#[inline]
pub fn spaces<Input>() -> impl Parser<Input, Output = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
skip_many(space()).expected("whitespaces")
}
#[inline]
pub fn newline<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
satisfy(|ch: u8| ch == b'\n').expected("lf newline")
}
#[inline]
pub fn crlf<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
no_partial(satisfy(|ch: u8| ch == b'\r').with(newline())).expected("crlf newline")
}
#[inline]
pub fn tab<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
satisfy(|ch| ch == b'\t').expected("tab")
}
#[inline]
pub fn upper<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
byte_parser!(upper, Upper, is_uppercase)
}
#[inline]
pub fn lower<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
byte_parser!(lower, Lower, is_lowercase)
}
#[inline]
pub fn alpha_num<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
byte_parser!(alpha_num, AlphaNum, is_alphanumeric)
}
#[inline]
pub fn letter<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
byte_parser!(letter, Letter, is_alphabetic)
}
#[inline]
pub fn oct_digit<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
satisfy(|ch| ch >= b'0' && ch <= b'7').expected("octal digit")
}
#[inline]
pub fn hex_digit<Input>() -> impl Parser<Input, Output = u8, PartialState = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
byte_parser!(hex_digit, HexDigit, is_digit(16))
}
parser! {
#[inline]
pub fn bytes['a, 'b, Input](s: &'static [u8])(Input) -> &'a [u8]
where [
Input: Stream<Token = u8, Range = &'b [u8]>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
]
{
bytes_cmp(s, |l: u8, r: u8| l == r)
}
}
parser! {
#[inline]
pub fn bytes_cmp['a, 'b, C, Input](s: &'static [u8], cmp: C)(Input) -> &'a [u8]
where [
C: FnMut(u8, u8) -> bool,
Input: Stream<Token = u8, Range = &'b [u8]>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
]
{
let s = *s;
tokens_cmp(s.iter().cloned(), cmp)
.map(move |_| s)
.expected(error::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]
$(#[$attr])*
pub fn $func_name[Input]($($param : u8),*)(Input) -> Input::Range
where [
Input: RangeStream,
Input::Range: AsRef<[u8]> + crate::stream::Range,
]
{
take_fn(move |haystack: Input::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]
pub fn take_until_bytes['a, Input](needle: &'a [u8])(Input) -> Input::Range
where [
Input: RangeStream,
Input::Range: AsRef<[u8]> + crate::stream::Range,
]
{
take_fn(move |haystack: Input::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 byteorder::{ByteOrder, BE, LE};
use crate::{error::ResultExt, lib::mem::size_of, stream::uncons};
use super::*;
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, Input>(PhantomData<(B, Input)>);
impl<'a, Input, B> Parser<Input> for $type_name<B, Input>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
B: ByteOrder,
{
type Output = $func_name;
type PartialState = ();
parse_mode!(Input);
fn parse_mode_impl<M>(
&mut self,
_mode: M,
input: &mut Input,
_state: &mut Self::PartialState,
) -> ParseResult<Self::Output, <Input as StreamOnce>::Error>
where
M: ParseMode,
{
let checkpoint = input.checkpoint();
let result = (|| {
let buffer = &mut [0u8; 8][..size_of::<Self::Output>()];
for elem in &mut *buffer {
*elem = ctry!(uncons(input)).0;
}
ConsumedOk(B::$read_name(buffer))
})();
if result.is_err() {
ctry!(input.reset(checkpoint).consumed());
}
result
}
}
$(#[$attr])*
#[inline]
pub fn $func_name<'a, B, Input>() -> $type_name<B, Input>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
B: ByteOrder,
{
$type_name(PhantomData)
}
$(#[$attr])*
#[inline]
pub fn $be_name<'a, Input>() -> $type_name<BE, Input>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
$func_name()
}
$(#[$attr])*
#[inline]
pub fn $le_name<'a, Input>() -> $type_name<LE, Input>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::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 crate::stream::{buffered, position, IteratorStream};
use super::*;
#[test]
fn no_rangestream() {
let mut buf = [0; 8];
LE::write_f64(&mut buf, 123.45);
assert_eq!(
f64::<LE, _>()
.parse(buffered::Stream::new(
position::Stream::new(IteratorStream::new(buf.iter().cloned())),
1
))
.map(|(t, _)| t),
Ok(123.45)
);
assert_eq!(
le_f64()
.parse(buffered::Stream::new(
position::Stream::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(
position::Stream::new(IteratorStream::new(buf.iter().cloned())),
1
))
.map(|(t, _)| t),
Ok(123.45)
);
}
}
}
#[cfg(test)]
mod tests {
use crate::stream::{buffered, position, ReadStream};
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));
}
#[test]
fn bytes_read_stream() {
assert!(bytes(b"abc")
.parse(buffered::Stream::new(
position::Stream::new(ReadStream::new("abc".as_bytes())),
1
))
.is_ok());
}
}