#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub(crate) struct InputRangeOffset {
pub start: usize,
pub len: usize,
}
impl InputRangeOffset {
pub const fn total_len(&self) -> usize {
self.start + self.len
}
}
#[derive(Clone, Copy)]
pub(crate) struct InputRange<'gram> {
input: &'gram str,
pub offset: InputRangeOffset,
}
impl<'gram> InputRange<'gram> {
pub const fn new(input: &'gram str) -> Self {
Self {
input,
offset: InputRangeOffset { start: 0, len: 0 },
}
}
#[inline(always)]
pub fn next(&self) -> &'gram str {
let next_idx = self.offset.start + self.offset.len;
self.input.get(next_idx..).unwrap_or("")
}
pub const fn after(&self) -> Self {
Self {
input: self.input,
offset: InputRangeOffset {
start: self.offset.start + self.offset.len,
len: 0,
},
}
}
#[cfg_attr(test, mutants::skip)]
pub fn advance_by(&self, step: usize) -> Self {
let InputRangeOffset { start, len } = self.offset;
let max_len = self.input.len() - start;
let len = std::cmp::min(len + step, max_len);
Self {
input: self.input,
offset: InputRangeOffset { start, len },
}
}
pub const fn is_complete(&self) -> bool {
self.offset.start == 0 && self.offset.len == self.input.len()
}
}
impl std::fmt::Debug for InputRange<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let InputRangeOffset { start, len, .. } = self.offset;
let before = self.input.get(..start).unwrap_or("");
let scanned = self
.input
.get(start..)
.and_then(|s| s.get(..len))
.unwrap_or("");
let after = self.input.get(start + len..).unwrap_or("");
write!(f, "InputRange(\"{before}|{scanned}|{after}\")",)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn advance_by_respects_input_bounds() {
let r = InputRange::new("ab").advance_by(1).after().advance_by(2);
assert_eq!(r.offset.start, 1);
assert_eq!(
r.offset.len, 1,
"advance_by must not exceed input.len() - start"
);
}
#[test]
fn debug_fmt() {
let input = "GATTACA";
let input_range = InputRange::new(input).advance_by(3).after().advance_by(2);
let debug_format = format!("{input_range:?}");
assert_eq!(debug_format, "InputRange(\"GAT|TA|CA\")");
}
}