use std::{
io::{ BufRead, BufReader, BufWriter, Error, Lines, Read, Write },
iter::{ Filter, FusedIterator, Peekable },
};
use crate::decode_instruction;
pub struct Disassembler<'a, R: Read, W: Write> {
writer: Option<BufWriter<Box<&'a mut W>>>,
lines: Peekable<Filter<Lines<BufReader<&'a mut R>>, fn(&Result<String, Error>) -> bool>>,
}
pub struct DisassemblerConfig<'a, R: Read, W: Write> {
pub reader: &'a mut R,
pub writer: Option<&'a mut W>,
}
impl<'a, R, W> Disassembler<'a, R, W> where R: Read, W: Write {
pub fn new(args: DisassemblerConfig<'a, R, W>) -> Disassembler<'a, R, W> {
let DisassemblerConfig { reader, writer } = args;
let filter: fn(&Result<String, Error>) -> bool = |line: &Result<String, Error>| {
line.is_ok() && !line.as_ref().unwrap().is_empty()
};
let lines: Peekable<
Filter<Lines<BufReader<&mut R>>, fn(&Result<String, Error>) -> bool>
> = BufReader::new(reader).lines().filter(filter).peekable();
let writer = match writer {
Some(file) => Some(BufWriter::new(Box::new(file))),
None => None,
};
Disassembler {
writer,
lines,
}
}
fn has_next(&mut self) -> bool {
self.lines.peek().is_some()
}
pub fn get_next(&mut self) -> Option<String> {
let out: Option<String> = {
if !self.has_next() {
return None;
}
let line = self.lines.next().unwrap();
if let Err(err) = line {
eprintln!("Error reading line: {}", err);
None
} else {
let instruction = match decode_instruction(line.unwrap().trim()) {
Ok(decoded) => decoded,
Err(err) => {
eprintln!("Error decoding instruction: {}", err);
return None;
}
};
Some(instruction)
}
};
out
}
pub fn get_to_end(&mut self) -> Option<String> {
let mut buffer = String::new();
while let Some(line) = self.lines.next() {
let instruction = match decode_instruction(line.unwrap().trim()) {
Ok(decoded) => decoded,
Err(err) => {
eprintln!("Error decoding instruction: {}", err);
continue;
}
};
buffer.push_str(&instruction);
buffer.push('\n');
}
match buffer.is_empty() {
true => None,
false => Some(buffer),
}
}
pub fn write_next(&mut self) -> Result<(), Error> {
let out = self.get_next();
if out.is_some() {
self.write_to_output(out.as_ref().unwrap())?;
return Ok(());
} else {
return Err(Error::new(std::io::ErrorKind::Other, "No more lines to disassemble"));
}
}
pub fn write_to_end(&mut self) -> Result<(), Error> {
let out = self.get_to_end();
if out.is_some() {
let out = out.unwrap();
self.write_to_output(out.as_ref())?;
return Ok(());
} else {
return Err(Error::new(std::io::ErrorKind::Other, "No more lines to disassemble"));
}
}
pub fn get_and_write_next(&mut self) -> Result<Option<String>, Error> {
let out = self.get_next();
if let Some(instruction) = &out {
self.write_to_output(instruction)?;
return Ok(out);
} else {
return Ok(None);
}
}
pub fn get_and_write_to_end(&mut self) -> Result<Option<String>, Error> {
let out = self.get_to_end();
if out.is_some() {
let out = out.unwrap();
self.write_to_output(out.as_ref())?;
return Ok(Some(out));
} else {
return Ok(None);
}
}
fn write_to_output(&mut self, contents: &str) -> Result<(), Error> {
if let Some(writer) = self.writer.as_mut() {
if let Err(error) = write!(writer, "{}\n", contents.trim()) {
eprintln!("Error writing to output: {}", error);
return Err(error);
}
writer.flush().unwrap();
return Ok(());
} else {
return Err(Error::new(std::io::ErrorKind::NotFound, "No writeable output specified"));
}
}
}
impl<'a, R, W> Iterator for Disassembler<'a, R, W> where R: Read + 'a, W: Write + 'a {
type Item = String;
fn next(&mut self) -> Option<Self::Item> {
self.get_next()
}
}
impl<'a, R, W> FusedIterator for Disassembler<'a, R, W> where R: Read + 'a, W: Write + 'a {}