Skip to main content

xyz_rust/
builder.rs

1// builder 是流式主入口:一条 Define 链配置整个程序。define 打开它,
2// summary/description/cli/http/mcp 配置当前命令,also 追加已构建完成的
3// 命令,终结的 run 把一切注册进默认注册表、派发进程参数并按结果退出。
4//
5// Rust 的形态:首条命令内联配置,后续命令以完整 define(...) 链交给
6// also(&[&dyn Definable] 切片,异构经由 trait object 擦除)。
7
8use serde::Serialize;
9
10use crate::config::Config;
11use crate::ctx::Ctx;
12use crate::errors;
13use crate::registry::Registry;
14use crate::spec::command::Command;
15use crate::spec::{XyzArgs, XyzSchema};
16use crate::{dispatch, spec};
17
18/// Definable 由任何构建完成的命令定义实现(spec::Command 或 builder 返回
19/// 的 Builder),使异构命令能并入一条链或一次 main 调用。
20pub trait Definable {
21    fn register(&self, reg: &Registry) -> errors::Result<()>;
22}
23
24impl<T, R, F, E> Definable for Command<T, R, F, E>
25where
26    T: XyzArgs,
27    R: XyzSchema + Serialize,
28    F: Fn(&Ctx, &T) -> std::result::Result<R, E> + Send + Sync + 'static,
29    E: std::error::Error + Send + Sync + 'static,
30{
31    fn register(&self, reg: &Registry) -> errors::Result<()> {
32        self.entry().map(|e| {
33            let _ = reg.add(std::sync::Arc::new(e));
34        })
35    }
36}
37
38/// Builder 是一条定义链:当前命令内联配置,命令列表经 also 追加,run
39/// 注册 + 派发 + 退出。
40pub struct Builder<T, R, F, E>
41where
42    T: XyzArgs,
43    R: XyzSchema + Serialize,
44    F: Fn(&Ctx, &T) -> std::result::Result<R, E> + Send + Sync + 'static,
45    E: std::error::Error + Send + Sync + 'static,
46{
47    cmd: Command<T, R, F, E>,
48    reg: &'static Registry,
49    committed: bool,
50    config: Config,
51    err: Option<errors::Error>,
52}
53
54/// 在默认注册表上打开一条定义链。
55pub fn define<T, R, F, E>(name: &str, h: F) -> Builder<T, R, F, E>
56where
57    T: XyzArgs,
58    R: XyzSchema + Serialize,
59    F: Fn(&Ctx, &T) -> std::result::Result<R, E> + Send + Sync + 'static,
60    E: std::error::Error + Send + Sync + 'static,
61{
62    Builder {
63        cmd: Command::new(name, h),
64        reg: Registry::default(),
65        committed: false,
66        config: Config::default(),
67        err: None,
68    }
69}
70
71impl<T, R, F, E> Builder<T, R, F, E>
72where
73    T: XyzArgs,
74    R: XyzSchema + Serialize,
75    F: Fn(&Ctx, &T) -> std::result::Result<R, E> + Send + Sync + 'static,
76    E: std::error::Error + Send + Sync + 'static,
77{
78    /// 单行描述。
79    pub fn summary(mut self, s: impl Into<String>) -> Self {
80        self.cmd = self.cmd.summary(s);
81        self
82    }
83
84    /// 长描述。
85    pub fn description(mut self, s: impl Into<String>) -> Self {
86        self.cmd = self.cmd.description(s);
87        self
88    }
89
90    /// 命令级 CLI 配置。
91    pub fn cli(mut self, h: spec::CliHints) -> Self {
92        self.cmd = self.cmd.cli(h);
93        self
94    }
95
96    /// 命令级 HTTP 配置。
97    pub fn http(mut self, h: spec::HTTPHints) -> Self {
98        self.cmd = self.cmd.http(h);
99        self
100    }
101
102    /// 命令级 MCP 配置。
103    pub fn mcp(mut self, h: spec::MCPHints) -> Self {
104        self.cmd = self.cmd.mcp(h);
105        self
106    }
107
108    /// 设置 Run/RunArgs 使用的派发器配置(模式词、通道能力)。在链任意
109    /// 位置调用;run_args_config 为那次调用显式指定 Config。
110    pub fn configure(mut self, cfg: Config) -> Self {
111        self.config = cfg;
112        self
113    }
114
115    /// 把当前命令与传入的每条命令都注册进同一默认注册表,然后续链。可
116    /// 再次调用追加更多。注册失败终止链:在 run 处浮出。
117    pub fn also(mut self, cmds: &[&dyn Definable]) -> Self {
118        if self.err.is_none() && !self.committed {
119            match self.commit_current() {
120                Ok(()) => self.committed = true,
121                Err(e) => self.err = Some(e),
122            }
123        }
124        if self.err.is_none() {
125            for c in cmds {
126                if let Err(e) = c.register(self.reg) {
127                    self.err = Some(e);
128                    break;
129                }
130            }
131        }
132        self
133    }
134
135    fn commit_current(&self) -> errors::Result<()> {
136        self.cmd.entry().map(|entry| {
137            let _ = self.reg.add(std::sync::Arc::new(entry));
138        })
139    }
140
141    /// 注册(若尚未注册)、按进程参数派发默认注册表、按结果退出。其后
142    /// 的代码按设计不可达。
143    pub fn run(self) -> ! {
144        let args: Vec<String> = std::env::args().skip(1).collect();
145        std::process::exit(self.run_args(args));
146    }
147
148    /// 带自定义配置的 run。
149    pub fn run_config(self, cfg: Config) -> ! {
150        let args: Vec<String> = std::env::args().skip(1).collect();
151        std::process::exit(self.run_args_config(args, cfg));
152    }
153
154    /// run 的可测试/可嵌入形态:注册、派发并返回退出码,不退出进程。
155    /// 使用链上 configure 的配置(零值 = 全默认)。
156    pub fn run_args(mut self, args: Vec<String>) -> i32 {
157        let cfg = std::mem::take(&mut self.config);
158        self.run_args_config(args, cfg)
159    }
160
161    /// 带自定义配置的 run_args。
162    pub fn run_args_config(mut self, args: Vec<String>, cfg: Config) -> i32 {
163        if self.err.is_none() && !self.committed {
164            match self.commit_current() {
165                Ok(()) => self.committed = true,
166                Err(e) => self.err = Some(e),
167            }
168        }
169        if let Some(e) = self.err {
170            eprintln!("{e}");
171            return 2;
172        }
173        dispatch::run_config(self.reg, args, cfg)
174    }
175}
176
177impl<T, R, F, E> Definable for Builder<T, R, F, E>
178where
179    T: XyzArgs,
180    R: XyzSchema + Serialize,
181    F: Fn(&Ctx, &T) -> std::result::Result<R, E> + Send + Sync + 'static,
182    E: std::error::Error + Send + Sync + 'static,
183{
184    fn register(&self, reg: &Registry) -> errors::Result<()> {
185        self.cmd.entry().map(|entry| {
186            let _ = reg.add(std::sync::Arc::new(entry));
187        })
188    }
189}