Skip to main content

varar_core/
registry.rs

1//! Step registry — port of `registry.ts` / `Registry.java`. Wraps the owned
2//! [`crate::expression`] layer. Persistent-value semantics: `add_step` /
3//! `define_parameter_type` return a new [`Registry`]; the argument is unchanged.
4
5use crate::error::RegistryError;
6use crate::expression::{CompiledExpression, ParameterTypeRegistry};
7use crate::handler::Handler;
8use crate::step_kind::StepKind;
9use crate::value::Value;
10use std::collections::HashMap;
11use std::rc::Rc;
12
13pub use crate::expression::ParseFn;
14
15/// A parameter-type display formatter (the inverse of `parse`): renders a value
16/// back in the document's notation. `None` result → fall through to the generic
17/// rendering chain.
18pub type FormatFn = Rc<dyn Fn(&Value) -> Option<String>>;
19
20/// A custom parameter type as registered by an author — name plus bare pattern
21/// source (the string the registry artifact serializes).
22#[derive(Clone, Debug, PartialEq, Eq)]
23pub struct CustomParameterType {
24    pub name: String,
25    pub regexp: String,
26}
27
28impl CustomParameterType {
29    pub fn new(name: impl Into<String>, regexp: impl Into<String>) -> CustomParameterType {
30        CustomParameterType {
31            name: name.into(),
32            regexp: regexp.into(),
33        }
34    }
35}
36
37/// One registered step: source expression, source location, handler, compiled
38/// expression, and role (`kind` may be `None` — the legacy/kindless path).
39#[derive(Clone)]
40pub struct StepRegistration {
41    pub expression: String,
42    pub expression_source_file: String,
43    pub expression_source_line: usize,
44    pub handler: Handler,
45    pub compiled: CompiledExpression,
46    pub kind: Option<StepKind>,
47}
48
49/// The step registry.
50#[derive(Clone)]
51pub struct Registry {
52    pub steps: Vec<Rc<StepRegistration>>,
53    pub parameter_types: ParameterTypeRegistry,
54    pub custom_parameter_types: Vec<CustomParameterType>,
55    pub formats: HashMap<String, FormatFn>,
56}
57
58/// An empty registry with a fresh default parameter-type registry.
59pub fn create_registry() -> Registry {
60    Registry {
61        steps: Vec::new(),
62        parameter_types: ParameterTypeRegistry::new(),
63        custom_parameter_types: Vec::new(),
64        formats: HashMap::new(),
65    }
66}
67
68/// Compiles `expression` against `registry`'s parameter types and appends it,
69/// returning a new [`Registry`]. Errors on a duplicate expression or an
70/// un-compilable one.
71pub fn add_step(
72    registry: &Registry,
73    expression: &str,
74    expression_source_file: &str,
75    expression_source_line: usize,
76    handler: Handler,
77    kind: Option<StepKind>,
78) -> Result<Registry, RegistryError> {
79    for existing in &registry.steps {
80        if existing.expression == expression {
81            return Err(RegistryError::DuplicateStep(format!(
82                "duplicate step definition for \"{}\" at {}:{} and {}:{}",
83                expression,
84                existing.expression_source_file,
85                existing.expression_source_line,
86                expression_source_file,
87                expression_source_line
88            )));
89        }
90    }
91    let compiled = CompiledExpression::compile(expression, &registry.parameter_types)
92        .map_err(|e| RegistryError::Expression(e.message))?;
93    let mut steps = registry.steps.clone();
94    steps.push(Rc::new(StepRegistration {
95        expression: expression.to_string(),
96        expression_source_file: expression_source_file.to_string(),
97        expression_source_line,
98        handler,
99        compiled,
100        kind,
101    }));
102    Ok(Registry {
103        steps,
104        parameter_types: registry.parameter_types.clone(),
105        custom_parameter_types: registry.custom_parameter_types.clone(),
106        formats: registry.formats.clone(),
107    })
108}
109
110/// Registers a custom parameter type and returns a new [`Registry`] recording it.
111pub fn define_parameter_type(
112    registry: &Registry,
113    name: &str,
114    regexp: &str,
115    parse: ParseFn,
116) -> Registry {
117    let mut parameter_types = registry.parameter_types.clone();
118    parameter_types.define(name, regexp, parse);
119    let mut custom_parameter_types = registry.custom_parameter_types.clone();
120    custom_parameter_types.push(CustomParameterType::new(name, regexp));
121    Registry {
122        steps: registry.steps.clone(),
123        parameter_types,
124        custom_parameter_types,
125        formats: registry.formats.clone(),
126    }
127}
128
129/// As [`define_parameter_type`], additionally retaining a display `format`.
130pub fn define_parameter_type_with_format(
131    registry: &Registry,
132    name: &str,
133    regexp: &str,
134    parse: ParseFn,
135    format: FormatFn,
136) -> Registry {
137    let mut next = define_parameter_type(registry, name, regexp, parse);
138    next.formats.insert(name.to_string(), format);
139    next
140}