use std::cmp::min;
use std::convert::Infallible;
use std::fmt::Debug;
use std::fs::File;
use std::io::{self, Read};
pub trait Reader {
type Error: std::error::Error;
fn read_byte(&mut self) -> Result<Option<u8>, Self::Error>;
fn try_read_string(&mut self, s: &[u8], case_sensitive: bool) -> Result<bool, Self::Error>;
#[inline(always)]
fn read_until<'b>(
&'b mut self,
needle: &[u8],
char_buf: &'b mut [u8; 4],
) -> Result<Option<&'b [u8]>, Self::Error> {
let _ = needle;
match self.read_byte()? {
Some(x) => {
char_buf[0] = x;
Ok(Some(&char_buf[..1]))
}
None => Ok(None),
}
}
}
pub trait Readable<'a> {
type Reader: Reader + 'a;
fn to_reader(self) -> Self::Reader;
}
impl<'a, R: 'a + Reader> Readable<'a> for R {
type Reader = Self;
fn to_reader(self) -> Self::Reader {
self
}
}
#[derive(Debug)]
pub struct StringReader<'a> {
input: &'a [u8],
}
impl<'a> StringReader<'a> {
fn new(input: &'a [u8]) -> Self {
StringReader { input }
}
}
impl<'a> Reader for StringReader<'a> {
type Error = Infallible;
#[inline(always)]
fn read_byte(&mut self) -> Result<Option<u8>, Self::Error> {
if self.input.is_empty() {
Ok(None)
} else {
let rv = self.input[0];
self.input = &self.input[1..];
Ok(Some(rv))
}
}
#[inline(always)]
fn read_until<'b>(
&'b mut self,
needle: &[u8],
_: &'b mut [u8; 4],
) -> Result<Option<&'b [u8]>, Self::Error> {
if self.input.is_empty() {
return Ok(None);
}
if let Some(needle_pos) = fast_find(needle, self.input) {
if needle_pos == 0 {
let (rv, new_input) = self.input.split_at(1);
self.input = new_input;
Ok(Some(rv))
} else {
let (rv, new_input) = self.input.split_at(needle_pos);
self.input = new_input;
Ok(Some(rv))
}
} else {
let rv = self.input;
self.input = b"";
Ok(Some(rv))
}
}
#[inline(always)]
fn try_read_string(&mut self, s1: &[u8], case_sensitive: bool) -> Result<bool, Self::Error> {
if let Some(s2) = self.input.get(..s1.len()) {
if s1 == s2 || (!case_sensitive && s1.eq_ignore_ascii_case(s2)) {
self.input = &self.input[s1.len()..];
return Ok(true);
}
}
Ok(false)
}
}
impl<'a> Readable<'a> for &'a str {
type Reader = StringReader<'a>;
fn to_reader(self) -> Self::Reader {
StringReader::new(self.as_bytes())
}
}
impl<'a> Readable<'a> for &'a String {
type Reader = StringReader<'a>;
fn to_reader(self) -> Self::Reader {
StringReader::new(self.as_bytes())
}
}
impl<'a> Readable<'a> for &'a Vec<u8> {
type Reader = StringReader<'a>;
fn to_reader(self) -> Self::Reader {
StringReader::new(self.as_slice())
}
}
impl<'a> Readable<'a> for &'a [u8] {
type Reader = StringReader<'a>;
fn to_reader(self) -> Self::Reader {
StringReader::new(self)
}
}
#[derive(Debug)]
pub struct IoReader<R: Read, Buffer: AsRef<[u8]> + AsMut<[u8]> = Box<[u8]>> {
buf: Buffer,
read_cursor: usize,
write_cursor: usize,
reader: R,
}
impl<R: Read> IoReader<R> {
pub fn new(reader: R) -> Self {
Self::new_with_buffer_size::<16384>(reader)
}
pub fn new_with_buffer_size<const BUF_SIZE: usize>(reader: R) -> Self {
Self::new_with_buffer_impl(reader, Box::new([0; BUF_SIZE]))
}
}
impl<'a, R: Read> IoReader<R, &'a mut [u8]> {
pub fn new_with_buffer(reader: R, buf: &'a mut [u8]) -> Self {
Self::new_with_buffer_impl(reader, buf)
}
}
impl<R: Read, Buffer: AsRef<[u8]> + AsMut<[u8]>> IoReader<R, Buffer> {
fn new_with_buffer_impl(reader: R, buf: Buffer) -> Self {
IoReader {
buf,
read_cursor: 0,
write_cursor: 0,
reader,
}
}
#[inline(always)]
fn prepare_buf(&mut self, min_read_len: usize) -> Result<(), io::Error> {
let mut readable_len = self.write_cursor - self.read_cursor;
debug_assert!(min_read_len <= self.buf.as_mut().len());
debug_assert!(readable_len <= self.buf.as_mut().len());
if readable_len < min_read_len {
let mut raw_buf = &mut self.buf.as_mut()[..];
raw_buf.copy_within(self.read_cursor..self.write_cursor, 0);
raw_buf = &mut raw_buf[readable_len..];
while readable_len < min_read_len {
let n = self.reader.read(raw_buf)?;
if n == 0 {
break;
}
readable_len += n;
raw_buf = &mut raw_buf[n..];
}
self.write_cursor = readable_len;
self.read_cursor = 0;
}
Ok(())
}
}
impl<R: Read, Buffer: AsRef<[u8]> + AsMut<[u8]>> Reader for IoReader<R, Buffer> {
type Error = io::Error;
#[inline(always)]
fn read_byte(&mut self) -> Result<Option<u8>, Self::Error> {
self.prepare_buf(1)?;
if self.read_cursor == self.write_cursor {
return Ok(None);
}
let rv = self.buf.as_mut().get(self.read_cursor).copied();
if rv.is_some() {
self.read_cursor += 1;
}
Ok(rv)
}
#[inline(always)]
fn try_read_string(&mut self, s1: &[u8], case_sensitive: bool) -> Result<bool, Self::Error> {
debug_assert!(!s1.contains(&b'\r'));
debug_assert!(!s1.contains(&b'\n'));
self.prepare_buf(s1.len())?;
let s2 = &self.buf.as_mut()
[self.read_cursor..min(self.read_cursor + s1.len(), self.write_cursor)];
if s1 == s2 || (!case_sensitive && s1.eq_ignore_ascii_case(s2)) {
self.read_cursor += s1.len();
Ok(true)
} else {
Ok(false)
}
}
#[inline(always)]
fn read_until<'b>(
&'b mut self,
needle: &[u8],
_: &'b mut [u8; 4],
) -> Result<Option<&'b [u8]>, Self::Error> {
self.prepare_buf(4)?;
let buf = &self.buf.as_ref()[self.read_cursor..self.write_cursor];
if buf.is_empty() {
Ok(None)
} else if let Some(needle_pos) = fast_find(needle, buf) {
if needle_pos == 0 {
self.read_cursor += 1;
Ok(Some(&buf[..1]))
} else {
self.read_cursor += needle_pos;
Ok(Some(&buf[..needle_pos]))
}
} else {
self.read_cursor += buf.len();
Ok(Some(buf))
}
}
}
impl<'a> Readable<'a> for File {
type Reader = IoReader<File>;
fn to_reader(self) -> Self::Reader {
IoReader::new(self)
}
}
#[inline]
fn fast_find(needle: &[u8], haystack: &[u8]) -> Option<usize> {
#[cfg(feature = "jetscii")]
{
debug_assert!(needle.len() <= 16);
let mut needle_arr = [0; 16];
needle_arr[..needle.len()].copy_from_slice(needle);
#[allow(clippy::cast_possible_truncation, clippy::cast_possible_wrap)]
jetscii::Bytes::new(needle_arr, needle.len() as i32, |b| needle.contains(&b)).find(haystack)
}
#[cfg(not(feature = "jetscii"))]
haystack.iter().position(|b| needle.contains(b))
}