#![allow(unused_extern_crates)]
#[cfg(feature = "from-spec")]
extern crate handlebars;
#[cfg(feature = "from-spec")]
#[macro_use]
extern crate lazy_static;
#[cfg(feature = "from-spec")]
extern crate serde;
#[cfg(feature = "from-spec")]
#[macro_use]
extern crate serde_derive;
#[cfg(feature = "from-spec")]
extern crate regex;
#[cfg(feature = "from-spec")]
extern crate serde_json;
#[cfg(feature = "from-spec")]
mod codegen;
fn main() {
#[cfg(feature = "from-spec")]
{
generate_from_spec();
}
}
#[cfg(feature = "from-spec")]
fn generate_from_spec() {
use handlebars::{
Context, Handlebars, Helper, Output, RenderContext, RenderError, RenderErrorReason,
};
use std::env;
use std::fs::File;
use std::io::Write;
let template = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/codegen/definitions.rs"
));
let spec = include_str!(concat!(
env!("CARGO_MANIFEST_DIR"),
"/codegen/specification.json"
));
let out_dir = env::var("CARGO_MANIFEST_DIR").expect("CARGO_MANIFEST_DIR is not defined")
+ "/src/protocol/";
let definitions = codegen::parse(spec);
let mut codegen = Handlebars::new();
codegen.register_helper(
"snake",
Box::new(
|h: &Helper<'_>,
_: &Handlebars<'_>,
_: &Context,
_rc: &mut RenderContext<'_, '_>,
out: &mut dyn Output|
-> Result<(), RenderError> {
let value = h.param(0).ok_or_else(|| {
RenderErrorReason::ParamNotFoundForName(
"Param not found for helper",
"snake".to_string(),
)
})?;
let param = value.value().as_str().ok_or_else(|| {
RenderErrorReason::ParamNotFoundForName(
"Param not found for helper",
"snake".to_string(),
)
})?;
out.write(&codegen::snake_case(param))?;
Ok(())
},
),
);
codegen
.register_template_string("definitions", template)
.expect("Failed to register template.");
let mut data = std::collections::BTreeMap::new();
data.insert("defs", definitions);
let def_path = std::path::Path::new(&out_dir).join("definitions.rs");
{
let mut f = File::create(def_path.clone()).expect("Failed to create target file.");
let rendered = codegen
.render("definitions", &data)
.expect("Failed to render template.");
writeln!(f, "{}", rendered).expect("Failed to write to file.");
}
reformat_file(&def_path);
fn reformat_file(path: &std::path::Path) {
use std::fs::OpenOptions;
use std::io::{Read, Seek};
std::process::Command::new("rustfmt")
.arg(path.to_str().unwrap())
.output()
.expect("failed to format definitions.rs");
let mut f = OpenOptions::new()
.read(true)
.write(true)
.open(path)
.expect("failed to open file");
let mut data = String::new();
f.read_to_string(&mut data).expect("failed to read file.");
let regex = regex::Regex::new("(?P<a>[\r]?\n)[\\s]*\r?\n").unwrap();
data = regex.replace_all(&data, "$a").into();
f.seek(std::io::SeekFrom::Start(0)).unwrap();
f.set_len(data.len() as u64).unwrap();
f.write_all(data.as_bytes())
.expect("Error writing reformatted file");
}
}