#[derive(Debug)]
pub struct Delimited<'a> {
s: &'a str,
ix: usize,
}
impl<'a> Delimited<'a> {
#[must_use]
pub fn new(
s: &str
) -> Delimited {
Delimited { s, ix: 0 }
}
pub fn bytes<T>(
&mut self,
bytes: usize,
) -> Option<T>
where
T: std::str::FromStr,
T::Err: std::fmt::Debug,
{
let r = self.s[self.ix..self.ix + bytes].parse::<T>().unwrap();
self.ix = self.ix + bytes;
Some(r)
}
pub fn bytes_s<T>(
&mut self,
bytes: usize,
) -> &str
{
let start = self.ix;
self.ix = self.ix + bytes;
&self.s[start..self.ix]
}
#[must_use]
pub fn matched<T>(
&mut self,
delim: &str
) -> Option<T>
where
T: std::str::FromStr,
T::Err: std::fmt::Debug,
{
self.matched_s(delim).map(|m| m.parse::<T>().unwrap())
}
#[must_use]
pub fn matched_s(
&mut self,
delim: &str
) -> Option<&'a str> {
self.mismatched_s(delim, delim)
}
#[must_use]
pub fn mismatched<T>(
&mut self,
delim_start: &str,
delim_end: &str
) -> Option<T>
where
T: std::str::FromStr,
T::Err: std::fmt::Debug,
{
self.mismatched_s(delim_start, delim_end)
.map(|m| m.parse::<T>().unwrap())
}
#[must_use]
pub fn mismatched_s(
&mut self,
delim_start: &str,
delim_end: &str
) -> Option<&'a str>
{
self.delimited(delim_start, delim_end)
}
fn delimited(
&mut self,
delim_start: &str,
delim_end: &str
) -> Option<&'a str>
{
self.s[self.ix..].find(delim_start)
.and_then(|s_ix| {
let from = self.ix + s_ix + 1; self.s[from..].find(delim_end)
.and_then(|len| {
if len > 0 {
self.ix += s_ix + len + 2;
Some(&self.s[from..from + len])
} else { None }
})
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn raw() {
let mut d = Delimited::new("12abc");
let result = d.bytes::<u8>(2);
assert_eq!(result, Some(12));
}
#[test]
fn matched() {
let mut d = Delimited::new("aaa :12: bbb :34: ccc");
let first = d.matched(":");
let second = d.matched(":");
assert_eq!(first, Some(12));
assert_eq!(second, Some(34));
}
#[test]
fn matched_empty() {
let mut d = Delimited::new("");
assert_eq!(d.matched::<usize>(":"), None);
}
#[test]
fn matched_missing_start() {
let mut d = Delimited::new("abc:12def");
assert_eq!(d.matched::<usize>(":"), None);
}
#[test]
fn matched_missing_end() {
let mut d = Delimited::new("abc12:def");
assert_eq!(d.matched::<usize>(":"), None);
}
#[test]
fn matched_missing_both() {
let mut d = Delimited::new("abc12def");
assert_eq!(d.matched::<usize>(":"), None);
}
#[test]
fn matched_uneven_delimiters() {
let mut d = Delimited::new("abc:12:def:34ghi");
assert_eq!(d.matched(":"), Some(12));
assert_eq!(d.matched::<usize>(":"), None);
}
#[test]
fn matched_empty_delimited_value() {
let mut d = Delimited::new("abc::def");
assert_eq!(d.matched::<usize>(":"), None);
}
#[test]
fn mismatched() {
let mut d = Delimited::new("aaa :12; bbb +34| ccc");
let first = d.mismatched(":", ";");
let second = d.mismatched("+", "|");
assert_eq!(first, Some(12));
assert_eq!(second, Some(34));
}
#[test]
fn delimited() {
let mut d = Delimited::new("abc:12;def");
assert_eq!(d.delimited(":", ";"), Some("12"));
}
}