nichlink_run_method/macros/entry.rs
1//! Host entry, host onboarding, and graft-plan macros.
2//! 宿主入口、宿主接入与 graft 计划宏。
3
4/// Declare the single host entry used by source-scope discovery.
5/// 声明源码作用域发现使用的唯一宿主入口。
6#[macro_export]
7macro_rules! application {
8 (entry = $entry:path $(,)?) => {
9 #[doc(hidden)]
10 pub const NICHLINK_APPLICATION_ENTRY: &str = stringify!($entry);
11 };
12}
13
14/// Declare this crate as a NichLink host and pull in the registration plan
15/// captured at build time.
16/// 声明当前 crate 为 NichLink 宿主,并引入构建时捕获的注册计划。
17///
18/// `nichlink-build` renders the discovered registration tree to
19/// `OUT_DIR/generated_lib.rs`; this macro includes it at the crate root so
20/// `builtin_static_plan()` and the per-level `{name}_object!` aliases are
21/// available crate-wide. It expands to
22/// `include!(concat!(env!("OUT_DIR"), "/generated_lib.rs"))` — writing that
23/// line directly is an equivalent, advanced alternative.
24/// `nichlink-build` 把发现的注册树渲染到 `OUT_DIR/generated_lib.rs`;
25/// 此宏将其包含到 crate 根,使 `builtin_static_plan()` 与各层级的
26/// `{name}_object!` 别名在整个 crate 内可用。它展开为
27/// `include!(concat!(env!("OUT_DIR"), "/generated_lib.rs"))`,
28/// 直接书写该行是等价的高级写法。
29///
30/// `include!` only accepts a literal path, so the generated entry's file name
31/// cannot be read from the kernel lexicon here. Pinning the two texts together
32/// makes a drift a compile error instead of a host that includes a file the
33/// build step no longer writes.
34/// `include!` 只接受字面量路径,因此这里无法从内核 lexicon 读取生成入口的文件名。
35/// 把两份文本钉在一起,漂移会变成编译错误,而不是去 include 一个构建步骤已不再写的
36/// 文件。
37const _: () = assert!(::nichlink::lexicon::same_text(
38 ::nichlink::lexicon::GENERATED_LIB_FILE,
39 "generated_lib.rs"
40));
41
42/// Pull the build-time registration plan into the crate root.
43/// 把构建期捕获的注册计划引入 crate 根。
44///
45/// Call it once per host crate whose build script has run the NichLink build
46/// step; the included file supplies `builtin_static_plan()` and the per-level
47/// object aliases. The `include!` target lives under `OUT_DIR`, so a crate that
48/// never runs that step fails to compile rather than silently missing faces.
49/// 在已由 build script 运行 NichLink 构建步骤的宿主 crate 中调用一次;被包含的文件
50/// 提供 `builtin_static_plan()` 与各层级 object 别名。`include!` 目标位于 `OUT_DIR`,
51/// 未运行该步骤的 crate 会编译失败,而不是静默缺少注册面。
52#[macro_export]
53macro_rules! host {
54 () => {
55 include!(concat!(env!("OUT_DIR"), "/generated_lib.rs"));
56 };
57}
58
59/// Declare graft selectors for build-time capture without constructing a
60/// runtime `GraftPlan`.
61/// 声明供构建阶段捕获的 graft selector,不构造运行时 `GraftPlan`。
62///
63/// Put this at the host crate entry. `nichlink-build` validates the grammar and
64/// stores the cuts in the generated `StaticPlan`. Use the dynamic
65/// [`graft_plan!`](crate::graft_plan) expression only when code needs to build
66/// or edit a plan at runtime.
67/// 将它放在宿主 crate 入口。`nichlink-build` 校验语法并把切口写入生成的
68/// `StaticPlan`;只有运行时代码确实要构造或编辑计划时才使用动态
69/// [`graft_plan!`](crate::graft_plan) 表达式。
70#[macro_export]
71macro_rules! static_graft_plan {
72 ($framework:expr, $($cuts:tt)+) => {
73 const _: $crate::FrameworkId = $framework;
74 const _: &str = stringify!($($cuts)+);
75 };
76}
77
78/// Build a persistent external graft overlay without touching source files.
79/// 构造持久化外部 graft 覆盖计划,不移动或修改任何源码文件。
80///
81/// ```
82/// # use nichlink_run_method::{FrameworkId, graft_plan};
83/// # let framework = FrameworkId::new("example");
84/// let plan = graft_plan!(framework,
85/// cut ["root/a1/b2"] graft "canvas_fast",
86/// cut ["root/a"] full graft "a_fast",
87/// );
88/// assert_eq!(plan.cuts.len(), 2);
89/// ```
90#[macro_export]
91macro_rules! graft_plan {
92 ($framework:expr, $($cuts:tt)+) => {{
93 let mut plan = $crate::GraftPlan::new($framework);
94 $crate::__graft_plan_cuts!(plan; $($cuts)+);
95 plan
96 }};
97}
98
99#[doc(hidden)]
100#[macro_export]
101macro_rules! __graft_plan_cuts {
102 ($plan:ident;) => {};
103 ($plan:ident; cut [$start:literal to $end:literal] full graft $graft:literal $(, $($rest:tt)*)?) => {{
104 let mut cut = $crate::GraftCut::range($start, $end, $graft);
105 cut.subtree = true;
106 $plan.cuts.push(cut);
107 $crate::__graft_plan_cuts!($plan; $($($rest)*)?);
108 }};
109 ($plan:ident; cut [$start:literal to $end:literal] graft $graft:literal $(, $($rest:tt)*)?) => {{
110 $plan.cuts
111 .push($crate::GraftCut::range($start, $end, $graft));
112 $crate::__graft_plan_cuts!($plan; $($($rest)*)?);
113 }};
114 ($plan:ident; cut [$path:literal] full graft $graft:literal $(, $($rest:tt)*)?) => {{
115 $plan.cuts.push($crate::GraftCut::subtree($path, $graft));
116 $crate::__graft_plan_cuts!($plan; $($($rest)*)?);
117 }};
118 ($plan:ident; cut [$path:literal] graft $graft:literal $(, $($rest:tt)*)?) => {{
119 $plan.cuts.push($crate::GraftCut::new($path, $graft));
120 $crate::__graft_plan_cuts!($plan; $($($rest)*)?);
121 }};
122 ($plan:ident; cut $path:literal full graft $graft:literal $(, $($rest:tt)*)?) => {{
123 $plan.cuts.push($crate::GraftCut::subtree($path, $graft));
124 $crate::__graft_plan_cuts!($plan; $($($rest)*)?);
125 }};
126 ($plan:ident; cut $path:literal graft $graft:literal $(, $($rest:tt)*)?) => {{
127 $plan.cuts.push($crate::GraftCut::new($path, $graft));
128 $crate::__graft_plan_cuts!($plan; $($($rest)*)?);
129 }};
130}