use std::marker::PhantomData;
use strcursor::StrCursor;
use ::ScanError;
use ::input::ScanInput;
use ::scanner::{ScanFromStr, ScanStr};
#[cfg(feature="regex")] use regex::Regex;
pub fn exact_width<Then>(width: usize, then: Then) -> ExactWidth<Then> {
ExactWidth(width, then)
}
pub fn exact_width_a<S>(width: usize) -> ExactWidth<ScanA<S>> {
exact_width(width, scan_a::<S>())
}
pub struct ExactWidth<Then>(usize, Then);
impl<'a, Then> ScanStr<'a> for ExactWidth<Then>
where Then: ScanStr<'a> {
type Output = Then::Output;
fn scan<I: ScanInput<'a>>(&mut self, s: I) -> Result<(Self::Output, usize), ScanError> {
let s_str = s.as_str();
if s_str.len() < self.0 {
return Err(ScanError::syntax("input not long enough"));
}
let sl = s.from_subslice(&s_str[..self.0]);
match self.1.scan(sl) {
Ok((_, n)) if n != self.0 => Err(ScanError::syntax("value did not consume enough characters")),
Err(err) => Err(err),
Ok((v, _)) => Ok((v, self.0))
}
}
fn wants_leading_junk_stripped(&self) -> bool {
self.1.wants_leading_junk_stripped()
}
}
#[cfg(test)]
#[test]
fn test_exact_width() {
use ::ScanError as SE;
use ::ScanErrorKind as SEK;
use ::scanner::Word;
let scan = exact_width_a::<Word>;
assert_match!(scan(2).scan(""), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(scan(2).scan("a"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(scan(2).scan("a b"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(scan(2).scan("ab"), Ok(("ab", 2)));
assert_match!(scan(2).scan("abc"), Ok(("ab", 2)));
}
pub fn max_width<Then>(width: usize, then: Then) -> MaxWidth<Then> {
MaxWidth(width, then)
}
pub fn max_width_a<S>(width: usize) -> MaxWidth<ScanA<S>> {
max_width(width, scan_a::<S>())
}
pub struct MaxWidth<Then>(usize, Then);
impl<'a, Then> ScanStr<'a> for MaxWidth<Then>
where Then: ScanStr<'a> {
type Output = Then::Output;
fn scan<I: ScanInput<'a>>(&mut self, s: I) -> Result<(Self::Output, usize), ScanError> {
let s_str = s.as_str();
let len = ::std::cmp::min(s_str.len(), self.0);
let stop = StrCursor::new_at_left_of_byte_pos(s_str, len);
let sl = s.from_subslice(stop.slice_before());
self.1.scan(sl)
}
fn wants_leading_junk_stripped(&self) -> bool {
self.1.wants_leading_junk_stripped()
}
}
#[cfg(test)]
#[test]
fn test_max_width() {
use ::ScanError as SE;
use ::ScanErrorKind as SEK;
use ::scanner::Word;
let scan = max_width_a::<Word>;
assert_match!(scan(2).scan(""), Err(SE { kind: SEK::SyntaxNoMessage, .. }));
assert_match!(scan(2).scan("a"), Ok(("a", 1)));
assert_match!(scan(2).scan("a b"), Ok(("a", 1)));
assert_match!(scan(2).scan("ab"), Ok(("ab", 2)));
assert_match!(scan(2).scan("abc"), Ok(("ab", 2)));
}
pub fn min_width<Then>(width: usize, then: Then) -> MinWidth<Then> {
MinWidth(width, then)
}
pub fn min_width_a<S>(width: usize) -> MinWidth<ScanA<S>> {
min_width(width, scan_a::<S>())
}
pub struct MinWidth<Then>(usize, Then);
impl<'a, Then> ScanStr<'a> for MinWidth<Then>
where Then: ScanStr<'a> {
type Output = Then::Output;
fn scan<I: ScanInput<'a>>(&mut self, s: I) -> Result<(Self::Output, usize), ScanError> {
let s_str = s.as_str();
if s_str.len() < self.0 {
return Err(ScanError::syntax("expected more bytes to scan"));
}
match self.1.scan(s) {
Ok((_, n)) if n < self.0 => Err(ScanError::syntax("scanned value too short")),
other => other
}
}
fn wants_leading_junk_stripped(&self) -> bool {
self.1.wants_leading_junk_stripped()
}
}
#[cfg(test)]
#[test]
fn test_min_width() {
use ::ScanError as SE;
use ::ScanErrorKind as SEK;
use ::scanner::Word;
let scan = min_width_a::<Word>;
assert_match!(scan(2).scan(""), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(scan(2).scan("a"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(scan(2).scan("a b"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(scan(2).scan("ab"), Ok(("ab", 2)));
assert_match!(scan(2).scan("abc"), Ok(("abc", 3)));
}
#[cfg(feature="regex")]
pub fn re<Then>(s: &str, then: Then) -> ScanRegex<Then> {
ScanRegex(Regex::new(s).unwrap(), then)
}
#[cfg(feature="regex")]
pub fn re_a<S>(s: &str) -> ScanRegex<ScanA<S>> {
re(s, scan_a::<S>())
}
#[cfg(feature="regex")]
pub fn re_str(s: &str) -> ScanRegex<ScanA<::scanner::Everything<&str>>> {
re_a::<::scanner::Everything<&str>>(s)
}
#[cfg(feature="regex")]
pub struct ScanRegex<Then>(Regex, Then);
#[cfg(feature="regex")]
impl<'a, Then> ScanStr<'a> for ScanRegex<Then>
where Then: ScanStr<'a> {
type Output = Then::Output;
fn scan<I: ScanInput<'a>>(&mut self, s: I) -> Result<(Self::Output, usize), ScanError> {
let s_str = s.as_str();
let cap = match self.0.captures(s_str) {
None => return Err(ScanError::syntax("no match for regular expression")),
Some(cap) => cap,
};
let cover = match cap.pos(0) {
None => return Err(ScanError::syntax("no match for regular expression")),
Some(pos) => pos,
};
let sl = if let Some(sl) = cap.name("scan") {
sl
} else if let Some((a, b)) = cap.pos(1) {
&s_str[a..b]
} else {
&s_str[cover.0 .. cover.1]
};
let sl = s.from_subslice(sl);
match self.1.scan(sl) {
Ok((v, _)) => Ok((v, cover.1)),
Err(err) => Err(err),
}
}
fn wants_leading_junk_stripped(&self) -> bool {
self.1.wants_leading_junk_stripped()
}
}
#[cfg(feature="regex")]
#[cfg(test)]
#[test]
fn test_re() {
use ::ScanError as SE;
use ::ScanErrorKind as SEK;
let scan = re_str;
assert_match!(scan("[a-z][0-9]").scan(""), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(scan("[a-z][0-9]").scan("a"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(scan("[a-z][0-9]").scan("a 0"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(scan("[a-z][0-9]").scan("a0"), Ok(("a0", 2)));
assert_match!(scan("[a-z][0-9]").scan("a0c"), Ok(("a0", 2)));
assert_match!(scan("[a-z][0-9]").scan(" a0"), Ok(("a0", 3)));
}
pub fn scan_a<S>() -> ScanA<S> {
ScanA(PhantomData)
}
pub struct ScanA<S>(PhantomData<S>);
impl<'a, S> ScanStr<'a> for ScanA<S>
where S: ScanFromStr<'a> {
type Output = S::Output;
fn scan<I: ScanInput<'a>>(&mut self, s: I) -> Result<(Self::Output, usize), ScanError> {
<S as ScanFromStr<'a>>::scan_from(s)
}
fn wants_leading_junk_stripped(&self) -> bool {
<S as ScanFromStr<'a>>::wants_leading_junk_stripped()
}
}
#[cfg(feature="nightly-pattern")]
pub fn until_pat<Then, P>(pat: P, then: Then) -> UntilPat<Then, P> {
UntilPat(pat, then)
}
#[cfg(feature="nightly-pattern")]
pub fn until_pat_a<S, P>(pat: P) -> UntilPat<ScanA<S>, P> {
until_pat(pat, scan_a::<S>())
}
#[cfg(feature="nightly-pattern")]
pub fn until_pat_str<'a, P>(pat: P) -> UntilPat<ScanA<::scanner::Everything<'a, &'a str>>, P> {
until_pat_a::<::scanner::Everything<&str>, _>(pat)
}
#[cfg(feature="nightly-pattern")]
pub struct UntilPat<Then, P>(P, Then);
#[cfg(feature="nightly-pattern")]
impl<'a, Then, P> ScanStr<'a> for UntilPat<Then, P>
where
Then: ScanStr<'a>,
for<'b> P: Copy + ::std::str::pattern::Pattern<'b>,
{
type Output = Then::Output;
fn scan<I: ScanInput<'a>>(&mut self, s: I) -> Result<(Self::Output, usize), ScanError> {
let s_str = s.as_str();
let off = match s_str.find(self.0) {
Some(off) => off,
None => return Err(ScanError::syntax("no match for pattern")),
};
let sl = &s_str[..off];
let sl = s.from_subslice(sl);
self.1.scan(sl)
}
fn wants_leading_junk_stripped(&self) -> bool {
self.1.wants_leading_junk_stripped()
}
}
#[cfg(feature="nightly-pattern")]
#[cfg(test)]
#[test]
fn test_until() {
use ::ScanError as SE;
use ::ScanErrorKind as SEK;
#[allow(non_snake_case)]
fn S(s: &str) -> String { String::from(s) }
assert_match!(until_pat_str("x").scan(""), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str("x").scan("a"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str("x").scan("ab"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str("x").scan("x"), Ok(("", 0)));
assert_match!(until_pat_str("x").scan("ax"), Ok(("a", 1)));
assert_match!(until_pat_str("x").scan("abx"), Ok(("ab", 2)));
assert_match!(until_pat_str(&"x").scan(""), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str(&"x").scan("a"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str(&"x").scan("ab"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str(&"x").scan("x"), Ok(("", 0)));
assert_match!(until_pat_str(&"x").scan("ax"), Ok(("a", 1)));
assert_match!(until_pat_str(&"x").scan("abx"), Ok(("ab", 2)));
assert_match!(until_pat_str(&S("x")).scan(""), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str(&S("x")).scan("a"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str(&S("x")).scan("ab"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str(&S("x")).scan("x"), Ok(("", 0)));
assert_match!(until_pat_str(&S("x")).scan("ax"), Ok(("a", 1)));
assert_match!(until_pat_str(&S("x")).scan("abx"), Ok(("ab", 2)));
assert_match!(until_pat_str('x').scan(""), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str('x').scan("a"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str('x').scan("ab"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str('x').scan("x"), Ok(("", 0)));
assert_match!(until_pat_str('x').scan("ax"), Ok(("a", 1)));
assert_match!(until_pat_str('x').scan("abx"), Ok(("ab", 2)));
assert_match!(until_pat_str(&['x'][..]).scan(""), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str(&['x'][..]).scan("a"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str(&['x'][..]).scan("ab"), Err(SE { kind: SEK::Syntax(_), .. }));
assert_match!(until_pat_str(&['x'][..]).scan("x"), Ok(("", 0)));
assert_match!(until_pat_str(&['x'][..]).scan("ax"), Ok(("a", 1)));
assert_match!(until_pat_str(&['x'][..]).scan("abx"), Ok(("ab", 2)));
}