FEATURE: must_string Result mapper and until! matcher.

This commit is contained in:
Jeremy Wall 2018-09-07 20:12:39 -05:00
parent 40c89a5cb3
commit 29b5d71bb1
2 changed files with 79 additions and 0 deletions

View File

@ -27,3 +27,52 @@ macro_rules! text_token {
} }
}}; }};
} }
macro_rules! until {
($i:expr, $term:ident!( $( $args:tt )* ) ) => {{
use $crate::{Result, Offsetable};
let mut acc = Vec::new();
let mut _i = $i.clone();
let pfn = || {
loop {
match $term!(_i.clone(), $($args)*) {
Result::Complete(_, _) => return Result::Complete(_i, acc),
Result::Abort(e) => return Result::Abort(e),
Result::Incomplete(offset) => return Result::Incomplete(offset),
Result::Fail(_) => {
// noop
}
}
let item = match _i.next() {
Some(it) => it,
None => return Result::Incomplete(_i.get_offset()),
};
acc.push(item);
}
};
pfn()
}};
($i:expr, $term:ident) => {
consume_until!($i, run!($term))
};
}
pub fn must_string<'a, I, E>(matched: Result<I, Vec<&'a u8>, E>, msg: E) -> Result<I, String, E>
where
I: InputIter<Item=&'a u8>,
E: Debug + Display,
{
match matched {
Result::Complete(i, mut o) => {
let new_string = String::from_utf8(o.drain(0..).map(|b| *b).collect());
match new_string {
Ok(s) => Result::Complete(i, s),
Err(_) => Result::Abort(Error::new(msg, &i)),
}
},
Result::Incomplete(offset) => Result::Incomplete(offset),
Result::Abort(e) => Result::Abort(e),
Result::Fail(e) => Result::Fail(e),
}
}

View File

@ -2,6 +2,7 @@ use std::fmt::{Debug, Display};
use super::{InputIter, Offsetable, Result}; use super::{InputIter, Offsetable, Result};
use iter::SliceIter; use iter::SliceIter;
use matchers::must_string;
#[test] #[test]
fn test_slice_iter() { fn test_slice_iter() {
@ -349,3 +350,32 @@ fn test_repeat_abort() {
let result = repeat!(iter, must!(will_fail)); let result = repeat!(iter, must!(will_fail));
assert!(result.is_abort()); assert!(result.is_abort());
} }
#[test]
fn test_until() {
let input_str = "foo; ";
let iter = SliceIter::new(input_str.as_bytes());
let result = must_string(until!(iter, text_token!("; ")), "AAAHHH!".to_string());
assert!(result.is_complete());
if let Result::Complete(i, o) = result {
assert_eq!(i.get_offset(), 3);
assert_eq!(o.len(), 3);
assert_eq!(&o, "foo");
}
}
#[test]
fn test_until_abort() {
let input_str = "foo ";
let iter = SliceIter::new(input_str.as_bytes());
let result = until!(iter, must!(will_fail));
assert!(result.is_abort());
}
#[test]
fn test_until_incomplete() {
let input_str = "foo;";
let iter = SliceIter::new(input_str.as_bytes());
let result = until!(iter, text_token!("; "));
assert!(result.is_incomplete());
}