use proc_macro::TokenStream; use quote::quote; /// Entry point for `gen_program!()`. /// /// Generates the `Next` type alias, `Routable` impl for `ChainProcess`, /// and delegates to `program_comp_gen!()`, `program_fallback_gen!()`, /// and `program_final_gen!()`. pub(crate) fn gen_program_impl(_input: TokenStream) -> TokenStream { #[cfg(feature = "comp")] let comp_gen = quote! { ::mingling::macros::program_comp_gen!(); }; #[cfg(not(feature = "comp"))] let comp_gen = quote! {}; // When pathf is enabled, load the type_using.rs generated by the build script // and emit its use statements so types from submodules are in scope. #[cfg(feature = "pathf")] let pathf_uses: Vec = { let uses = load_pathf_uses(); if uses.is_empty() { // The file might not exist yet — emit a clear hint let hint: proc_macro2::TokenStream = syn::parse_quote! { compile_error!( "pathf: `{}` not found or empty.\n\ Make sure `build.rs` calls `mingling::build::analyze_and_build_type_mapping().unwrap();`\n\ with features [\"build\", \"pathf\"] enabled." ); }; vec![hint] } else { uses } }; #[cfg(not(feature = "pathf"))] let pathf_uses: Vec = Vec::new(); #[cfg(feature = "pathf")] let super_use = quote! {}; #[cfg(not(feature = "pathf"))] let super_use = quote! { use super::*; }; TokenStream::from(quote! { pub use __this_program_impl::*; #[doc(hidden)] pub mod __this_program_impl { #super_use #(#pathf_uses)* /// Alias for the current program type `ThisProgram` pub type Next = ::mingling::ChainProcess; ::mingling::macros::pack!(Entry = Vec); impl ::mingling::Routable for ::mingling::ChainProcess { fn to_chain(self) -> ::mingling::ChainProcess { match self { ::mingling::ChainProcess::Ok((any, _)) => { ::mingling::ChainProcess::Ok((any, mingling::NextProcess::Chain)) } other => other, } } fn to_render(self) -> ::mingling::ChainProcess { match self { ::mingling::ChainProcess::Ok((any, _)) => { ::mingling::ChainProcess::Ok((any, mingling::NextProcess::Renderer)) } other => other, } } } #comp_gen ::mingling::macros::program_fallback_gen!(); ::mingling::macros::program_final_gen!(); } }) } /// Loads `type_using.rs` generated by the pathf build script and returns each /// `use ...;` line as a token stream, ready to be emitted in the generated output. #[cfg(feature = "pathf")] fn load_pathf_uses() -> Vec { let out_dir = match std::env::var("OUT_DIR") { Ok(d) => d, Err(_) => return Vec::new(), }; let crate_name = match std::env::var("CARGO_PKG_NAME") { Ok(n) => n, Err(_) => return Vec::new(), }; let path = std::path::Path::new(&out_dir) .join(&crate_name) .join("type_using.rs"); let content = match std::fs::read_to_string(&path) { Ok(c) => c, Err(_) => return Vec::new(), }; content .lines() .map(|line| line.trim().to_string()) .filter(|line| !line.is_empty()) .filter_map(|line| line.parse::().ok()) .collect() }