safe_chains/registry/
mod.rs1mod build;
2mod custom;
3mod dispatch;
4mod docs;
5mod policy;
6pub(crate) mod types;
7
8use std::collections::HashMap;
9use std::sync::LazyLock;
10
11use crate::parse::Token;
12use crate::verdict::Verdict;
13
14pub use build::{build_registry, load_toml};
15pub use dispatch::dispatch_spec;
16pub use types::{CommandSpec, OwnedPolicy};
17
18use types::DispatchKind;
19
20type HandlerFn = fn(&[Token]) -> Verdict;
21
22static CMD_HANDLERS: LazyLock<HashMap<&'static str, HandlerFn>> =
23 LazyLock::new(crate::handlers::custom_cmd_handlers);
24
25static SUB_HANDLERS: LazyLock<HashMap<&'static str, HandlerFn>> =
26 LazyLock::new(crate::handlers::custom_sub_handlers);
27
28static TOML_REGISTRY: LazyLock<HashMap<String, CommandSpec>> = LazyLock::new(||
29 include!(concat!(env!("OUT_DIR"), "/toml_includes.rs"))
30);
31
32static CUSTOM_REGISTRY: LazyLock<HashMap<String, CommandSpec>> = LazyLock::new(|| {
33 let mut map = HashMap::new();
34 custom::apply_custom(&mut map);
35 map
36});
37
38pub fn toml_dispatch(tokens: &[Token]) -> Option<Verdict> {
39 let cmd = tokens[0].command_name();
40 TOML_REGISTRY.get(cmd).map(|spec| dispatch_spec(tokens, spec))
41}
42
43pub fn custom_dispatch(tokens: &[Token]) -> Option<Verdict> {
48 let cmd = tokens[0].command_name();
49 CUSTOM_REGISTRY.get(cmd).map(|spec| dispatch_spec(tokens, spec))
50}
51
52pub fn toml_command_names() -> Vec<&'static str> {
53 TOML_REGISTRY
54 .keys()
55 .map(|k| k.as_str())
56 .collect()
57}
58
59pub fn try_sub_dispatch(cmd_name: &str, tokens: &[Token]) -> Option<Verdict> {
64 let spec = handler_spec(cmd_name)?;
65 let DispatchKind::Custom { subs, .. } = &spec.kind else {
66 return None;
67 };
68 let arg = tokens.get(1)?.as_str();
69 let sub = subs.iter().find(|s| s.name == arg)?;
70 Some(dispatch::dispatch_sub_kind(&tokens[1..], &sub.kind))
71}
72
73pub fn try_fallback_grammar(cmd_name: &str, tokens: &[Token]) -> Option<Verdict> {
76 let spec = handler_spec(cmd_name)?;
77 let DispatchKind::Custom { fallback, .. } = &spec.kind else {
78 return None;
79 };
80 let f = fallback.as_ref()?;
81 Some(dispatch::dispatch_fallback(tokens, f))
82}
83
84fn handler_spec(cmd_name: &str) -> Option<&'static CommandSpec> {
85 CUSTOM_REGISTRY
86 .get(cmd_name)
87 .or_else(|| TOML_REGISTRY.get(cmd_name))
88}
89
90pub fn toml_command_docs() -> Vec<crate::docs::CommandDoc> {
91 TOML_REGISTRY
92 .iter()
93 .filter(|(key, spec)| *key == &spec.name)
94 .map(|(_, spec)| spec.to_command_doc())
95 .collect()
96}
97
98#[cfg(test)]
99mod tests;