use crate::{
location::{Offset, line_column},
stream::alias::{Guard, IndexRef, MutGuard},
};
use std::io;
#[derive(Debug)]
pub struct Stream<'index, Reader> {
reader: Reader,
index: IndexRef<'index>,
next_offset: Offset,
current_line: usize,
base: usize, }
impl<'index, R> Stream<'index, R> {
pub fn new(reader: R, index: IndexRef<'index>) -> Self {
Self {
reader,
base: 0,
index,
next_offset: 0.into(),
current_line: 0,
}
}
pub fn get_ref(&self) -> &R {
&self.reader
}
#[inline]
pub fn base(&self) -> usize {
self.base
}
#[inline]
pub fn get_index(&self) -> Guard<'_> {
self.index.get()
}
#[inline]
pub fn get_index_mut(&mut self) -> MutGuard<'_> {
self.index.get_mut()
}
}
impl<'index, R: io::Read> Stream<'index, R> {
#[inline]
pub fn read_len(&self) -> usize {
self.next_offset.raw()
}
fn forward(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let n = self.reader.read(buf)?;
for (offset, b) in buf.iter().take(n).enumerate() {
if *b == b'\n' {
self.current_line += 1;
let next_offset = self.next_offset;
self.get_index_mut().add_next_line(next_offset + offset + 1);
continue;
}
}
if !buf.is_empty() && n == 0 {
let end = self.get_index().end();
let next_offset = self.next_offset;
match end {
Some(end) if end != next_offset => {
self.get_index_mut().add_next_line(next_offset);
}
None => self.get_index_mut().add_next_line(next_offset),
_ => {}
}
}
self.next_offset += n;
Ok(n)
}
pub fn locate(&mut self, offset: Offset, buf: &mut [u8]) -> io::Result<line_column::ZeroBased> {
let line = self.locate_line(offset, buf)?;
let line_offset = self.get_index().query().line_offset(line).unwrap();
let col = offset - line_offset;
Ok((line, col.raw()).into())
}
pub fn locate_line(&mut self, offset: Offset, buf: &mut [u8]) -> io::Result<usize> {
let mut begin = 0;
loop {
if let Some(i) = self
.get_index()
.query()
.range_from(begin..)
.locate_line(offset)
{
break Ok(i); }
begin = self.get_index().count();
if self.forward(buf)? == 0 {
break Err(io_error("Invalid offset, exceed EOF"));
}
}
}
pub fn encode(
&mut self,
line_index: line_column::ZeroBased,
buf: &mut [u8],
) -> io::Result<Offset> {
let (line, col) = line_index.raw();
loop {
if let Some(offset) = self.get_index().query().line_offset(line) {
break Ok(offset + col);
}
if self.forward(buf)? == 0 {
break Err(io_error(format!("Invalid line index: ({}, {})", line, col)));
}
}
}
pub fn drain(&mut self, buf: &mut [u8]) -> io::Result<()> {
loop {
let n = self.forward(buf)?;
if n == 0 {
return Ok(());
}
}
}
}
impl<'index, R: io::Read> io::Read for Stream<'index, R> {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
self.forward(buf)
}
}
#[inline]
fn io_error<S: ToString>(msg: S) -> io::Error {
io::Error::new(io::ErrorKind::Other, msg.to_string())
}
#[cfg(test)]
mod test {
#![allow(unused_must_use)]
use crate::Index;
use super::*;
use std::{
cell::RefCell,
io::{BufReader, Read},
rc::Rc,
};
static SRC: &'static str = "\nThis is s sim\nple test that\n I have to verify stream reader!";
#[test]
fn test_stream_str_buf() {
let mut index = Index::new();
let stream = Stream::new(SRC.as_bytes(), IndexRef::Direct(&mut index));
let mut reader = BufReader::new(stream);
let mut buf = String::new();
reader.read_to_string(&mut buf).unwrap();
let ans = reader.get_ref().get_index().query().locate(Offset(20));
assert!(ans.is_some());
assert_eq!(ans.unwrap(), (2, 5).into());
}
#[test]
fn test_stream_str_drain() {
let mut index = Index::new();
let mut stream = Stream::new(SRC.as_bytes(), IndexRef::Direct(&mut index));
let mut buf = vec![b'\0'; 10];
stream.drain(&mut buf);
let ans = stream.get_index().query().locate(Offset(20));
assert!(ans.is_some());
assert_eq!(ans.unwrap(), (2, 5).into());
}
#[test]
fn test_stream_str_incremental() {
let mut index = Index::new();
let mut stream = Stream::new(SRC.as_bytes(), IndexRef::Direct(&mut index));
let mut buf = vec![b'\0'; 10];
let ans = stream.locate(Offset(20), &mut buf);
assert!(ans.is_ok());
assert_eq!(ans.unwrap(), (2, 5).into());
}
#[test]
fn test_stream_str_incremental_rc() {
let index = Index::new();
let index = Rc::new(RefCell::new(index));
let mut stream = Stream::new(SRC.as_bytes(), IndexRef::Shared(index.clone()));
let mut buf = vec![b'\0'; 10];
let ans = stream.locate(Offset(20), &mut buf);
assert!(ans.is_ok());
assert_eq!(ans.unwrap(), (2, 5).into());
let ans = index.borrow().query().locate(Offset(20));
assert!(ans.is_some());
assert_eq!(ans.unwrap(), (2, 5).into());
}
}