#![forbid(unsafe_code)]
#![allow(clippy::print_stderr, clippy::print_stdout, clippy::exit)]
use std::path::PathBuf;
use zerodds_wire_probe::ProbeError;
use zerodds_wire_probe::corba_idl::{corba_idl, cpp_name, java_name};
use zerodds_wire_probe::encode::model_from_idl;
const USAGE: &str = "\
wireprobe-corba-idl — one corpus type, printed as CORBA IDL
--idl <file> the IDL source
--type <ScopedName> the top-level type
--out <file> where the IDL goes (default: stdout)
--print-cpp-name print the C++ name of --type and stop
--print-java-name print the Java name of --type and stop
";
const NOT_FILLED: i32 = 6;
const GENERATOR_DEFECT: i32 = 7;
const MAPPING_DIVERGENCE: i32 = 8;
fn main() {
let argv: Vec<String> = std::env::args().skip(1).collect();
match run(&argv) {
Ok(()) => {}
Err(Failure::GeneratorDefect(message)) => {
eprintln!("wireprobe-corba-idl: {message}");
std::process::exit(GENERATOR_DEFECT);
}
Err(Failure::MappingDivergence(message)) => {
eprintln!("wireprobe-corba-idl: {message}");
std::process::exit(MAPPING_DIVERGENCE);
}
Err(Failure::Usage(message)) => {
eprintln!("{message}\n\n{USAGE}");
std::process::exit(1);
}
Err(Failure::NoCorbaForm(message)) => {
eprintln!("wireprobe-corba-idl: {message}");
std::process::exit(3);
}
Err(Failure::NotFilled(message)) => {
eprintln!("wireprobe-corba-idl: {message}");
std::process::exit(NOT_FILLED);
}
}
}
enum Failure {
GeneratorDefect(String),
MappingDivergence(String),
Usage(String),
NoCorbaForm(String),
NotFilled(String),
}
impl From<String> for Failure {
fn from(message: String) -> Self {
Self::Usage(message)
}
}
fn run(argv: &[String]) -> Result<(), Failure> {
let mut idl = None;
let mut type_name = None;
let mut out: Option<PathBuf> = None;
let mut print_cpp = false;
let mut print_java = false;
let mut index = 0;
while index < argv.len() {
let flag = &argv[index];
let value = || {
argv.get(index + 1)
.cloned()
.ok_or_else(|| format!("`{flag}` takes a value"))
};
match flag.as_str() {
"--idl" => {
idl = Some(PathBuf::from(value()?));
index += 2;
}
"--type" => {
type_name = Some(value()?);
index += 2;
}
"--out" => {
out = Some(PathBuf::from(value()?));
index += 2;
}
"--print-cpp-name" => {
print_cpp = true;
index += 1;
}
"--print-java-name" => {
print_java = true;
index += 1;
}
"--help" | "-h" => {
println!("{USAGE}");
return Ok(());
}
other => return Err(format!("`{other}` is not an option").into()),
}
}
let idl = idl.ok_or_else(|| String::from("--idl is required"))?;
let type_name = type_name.ok_or_else(|| String::from("--type is required"))?;
let source =
std::fs::read_to_string(&idl).map_err(|error| format!("{}: {error}", idl.display()))?;
let ast = model_from_idl(&source, &idl.display().to_string())
.map_err(|error| format!("{}: {error}", idl.display()))?;
let segments: Vec<String> = type_name
.split("::")
.filter(|segment| !segment.is_empty())
.map(std::string::ToString::to_string)
.collect();
let type_ = ast
.find_by_scoped_name(&zerodds_ast_core::ScopedName::absolute(segments))
.ok()
.and_then(zerodds_ast::AnyId::as_type)
.ok_or_else(|| format!("`{type_name}` is not in the model"))?;
if print_cpp {
println!("{}", cpp_name(&ast, type_));
return Ok(());
}
if print_java {
println!("{}", java_name(&ast, type_));
return Ok(());
}
let text = corba_idl(&ast, type_).map_err(|error| match error {
ProbeError::Unfilled { .. } => Failure::NotFilled(format!("{error}")),
ProbeError::GeneratorDefect { .. } => Failure::GeneratorDefect(format!("{error}")),
ProbeError::MappingDivergence { .. } => Failure::MappingDivergence(format!("{error}")),
other => Failure::NoCorbaForm(format!("{other}")),
})?;
match out {
Some(path) => std::fs::write(&path, text)
.map_err(|error| format!("{}: {error}", path.display()).into()),
None => {
print!("{text}");
Ok(())
}
}
}