#![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;
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 main() {
println!("cargo:rerun-if-changed=idl/spatial_core.idl");
println!("cargo:rerun-if-changed=build.rs");
let idl = std::fs::read_to_string("idl/spatial_core.idl").expect("read spatial_core.idl");
let parsed = zerodds_idl_parse::parse(&idl);
assert!(
parsed.diagnostics().is_empty(),
"the SpatialDDS IDL must parse: {:?}",
parsed.diagnostics()
);
let lowered = zerodds_idl_lower::lower(&parsed.syntax(), "spatial_core.idl");
assert!(
lowered.diagnostics.iter().all(|d| !d.is_error()),
"the SpatialDDS 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 SpatialDDS 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 SpatialDDS 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 SpatialDDS 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/spatial_core.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 rendered = zerodds_lang_render::rust::file(&file);
let out = PathBuf::from(std::env::var("OUT_DIR").expect("OUT_DIR")).join("spatial_core.rs");
std::fs::write(&out, rendered).expect("write the generated module");
}