use crate::segment::OwnedSegment;
#[derive(Debug)]
pub struct SegmentNotFound {
pub expected: String,
}
impl std::fmt::Display for SegmentNotFound {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "Expected segment '{}' not found", self.expected)
}
}
impl std::error::Error for SegmentNotFound {}
pub struct SegmentCursor {
position: usize,
total: usize,
}
impl SegmentCursor {
pub fn new(total: usize) -> Self {
Self { position: 0, total }
}
pub fn position(&self) -> usize {
self.position
}
pub fn remaining(&self) -> usize {
self.total.saturating_sub(self.position)
}
pub fn is_exhausted(&self) -> bool {
self.position >= self.total
}
pub fn advance(&mut self) {
self.position += 1;
}
pub fn save(&self) -> usize {
self.position
}
pub fn restore(&mut self, saved: usize) {
self.position = saved;
}
}
pub fn peek_is(segments: &[OwnedSegment], cursor: &SegmentCursor, tag: &str) -> bool {
if cursor.is_exhausted() {
return false;
}
segments[cursor.position()].is(tag)
}
pub fn consume<'a>(
segments: &'a [OwnedSegment],
cursor: &mut SegmentCursor,
) -> Option<&'a OwnedSegment> {
if cursor.is_exhausted() {
return None;
}
let seg = &segments[cursor.position()];
cursor.advance();
Some(seg)
}
pub fn expect_segment<'a>(
segments: &'a [OwnedSegment],
cursor: &mut SegmentCursor,
tag: &str,
) -> Result<&'a OwnedSegment, SegmentNotFound> {
if cursor.is_exhausted() {
return Err(SegmentNotFound {
expected: tag.to_string(),
});
}
let seg = &segments[cursor.position()];
if !seg.is(tag) {
return Err(SegmentNotFound {
expected: tag.to_string(),
});
}
cursor.advance();
Ok(seg)
}
#[cfg(test)]
mod tests {
use super::*;
fn make_segment(id: &str) -> OwnedSegment {
OwnedSegment {
id: id.to_string(),
elements: vec![],
segment_number: 0,
}
}
#[test]
fn test_cursor_peek_and_advance() {
let mut cursor = SegmentCursor::new(4);
assert_eq!(cursor.position(), 0);
assert!(!cursor.is_exhausted());
cursor.advance();
assert_eq!(cursor.position(), 1);
cursor.advance();
cursor.advance();
cursor.advance();
assert!(cursor.is_exhausted());
}
#[test]
fn test_cursor_remaining() {
let mut cursor = SegmentCursor::new(5);
assert_eq!(cursor.remaining(), 5);
cursor.advance();
assert_eq!(cursor.remaining(), 4);
}
#[test]
fn test_cursor_save_restore() {
let mut cursor = SegmentCursor::new(10);
cursor.advance();
cursor.advance();
let saved = cursor.save();
assert_eq!(saved, 2);
cursor.advance();
cursor.advance();
assert_eq!(cursor.position(), 4);
cursor.restore(saved);
assert_eq!(cursor.position(), 2);
}
#[test]
fn test_cursor_empty() {
let cursor = SegmentCursor::new(0);
assert!(cursor.is_exhausted());
assert_eq!(cursor.remaining(), 0);
}
#[test]
fn test_peek_is_helper() {
let segments = vec![make_segment("NAD"), make_segment("IDE")];
let cursor = SegmentCursor::new(segments.len());
assert!(peek_is(&segments, &cursor, "NAD"));
assert!(!peek_is(&segments, &cursor, "IDE"));
}
#[test]
fn test_peek_is_exhausted() {
let segments: Vec<OwnedSegment> = vec![];
let cursor = SegmentCursor::new(0);
assert!(!peek_is(&segments, &cursor, "NAD"));
}
#[test]
fn test_consume_helper() {
let segments = vec![make_segment("UNH"), make_segment("BGM")];
let mut cursor = SegmentCursor::new(segments.len());
let seg = consume(&segments, &mut cursor).unwrap();
assert_eq!(seg.id, "UNH");
assert_eq!(cursor.position(), 1);
let seg = consume(&segments, &mut cursor).unwrap();
assert_eq!(seg.id, "BGM");
assert!(cursor.is_exhausted());
assert!(consume(&segments, &mut cursor).is_none());
}
#[test]
fn test_expect_segment_helper() {
let segments = vec![make_segment("UNH"), make_segment("BGM")];
let mut cursor = SegmentCursor::new(segments.len());
let seg = expect_segment(&segments, &mut cursor, "UNH").unwrap();
assert_eq!(seg.id, "UNH");
assert_eq!(cursor.position(), 1);
}
#[test]
fn test_expect_segment_wrong_tag() {
let segments = vec![make_segment("UNH")];
let mut cursor = SegmentCursor::new(segments.len());
let result = expect_segment(&segments, &mut cursor, "BGM");
assert!(result.is_err());
}
#[test]
fn test_expect_segment_exhausted() {
let segments: Vec<OwnedSegment> = vec![];
let mut cursor = SegmentCursor::new(0);
let result = expect_segment(&segments, &mut cursor, "UNH");
assert!(result.is_err());
}
}