use std::borrow::Cow;
use crate::char_stream::{CharStream, InputData};
use crate::int_stream::IntStream;
#[derive(Debug)]
pub struct InputStream<'input> {
name: String,
data_raw: &'input str,
index: isize,
}
impl<'input> CharStream<'input> for InputStream<'input> {
#[inline]
fn get_text(&self, start: isize, stop: isize) -> Cow<'input, str> {
self.get_text_inner(start, stop).into()
}
}
impl<'input> InputStream<'input> {
fn get_text_inner(&self, start: isize, stop: isize) -> &'input str {
let start = start as usize;
let stop = self.data_raw.offset(stop, 1).unwrap_or(stop) as usize;
if stop < self.data_raw.len() {
&self.data_raw[start..stop]
} else {
&self.data_raw[start..]
}
}
pub fn new(data_raw: &'input str) -> Self {
Self {
name: "<empty>".to_string(),
data_raw,
index: 0,
}
}
#[inline]
pub fn reset(&mut self) {
self.index = 0
}
}
impl IntStream for InputStream<'_> {
#[inline]
fn consume(&mut self) {
if let Some(index) = self.data_raw.offset(self.index, 1) {
self.index = index;
} else {
panic!("cannot consume EOF");
}
}
#[inline]
fn la(&mut self, mut offset: isize) -> i32 {
if offset == 1 {
return self
.data_raw
.item(self.index)
.unwrap_or(crate::int_stream::EOF);
}
if offset == 0 {
panic!("should not be called with offset 0");
}
if offset < 0 {
offset += 1; }
self.data_raw
.offset(self.index, offset - 1)
.and_then(|index| self.data_raw.item(index))
.unwrap_or(crate::int_stream::EOF)
}
#[inline]
fn mark(&mut self) -> isize {
-1
}
#[inline]
fn release(&mut self, _marker: isize) {}
#[inline]
fn index(&self) -> isize {
self.index
}
#[inline]
fn seek(&mut self, index: isize) {
self.index = index
}
#[inline]
fn size(&self) -> isize {
self.data_raw.len() as isize
}
fn get_source_name(&self) -> String {
self.name.clone()
}
}
#[cfg(test)]
mod test {
use crate::{char_stream::CharStream, int_stream::EOF};
use super::InputStream;
#[test]
fn test_str_input_stream() {
let mut input = InputStream::new("V1は3");
let input = &mut input as &mut dyn CharStream;
assert_eq!(input.la(1), 'V' as i32);
assert_eq!(input.index(), 0);
input.consume();
assert_eq!(input.la(1), '1' as i32);
assert_eq!(input.la(-1), 'V' as i32);
assert_eq!(input.index(), 1);
input.consume();
assert_eq!(input.la(1), 0x306F);
assert_eq!(input.index(), 2);
input.consume();
assert_eq!(input.index(), 5);
assert_eq!(input.la(-2), '1' as i32);
assert_eq!(input.la(2), EOF);
assert_eq!(input.get_text(1, 1), "1");
assert_eq!(input.get_text(1, 2), "1は");
assert_eq!(input.get_text(2, 2), "は");
assert_eq!(input.get_text(2, 5), "は3");
assert_eq!(input.get_text(5, 5), "3");
}
}