use std::{ fs::{self, File}, io::{BufRead, BufReader}, path::Path, }; pub fn main() { let proto_file = "nap.proto"; if Path::new(&proto_file).exists() { println!("cargo:rerun-if-changed={proto_file}"); let _ = fs::create_dir("out/"); prost_build::Config::new() .out_dir("out/") .type_attribute(".", "#[derive(proto_gen::CmdID)]") .type_attribute(".", "#[derive(proto_gen::XorFields)]") .compile_protos(&[proto_file], &["."]) .unwrap(); apply_xor(Path::new("out/_.rs")).unwrap(); } let proto_file = "bin.server.proto"; if Path::new(&proto_file).exists() { println!("cargo:rerun-if-changed={proto_file}"); let _ = fs::create_dir("out/"); prost_build::Config::new() .out_dir("out/") .compile_protos(&[proto_file], &["bin"]) .unwrap(); } } fn apply_xor(path: &Path) -> std::io::Result<()> { let file = File::open(path)?; let reader = BufReader::new(file); let mut output = Vec::new(); let mut cmd_id_attr = None; for line in reader.lines() { let line = line?; if line.contains("xor const: ") { if !line.contains("xor const: 0") { output.push(make_xor_attr(&line).unwrap()); } } else if line.contains("CmdID: ") { cmd_id_attr = Some(make_cmd_id_attr(&line).unwrap()); } else { output.push(line); if let Some(attr) = cmd_id_attr.take() { output.push(attr); } } } fs::write(path, output.join("\n").as_bytes())?; Ok(()) } fn make_xor_attr(line: &str) -> Option { let xor_value = line.split("xor const: ").nth(1)?.parse::().ok()?; Some(format!(" #[xor({xor_value})]")) } fn make_cmd_id_attr(line: &str) -> Option { let cmd_id = line.split("CmdID: ").nth(1)?.parse::().ok()?; Some(format!("#[cmdid({cmd_id})]")) }