#![allow(clippy::expect_used, clippy::unwrap_used, clippy::panic)]
use std::path::PathBuf;
use zerodds_ast::facet::Extensibility;
use zerodds_ast::{Ast, TypeKind, TypeNode};
use zerodds_ast_core::Id;
use zerodds_ast_layout::key::{Encoding, Endianness, LayoutKey};
use zerodds_lang_rules::adapter::cst::{nest_by_module, rust_item_pairs};
use zerodds_lang_rules::encode::{rust_codec, rust_codec_pair};
use zerodds_lang_rules::rule::rust;
use zerodds_lang_rules::{ModelGraph, apply};
fn encoding_for(ast: &Ast, id: Id<TypeNode>) -> Encoding {
match ast.effective_extensibility(id) {
Extensibility::Final => Encoding::PlainCdr2,
Extensibility::Appendable => Encoding::DelimitedCdr,
Extensibility::Mutable => Encoding::PlCdr2,
}
}
fn xcdr1_encoding_for(ast: &Ast, id: Id<TypeNode>) -> Encoding {
match ast.effective_extensibility(id) {
Extensibility::Final | Extensibility::Appendable => Encoding::PlainCdr1,
Extensibility::Mutable => Encoding::PlCdr1,
}
}
fn main() {
println!("cargo:rerun-if-changed=idl/ros_msgs.idl");
println!("cargo:rerun-if-changed=build.rs");
let idl = std::fs::read_to_string("idl/ros_msgs.idl").expect("read ros_msgs.idl");
let dialect = zerodds_idl_parse::Dialect {
ros2: true,
..zerodds_idl_parse::Dialect::ALL_VENDORS
};
let parsed = zerodds_idl_parse::parse_with(&idl, dialect);
assert!(
parsed.diagnostics().is_empty(),
"the ROS message IDL must parse: {:?}",
parsed.diagnostics()
);
let lowered = zerodds_idl_lower::lower_with(
&parsed.syntax(),
"ros_msgs.idl",
zerodds_idl_lower::Options {
dialect,
..zerodds_idl_lower::Options::default()
},
);
assert!(
lowered.diagnostics.iter().all(|d| !d.is_error()),
"the ROS message IDL must lower: {:?}",
lowered
.diagnostics
.iter()
.filter(|d| d.is_error())
.collect::<Vec<_>>()
);
let mut ast = lowered.ast;
let report = ast.resolve_all_by_name().expect("a resolve pass");
assert!(
report.broken.is_empty(),
"every name in the ROS message IDL must resolve: {:?}",
report.broken
);
let graph = ModelGraph::of(&ast);
let applied = apply(&graph, &rust::catalogue()).expect("apply the Rust rules");
let mut pairs = rust_item_pairs(&ast, &applied).expect("materialise the ROS message types");
for (id, node) in ast.types() {
if node.name.is_empty() {
continue;
}
if !matches!(
node.kind,
TypeKind::Structure { .. }
| TypeKind::Union { .. }
| TypeKind::Enumeration { .. }
| TypeKind::Bitmask { .. }
| TypeKind::Bitset { .. }
) {
continue;
}
let key = LayoutKey::data(encoding_for(&ast, id), Endianness::Little);
for item in rust_codec(&ast, id, key).expect("a codec for every declared ROS type") {
pairs.push((node.module, item));
}
let v1 = LayoutKey::data(xcdr1_encoding_for(&ast, id), Endianness::Little);
for item in rust_codec_pair(&ast, id, v1).expect("an XCDR1 codec for every ROS type") {
pairs.push((node.module, item));
}
}
let items = nest_by_module(&ast, pairs).expect("a scope for every declaration");
let file = zerodds_lang_cst::rust::File {
inner_attrs: Vec::new(),
doc: zerodds_lang_cst::common::Doc::lines(&[
"Generated by zerodds-lang-rules from idl/ros_msgs.idl.",
"",
"Do not edit: the point of this file is that nobody did.",
]),
uses: vec![zerodds_lang_cst::rust::Use {
path: zerodds_lang_cst::common::Path::single("zerodds_wire"),
names: vec![
zerodds_lang_cst::common::Ident::new("Narrowed"),
zerodds_lang_cst::common::Ident::new("Reader"),
zerodds_lang_cst::common::Ident::new("TryConstruct"),
zerodds_lang_cst::common::Ident::new("WireError"),
zerodds_lang_cst::common::Ident::new("Writer"),
],
visibility: zerodds_lang_cst::common::Visibility::Private,
}],
items,
};
let out = PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR")).join("ros_msgs.rs");
std::fs::write(&out, zerodds_lang_render::rust::file(&file))
.expect("write the generated module");
}