use crate::error::RegistryError;
use crate::expression::{CompiledExpression, ParameterTypeRegistry};
use crate::handler::Handler;
use crate::step_kind::StepKind;
use crate::value::Value;
use std::collections::HashMap;
use std::rc::Rc;
pub use crate::expression::ParseFn;
pub type FormatFn = Rc<dyn Fn(&Value) -> Option<String>>;
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CustomParameterType {
pub name: String,
pub regexp: String,
}
impl CustomParameterType {
pub fn new(name: impl Into<String>, regexp: impl Into<String>) -> CustomParameterType {
CustomParameterType {
name: name.into(),
regexp: regexp.into(),
}
}
}
#[derive(Clone)]
pub struct StepRegistration {
pub expression: String,
pub expression_source_file: String,
pub expression_source_line: usize,
pub handler: Handler,
pub compiled: CompiledExpression,
pub kind: Option<StepKind>,
}
#[derive(Clone)]
pub struct Registry {
pub steps: Vec<Rc<StepRegistration>>,
pub parameter_types: ParameterTypeRegistry,
pub custom_parameter_types: Vec<CustomParameterType>,
pub formats: HashMap<String, FormatFn>,
}
pub fn create_registry() -> Registry {
Registry {
steps: Vec::new(),
parameter_types: ParameterTypeRegistry::new(),
custom_parameter_types: Vec::new(),
formats: HashMap::new(),
}
}
pub fn add_step(
registry: &Registry,
expression: &str,
expression_source_file: &str,
expression_source_line: usize,
handler: Handler,
kind: Option<StepKind>,
) -> Result<Registry, RegistryError> {
for existing in ®istry.steps {
if existing.expression == expression {
return Err(RegistryError::DuplicateStep(format!(
"duplicate step definition for \"{}\" at {}:{} and {}:{}",
expression,
existing.expression_source_file,
existing.expression_source_line,
expression_source_file,
expression_source_line
)));
}
}
let compiled = CompiledExpression::compile(expression, ®istry.parameter_types)
.map_err(|e| RegistryError::Expression(e.message))?;
let mut steps = registry.steps.clone();
steps.push(Rc::new(StepRegistration {
expression: expression.to_string(),
expression_source_file: expression_source_file.to_string(),
expression_source_line,
handler,
compiled,
kind,
}));
Ok(Registry {
steps,
parameter_types: registry.parameter_types.clone(),
custom_parameter_types: registry.custom_parameter_types.clone(),
formats: registry.formats.clone(),
})
}
pub fn define_parameter_type(
registry: &Registry,
name: &str,
regexp: &str,
parse: ParseFn,
) -> Registry {
let mut parameter_types = registry.parameter_types.clone();
parameter_types.define(name, regexp, parse);
let mut custom_parameter_types = registry.custom_parameter_types.clone();
custom_parameter_types.push(CustomParameterType::new(name, regexp));
Registry {
steps: registry.steps.clone(),
parameter_types,
custom_parameter_types,
formats: registry.formats.clone(),
}
}
pub fn define_parameter_type_with_format(
registry: &Registry,
name: &str,
regexp: &str,
parse: ParseFn,
format: FormatFn,
) -> Registry {
let mut next = define_parameter_type(registry, name, regexp, parse);
next.formats.insert(name.to_string(), format);
next
}