1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
|
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<proc_macro2::TokenStream> = {
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<proc_macro2::TokenStream> = 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<ThisProgram>;
::mingling::macros::pack!(Entry = Vec<String>);
impl ::mingling::Routable<ThisProgram> for ::mingling::ChainProcess<ThisProgram>
{
fn to_chain(self) -> ::mingling::ChainProcess<ThisProgram> {
match self {
::mingling::ChainProcess::Ok((any, _)) => {
::mingling::ChainProcess::Ok((any, mingling::NextProcess::Chain))
}
other => other,
}
}
fn to_render(self) -> ::mingling::ChainProcess<ThisProgram> {
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<proc_macro2::TokenStream> {
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::<proc_macro2::TokenStream>().ok())
.collect()
}
|