Skip to main content

codegen/
gen_barrel.rs

1use anyhow::Context as _;
2use quote::{format_ident, quote};
3
4use crate::rust_source::{FileComment, render_rust, rust_ident};
5
6const GENERATED_BANNER: &str = "@generated by codegen-cli -- do not edit by hand.";
7
8/// Emit the top-level `generated/mod.rs`.
9pub(crate) fn generate_top_mod() -> anyhow::Result<String> {
10    let lint_level = format_ident!("allow");
11
12    render_rust(
13        quote! {
14            #![#lint_level(
15                dead_code,
16                clippy::allow_attributes_without_reason,
17                clippy::doc_markdown,
18                clippy::fn_to_numeric_cast_any,
19                clippy::must_use_candidate,
20                clippy::needless_pass_by_value,
21                reason = "generated bindings preserve manifest names and registry ABI shapes"
22            )]
23
24            pub(crate) mod items;
25            pub(crate) mod shared;
26            pub(crate) mod specs;
27        },
28        &[FileComment::inner_doc(GENERATED_BANNER)?],
29    )
30    .context("rendering top-level generated module")
31}
32
33/// Emits a module containing generated shared-manifest binding modules.
34pub(crate) fn generate_shared_mod(module_names: &[String]) -> anyhow::Result<String> {
35    let mut sorted_names = module_names.to_vec();
36
37    sorted_names.sort();
38
39    let modules = sorted_names
40        .iter()
41        .map(|name| rust_ident(name))
42        .collect::<Result<Vec<_>, _>>()
43        .context("shared module name is not a Rust identifier")?;
44    let lint_level = format_ident!("allow");
45
46    render_rust(
47        quote! {
48            #![#lint_level(dead_code)]
49
50            #(pub(crate) mod #modules;)*
51        },
52        &[FileComment::inner_doc(GENERATED_BANNER)?],
53    )
54    .context("rendering shared generated module")
55}
56
57/// Emit `generated/specs/mod.rs`.
58pub(crate) fn generate_specs_mod(spec_names: &[String]) -> anyhow::Result<String> {
59    let mut sorted_names = spec_names.to_vec();
60
61    sorted_names.sort();
62
63    let modules = sorted_names
64        .iter()
65        .map(|name| rust_ident(name))
66        .collect::<Result<Vec<_>, _>>()
67        .context("spec module name is not a Rust identifier")?;
68    let descriptors = spec_names
69        .iter()
70        .map(|name| rust_ident(name))
71        .collect::<Result<Vec<_>, _>>()
72        .context("spec descriptor module name is not a Rust identifier")?;
73    let lint_level = format_ident!("allow");
74
75    render_rust(
76        quote! {
77            #![#lint_level(dead_code)]
78
79            #(pub(crate) mod #modules;)*
80
81            use wowlab_engine_ports::SpecDescriptor;
82
83            pub(crate) const SPEC_DESCRIPTORS: &[SpecDescriptor] = &[
84                #(#descriptors::SPEC_DESCRIPTOR,)*
85            ];
86
87            #[doc(hidden)]
88            #[inline(never)]
89            pub(crate) fn force_link_generated_specs() -> usize {
90                std::hint::black_box(SPEC_DESCRIPTORS.as_ptr() as usize)
91            }
92        },
93        &[FileComment::inner_doc(GENERATED_BANNER)?],
94    )
95    .context("rendering spec generated module")
96}