use std::fs::File;
use std::io::prelude::*;
pub struct Writer {
file: File,
}
impl Writer {
pub fn new(file: File) -> Writer {
Writer {
file: file
}
}
pub fn write(&mut self, content: &str, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.file.write_all(format!("{:width$}{}", "", content, width=(4 * indent)).as_bytes())?;
Ok(())
}
pub fn blank_line(&mut self) -> Result<(), Box<dyn std::error::Error>> {
self.write("\n", 0)
}
pub fn generate_use(&mut self, crate_name: &str, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.write(&format!(
"use {};\n",
crate_name
), indent)
}
pub fn generate_mod(&mut self, mod_name: &str, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.write(&format!(
"pub mod {};\n",
mod_name
), indent)
}
pub fn generate_typedef(&mut self, id: &str, var_type: &str, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.write(&format!(
"type {} = {};\n",
id,
var_type
), indent)
}
pub fn generate_close_block(&mut self, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.write("}\n", indent)
}
pub fn generate_enum_open(&mut self, id: &str, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.write(&format!(
"pub enum {} {{\n",
id
), indent)
}
pub fn generate_struct_open(&mut self, id: &str, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.write(&format!(
"pub struct {} {{\n",
id
), indent)
}
pub fn generate_trait_open(&mut self, id: &str, derived: Option<&str>, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.write(&format!("pub trait {}", id), indent)?;
if derived.is_some() {
self.write(&format!(" : {}", derived.unwrap()), 0)?;
}
self.write("{\n", 0)
}
pub fn generate_struct_member(&mut self, id: &str, vartype: &str, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.write(&format!(
"pub {}: {},\n",
id,
vartype
), indent)
}
pub fn generate_enum_variant(&mut self, id: &str, value: i32, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.write(&format!(
"{} = {},\n",
id,
value
), indent)
}
pub fn generate_impl(&mut self, impl_trait: Option<&str>, object: &str, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.write(&format!(
"impl {}{} {} {{\n",
if impl_trait.is_some() { impl_trait.unwrap() } else { "" },
if impl_trait.is_some() { " for" } else { "" },
object
), indent)
}
pub fn generate_fn(&mut self, public: bool, generic: Option<String>, fn_name: &str, arguments: Vec<String>, return_type: Option<&str>, is_impl: bool, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.write(&format!(
"{}fn {}",
if public { "pub " } else { "" },
fn_name
), indent)?;
if generic.is_some() {
self.write(&format!(
"<{}>",
generic.unwrap()
), 0)?;
}
self.write("(", 0)?;
self.write(&arguments.join(", "), 0)?;
self.write(")", 0)?;
if return_type.is_some() {
self.write(" -> ", 0)?;
self.write(return_type.unwrap(), 0)?;
}
if is_impl {
self.write(" {\n", 0)
} else {
self.write(";\n", 0)
}
}
pub fn generate_to_bytes_impl(&mut self, object: &str, lines: Vec<String>, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.generate_impl(Some("ToBytes"), object, indent)?;
self.generate_fn(false, None, "to_bytes", vec![String::from("&self")], Some("Result<Vec<u8>, Box<dyn std::error::Error>>"), true, indent + 1)?;
self.write("let mut bytes = Vec::new();\n", indent + 2)?;
for line in lines {
self.write(&line, indent + 2)?;
self.blank_line()?;
}
self.write("Ok(bytes)\n", indent + 2)?;
self.generate_close_block(1)?;
self.generate_close_block(0)?;
self.blank_line()
}
pub fn generate_from_bytes_impl(&mut self, object: &str, lines: Vec<String>, pre_read: Option<Vec<String>>, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.generate_impl(Some("FromBytes"), object, indent)?;
self.generate_fn(false, None, "from_bytes", vec![String::from("bytes: &[u8]"), String::from("read_bytes: &mut i32")], Some("Result<Self, Box<dyn std::error::Error>>"), true, indent + 1)?;
self.write("let mut read = 0;\n", indent + 2)?;
if pre_read.is_some() {
for item in pre_read.unwrap() {
self.write(&item, indent + 2)?;
self.blank_line()?;
}
}
self.write("let obj = Self{\n", indent + 2)?;
for line in lines {
self.write(&line, indent + 3)?;
self.blank_line()?;
}
self.write("};\n", indent + 2)?;
self.write("*read_bytes = *read_bytes + read;\n", indent + 2)?;
self.write("Ok(obj)\n", indent + 2)?;
self.generate_close_block(1)?;
self.generate_close_block(0)?;
self.blank_line()
}
pub fn generate_derive(&mut self, traits: Vec<&str>, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.write("#[derive(", indent)?;
self.write(&traits.join(", "), indent)?;
self.write(")]\n", indent)
}
pub fn generate_optional_type(&mut self, object: &str, result: u8, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
self.generate_impl(Some("OptionalType"), object, indent)?;
self.generate_fn(false, None, "optional_type", vec![], Some("u8"), true, indent + 1)?;
self.write(&format!("{}\n", result), indent + 2)?;
self.generate_close_block(indent + 1)?;
self.generate_close_block(indent)?;
self.blank_line()
}
}
pub fn write(file: &mut File, line: &str, indent: usize) -> Result<(), Box<dyn std::error::Error>> {
file.write_all(format!("{:width$}{}", "", line, width=(4 * indent)).as_bytes())?;
Ok(())
}