use std::fmt::Debug;
fn main() -> Result<(), impl Debug> {
#[cfg(feature = "generate")]
{
let child = std::thread::Builder::new()
.stack_size(32 * 1024 * 1024)
.spawn(generate_code)?;
child.join().expect("did not panic")?;
Result::<_, xsd_parser::Error>::Ok(())
}
#[cfg(not(feature = "generate"))]
Result::<_, std::convert::Infallible>::Ok(())
}
#[cfg(feature = "generate")]
fn generate_code() -> Result<(), xsd_parser::Error> {
use xsd_parser::config::{Namespace, RendererFlags};
use xsd_parser::{
Config,
config::{GeneratorFlags, InterpreterFlags, OptimizerFlags, RenderStep, Schema},
generate,
};
let schema_path =
std::env::var("OPEN_PLC_SCHEMA_PATH").expect("you must provide the path to the schema");
let mut config = Config::default();
config.parser.schemas = vec![Schema::File(schema_path.into())];
config.interpreter.flags = InterpreterFlags::all();
config.optimizer.flags = OptimizerFlags::all();
config.generator.flags = GeneratorFlags::all();
config.renderer.flags = RendererFlags::all();
config.generator.any_type = Some("xsd_parser::xml::AnyElement".into());
config.generator.any_attribute_type = Some("xsd_parser::xml::AnyAttributes".into());
let config = config.with_render_steps([
RenderStep::Types,
RenderStep::Defaults,
RenderStep::NamespaceConstants,
RenderStep::QuickXmlDeserialize {
boxed_deserializer: true,
},
RenderStep::QuickXmlSerialize {
with_namespaces: true,
default_namespace: Some(Namespace::new_const(b"http://www.plcopen.org/xml/tc6_0201")),
},
]);
let code = generate(config)?;
let code = code.to_string();
let code = rustfmt_pretty_print(code).unwrap();
let mut file = std::fs::File::create("src/schema.rs")?;
use std::io::Write;
file.write_all(code.to_string().as_bytes())?;
Ok(())
}
#[cfg(feature = "generate")]
pub fn rustfmt_pretty_print(code: String) -> Result<String, std::io::Error> {
use std::io::Write;
use std::process::{Command, Output, Stdio};
let mut child = Command::new("rustfmt")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.stderr(Stdio::piped())
.spawn()?;
let mut stdin = child.stdin.take().unwrap();
write!(stdin, "{code}")?;
stdin.flush()?;
drop(stdin);
let Output {
status,
stdout,
stderr,
} = child.wait_with_output()?;
let stdout = String::from_utf8_lossy(&stdout);
let stderr = String::from_utf8_lossy(&stderr);
if !status.success() {
let code = status.code();
match code {
Some(code) => {
if code != 0 {
panic!("The `rustfmt` command failed with return code {code}!\n{stderr}");
}
}
None => {
panic!("The `rustfmt` command failed!\n{stderr}")
}
}
}
Ok(stdout.into())
}