use core::ops;
pub(crate) mod errors;
use self::errors::*;
mod luapat;
use self::luapat::{LUA_MAXCAPTURES, LuaMatch, str_check, str_match};
pub(crate) struct LuaPattern<'a> {
patt: &'a [u8],
matches: [LuaMatch; LUA_MAXCAPTURES],
n_match: usize,
}
impl<'a> LuaPattern<'a> {
pub(crate) fn from_bytes_try(bytes: &'a [u8]) -> Result<LuaPattern<'a>, PatternError> {
str_check(bytes)?;
Ok(LuaPattern {
patt: bytes,
matches: [LuaMatch { start: 0, end: 0 }; LUA_MAXCAPTURES],
n_match: 0,
})
}
pub(crate) fn matches_bytes(&mut self, s: &[u8]) -> bool {
match str_match(s, self.patt, &mut self.matches) {
Ok(n_match) => {
self.n_match = n_match;
n_match > 0
}
Err(_) => {
self.n_match = 0;
false
}
}
}
pub(crate) fn range(&self) -> ops::Range<usize> {
self.capture(0)
}
pub(crate) fn capture(&self, i: usize) -> ops::Range<usize> {
ops::Range {
start: self.matches[i].start,
end: self.matches[i].end,
}
}
pub(crate) fn num_matches(&self) -> usize {
self.n_match
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn byte_captures_and_matching() {
let mut pattern = LuaPattern::from_bytes_try(b"^(%a+)").unwrap();
assert!(pattern.matches_bytes(b"one dog"));
assert_eq!(pattern.capture(0), 0..3);
assert_eq!(pattern.capture(1), 0..3);
assert_eq!(pattern.num_matches(), 2);
assert!(!pattern.matches_bytes(b" one dog"));
}
#[test]
fn multiple_byte_captures() {
let mut pattern = LuaPattern::from_bytes_try(b"%s*(%d+)%s+(%S+)").unwrap();
assert!(pattern.matches_bytes(b" 233 hello dolly"));
assert_eq!(pattern.capture(1), 1..4);
assert_eq!(pattern.capture(2), 7..12);
}
#[test]
fn bad_patterns() {
let bad = [
(
b"bonzo %".as_slice(),
PatternError::MalformedPattern(MalformedPattern::EndsWithPercent),
),
(b"bonzo (dog%(".as_slice(), PatternError::UnfinishedCapture),
(
b"alles [%a%[".as_slice(),
PatternError::MalformedPattern(MalformedPattern::MissingBracket),
),
(
b"bonzo (dog (cat)".as_slice(),
PatternError::UnfinishedCapture,
),
(
b"frodo %f[%A".as_slice(),
PatternError::MalformedPattern(MalformedPattern::MissingBracket),
),
(
b"frodo (1) (2(3)%2)%1".as_slice(),
PatternError::InvalidCaptureIndex(Some(1)),
),
];
for (pattern, expected) in bad {
let result = LuaPattern::from_bytes_try(pattern);
assert!(matches!(result, Err(error) if error == expected));
}
}
}