use super::encoder::EncoderWriter;
use crate::Config;
use std::io;
use std::io::Write;
pub struct EncoderStringWriter<S: StrConsumer> {
encoder: EncoderWriter<Utf8SingleCodeUnitWriter<S>>,
}
impl<S: StrConsumer> EncoderStringWriter<S> {
pub fn from(str_consumer: S, config: Config) -> Self {
EncoderStringWriter {
encoder: EncoderWriter::new(Utf8SingleCodeUnitWriter { str_consumer }, config),
}
}
pub fn into_inner(mut self) -> S {
self.encoder
.finish()
.expect("Writing to a Vec<u8> should never fail")
.str_consumer
}
}
impl EncoderStringWriter<String> {
pub fn new(config: Config) -> Self {
EncoderStringWriter::from(String::new(), config)
}
}
impl<S: StrConsumer> Write for EncoderStringWriter<S> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.encoder.write(buf)
}
fn flush(&mut self) -> io::Result<()> {
self.encoder.flush()
}
}
pub trait StrConsumer {
fn consume(&mut self, buf: &str);
}
impl<S: StrConsumer + ?Sized> StrConsumer for &mut S {
fn consume(&mut self, buf: &str) {
(**self).consume(buf)
}
}
impl StrConsumer for String {
fn consume(&mut self, buf: &str) {
self.push_str(buf)
}
}
struct Utf8SingleCodeUnitWriter<S: StrConsumer> {
str_consumer: S,
}
impl<S: StrConsumer> io::Write for Utf8SingleCodeUnitWriter<S> {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let s = std::str::from_utf8(buf).expect("Input must be valid UTF-8");
self.str_consumer.consume(s);
Ok(buf.len())
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
#[cfg(test)]
mod tests {
use crate::encode_config_buf;
use crate::tests::random_config;
use crate::write::encoder_string_writer::EncoderStringWriter;
use rand::Rng;
use std::io::Write;
#[test]
fn every_possible_split_of_input() {
let mut rng = rand::thread_rng();
let mut orig_data = Vec::<u8>::new();
let mut normal_encoded = String::new();
let size = 5_000;
for i in 0..size {
orig_data.clear();
normal_encoded.clear();
for _ in 0..size {
orig_data.push(rng.gen());
}
let config = random_config(&mut rng);
encode_config_buf(&orig_data, config, &mut normal_encoded);
let mut stream_encoder = EncoderStringWriter::new(config);
stream_encoder.write_all(&orig_data[0..i]).unwrap();
stream_encoder.write_all(&orig_data[i..]).unwrap();
let stream_encoded = stream_encoder.into_inner();
assert_eq!(normal_encoded, stream_encoded);
}
}
}