use crate::{
error::{self, ParseError, ParseResult::*},
parser::{
combinator::no_partial,
range::{take_fn, TakeRange},
repeat::skip_many,
token::{satisfy, token, tokens_cmp, Token},
},
stream::{RangeStream, Stream},
Parser,
};
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| c.$f())
.expected(stringify!($name))
}};
($name:ident, $ty:ident, $f: ident $($args:tt)+) => {{
satisfy(|c: u8| c.$f $($args)+)
.expected(stringify!($name))
}};
}
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_ascii_digit())
}
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_ascii_whitespace)
}
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")
}
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")
}
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")
}
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")
}
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_ascii_uppercase)
}
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_ascii_lowercase)
}
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_ascii_alphanumeric)
}
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_ascii_alphabetic)
}
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")
}
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_ascii_hexdigit())
}
parser! {
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! {
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;
$(#[$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! {
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 crate::{error::ResultExt, lib::mem::size_of, parser::function::parser, stream::uncons};
use super::*;
macro_rules! integer_parser {
(
$(#[$attr:meta])*
pub $type_name: ident,
$output_type: ident, $be_name: ident, $le_name: ident, $read_name: ident
) => {
$(#[$attr])*
pub fn $be_name<'a, Input>() -> impl Parser<Input, Output = $output_type, PartialState = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
parser(|input: &mut Input| {
let checkpoint = input.checkpoint();
let result = (|input: &mut Input| {
let mut buffer = [0u8; size_of::<$output_type>()];
for elem in &mut buffer[..] {
*elem = ctry!(uncons(input)).0;
}
CommitOk($output_type::from_be_bytes(buffer))
})(input);
if result.is_err() {
input.reset(checkpoint).committed().into_result()?;
}
result.into_result()
})
}
$(#[$attr])*
pub fn $le_name<'a, Input>() -> impl Parser<Input, Output = $output_type, PartialState = ()>
where
Input: Stream<Token = u8>,
Input::Error: ParseError<Input::Token, Input::Range, Input::Position>,
{
parser(|input: &mut Input| {
let checkpoint = input.checkpoint();
let result = (|input: &mut Input| {
let mut buffer = [0u8; size_of::<$output_type>()];
for elem in &mut buffer[..] {
*elem = ctry!(uncons(input)).0;
}
CommitOk($output_type::from_le_bytes(buffer))
})(input);
if result.is_err() {
input.reset(checkpoint).committed().into_result()?;
}
result.into_result()
})
}
}
}
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 buf = 123.45f64.to_le_bytes();
assert_eq!(
le_f64()
.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 buf = 123.45f64.to_be_bytes();
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, read};
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(read::Stream::new("abc".as_bytes())),
1
))
.is_ok());
}
}