use {
base64::{engine::general_purpose::*, write::*},
std::io::{self, BufRead, Write},
};
const COMMAND_START: &str = "\x1b_G";
const COMMAND_END: &str = "\x1b\\";
const COMMAND_END_FIRST: u8 = b'\x1b';
const COMMAND_END_REST: &str = "\\";
pub trait KittyWriter: Sized {
fn write_start(&mut self) -> io::Result<()>;
fn write_end(&mut self) -> io::Result<()>;
fn write_base64(self, data: &[u8]) -> io::Result<Self>;
}
impl<WriteT> KittyWriter for WriteT
where
WriteT: io::Write,
{
fn write_start(&mut self) -> io::Result<()> {
write!(self, "{}", COMMAND_START)
}
fn write_end(&mut self) -> io::Result<()> {
write!(self, "{}", COMMAND_END)?;
self.flush()
}
fn write_base64(self, data: &[u8]) -> io::Result<Self> {
let mut encoder = EncoderWriter::new(self, &STANDARD);
encoder.write_all(data)?;
encoder.finish()
}
}
#[allow(unused)]
pub trait KittyReader {
fn read_response(&mut self) -> io::Result<Option<Vec<u8>>>;
}
impl<ReadT> KittyReader for ReadT
where
ReadT: io::Read,
{
fn read_response(&mut self) -> io::Result<Option<Vec<u8>>> {
let mut buffer = vec![0; COMMAND_START.len()];
self.read_exact(&mut buffer)?;
if buffer == COMMAND_START.as_bytes() {
let mut response = Vec::default();
let mut reader = io::BufReader::new(self);
reader.read_until(COMMAND_END_FIRST, &mut response)?;
let reader = reader.into_inner();
let mut buffer = vec![0; COMMAND_END_REST.len()];
reader.read_exact(&mut buffer)?;
if buffer == COMMAND_END_REST.as_bytes() {
response.pop(); return Ok(Some(response));
}
}
Ok(None)
}
}