use std::io::{self, BufReader, BufWriter};
use std::collections::VecDeque;
use super::prelude::*;
struct CesuEncoder(StreamState);
struct CesuDecoder(StreamState);
struct MutfEncoder(StreamState);
struct MutfDecoder(StreamState);
struct StreamState {
buffer: VecDeque<u8>,
invalid_end: usize,
}
trait StreamConfig
where
for<'b> &'b Self::BaseStr: TryFrom<&'b [u8], Error = super::EncodingError>
{
type BaseStr: ?Sized;
fn state(&mut self) -> &mut StreamState;
fn try_append_chunk(&mut self, chunk: &[u8]) -> io::Result<usize> {
let state = self.state();
let orig_len = state.buffer.len();
state.buffer.extend(chunk);
let contents = state.buffer.make_contiguous();
match <&Self::BaseStr>::try_from(&contents[orig_len..]) {
Ok(_) => {
state.invalid_end = 0;
Ok(chunk.len()) },
Err(e) => {
let invalid_at = orig_len + e.valid_up_to();
match e.error_len() {
None => {
state.invalid_end = contents.len() - e.valid_up_to();
Ok(chunk.len()) },
Some(_) if invalid_at == 0 => {
state.buffer.truncate(orig_len);
Err(io::Error::new(io::ErrorKind::InvalidData, e))
},
Some(_) => {
state.buffer.truncate(e.valid_up_to());
let wrote = state.buffer.len() - orig_len;
Ok(wrote)
}
}
}
}
}
}
impl StreamConfig for CesuEncoder {
type BaseStr = Cesu8Str;
fn state(&mut self) -> &mut StreamState {
&mut self.0
}
}
impl StreamConfig for MutfEncoder {
type BaseStr = Mutf8Str;
fn state(&mut self) -> &mut StreamState {
&mut self.0
}
}
impl io::Write for CesuEncoder {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.try_append_chunk(buf)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl io::Read for CesuEncoder {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let state = self.state();
let valid = state.buffer.len() - state.invalid_end;
let cesu = state.buffer.make_contiguous();
let cesu = Cesu8Str::try_from_bytes(&cesu[..valid]).unwrap();
let utf8 = cesu.to_str();
let safe_len = utf8.floor_char_boundary(buf.len());
buf[..safe_len].copy_from_slice(&utf8.as_bytes()[..safe_len]);
let unused_utf8_chars = utf8[safe_len..].chars().count();
todo!("figure out how to subtract characters (not code points) from the end of a string");
Ok(safe_len)
}
}