use crate::builder::{BuilderError, BuilderResult};
use crate::types::{
basic::{OSString, ParameterDeclaration, ParameterDeclarations, Value},
enums::ParameterType,
};
use std::collections::HashMap;
#[derive(Debug, Default)]
pub struct ParameterDeclarationsBuilder {
parameters: Vec<ParameterDeclaration>,
}
impl ParameterDeclarationsBuilder {
pub fn new() -> Self {
Self::default()
}
pub fn add_string_parameter(mut self, name: &str, default_value: &str) -> Self {
self.parameters.push(ParameterDeclaration {
name: OSString::literal(name.to_string()),
parameter_type: ParameterType::String,
value: OSString::literal(default_value.to_string()),
constraint_groups: Vec::new(),
});
self
}
pub fn add_double_parameter(mut self, name: &str, default_value: f64) -> Self {
self.parameters.push(ParameterDeclaration {
name: OSString::literal(name.to_string()),
parameter_type: ParameterType::Double,
value: OSString::literal(default_value.to_string()),
constraint_groups: Vec::new(),
});
self
}
pub fn add_int_parameter(mut self, name: &str, default_value: i32) -> Self {
self.parameters.push(ParameterDeclaration {
name: OSString::literal(name.to_string()),
parameter_type: ParameterType::Int,
value: OSString::literal(default_value.to_string()),
constraint_groups: Vec::new(),
});
self
}
pub fn add_boolean_parameter(mut self, name: &str, default_value: bool) -> Self {
self.parameters.push(ParameterDeclaration {
name: OSString::literal(name.to_string()),
parameter_type: ParameterType::Boolean,
value: OSString::literal(default_value.to_string()),
constraint_groups: Vec::new(),
});
self
}
pub fn add_datetime_parameter(mut self, name: &str, default_value: &str) -> Self {
self.parameters.push(ParameterDeclaration {
name: OSString::literal(name.to_string()),
parameter_type: ParameterType::DateTime,
value: OSString::literal(default_value.to_string()),
constraint_groups: Vec::new(),
});
self
}
pub fn add_unsigned_short_parameter(mut self, name: &str, default_value: u16) -> Self {
self.parameters.push(ParameterDeclaration {
name: OSString::literal(name.to_string()),
parameter_type: ParameterType::UnsignedShort,
value: OSString::literal(default_value.to_string()),
constraint_groups: Vec::new(),
});
self
}
pub fn add_unsigned_int_parameter(mut self, name: &str, default_value: u32) -> Self {
self.parameters.push(ParameterDeclaration {
name: OSString::literal(name.to_string()),
parameter_type: ParameterType::UnsignedInt,
value: OSString::literal(default_value.to_string()),
constraint_groups: Vec::new(),
});
self
}
pub fn build(self) -> ParameterDeclarations {
ParameterDeclarations {
parameter_declarations: self.parameters,
}
}
pub fn len(&self) -> usize {
self.parameters.len()
}
pub fn is_empty(&self) -> bool {
self.parameters.is_empty()
}
}
#[derive(Debug, Clone)]
pub struct ParameterizedValueBuilder<T> {
value: Value<T>,
}
impl<T> ParameterizedValueBuilder<T> {
pub fn literal(value: T) -> Self {
Self {
value: Value::Literal(value),
}
}
pub fn parameter(parameter_name: &str) -> Self {
Self {
value: Value::Parameter(parameter_name.to_string()),
}
}
pub fn expression(expression: &str) -> Self {
Self {
value: Value::Expression(expression.to_string()),
}
}
pub fn build(self) -> Value<T> {
self.value
}
}
#[derive(Debug, Default)]
pub struct ParameterContext {
parameters: HashMap<String, String>,
}
impl ParameterContext {
pub fn new() -> Self {
Self::default()
}
pub fn add_parameter(mut self, name: &str, value: &str) -> Self {
self.parameters.insert(name.to_string(), value.to_string());
self
}
pub fn with_parameters(mut self, parameters: HashMap<String, String>) -> Self {
self.parameters.extend(parameters);
self
}
pub fn get_parameter(&self, name: &str) -> Option<&str> {
self.parameters.get(name).map(|s| s.as_str())
}
pub fn resolve_parameter(&self, parameter_name: &str) -> BuilderResult<String> {
self.parameters.get(parameter_name).cloned().ok_or_else(|| {
BuilderError::validation_error(&format!(
"Parameter '{}' not found in context",
parameter_name
))
})
}
pub fn resolve_value<T>(&self, value: &Value<T>) -> BuilderResult<String>
where
T: ToString,
{
match value {
Value::Literal(val) => Ok(val.to_string()),
Value::Parameter(param_name) => self.resolve_parameter(param_name),
Value::Expression(expr) => {
Ok(expr.clone())
}
}
}
pub fn parameters(&self) -> &HashMap<String, String> {
&self.parameters
}
}
pub trait Parameterizable {
fn apply_parameters(&mut self, context: &ParameterContext) -> BuilderResult<()>;
}
pub mod utils {
use super::*;
pub fn parameter_ref(name: &str) -> String {
format!("${{{}}}", name)
}
pub fn is_parameter_ref(value: &str) -> bool {
value.starts_with("${") && value.ends_with('}')
}
pub fn extract_parameter_name(param_ref: &str) -> Option<&str> {
if is_parameter_ref(param_ref) {
Some(¶m_ref[2..param_ref.len() - 1])
} else {
None
}
}
pub fn parameterized_string(parameter_name: &str) -> OSString {
OSString::parameter(parameter_name.to_string())
}
pub fn parameterized_double(parameter_name: &str) -> crate::types::basic::Double {
crate::types::basic::Double::parameter(parameter_name.to_string())
}
pub fn parameterized_int(parameter_name: &str) -> crate::types::basic::Int {
crate::types::basic::Int::parameter(parameter_name.to_string())
}
pub fn parameterized_boolean(parameter_name: &str) -> crate::types::basic::Boolean {
crate::types::basic::Boolean::parameter(parameter_name.to_string())
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_parameter_declarations_builder() {
let params = ParameterDeclarationsBuilder::new()
.add_string_parameter("vehicle_name", "ego")
.add_double_parameter("initial_speed", 25.0)
.add_int_parameter("lane_id", 1)
.add_boolean_parameter("enable_logging", true)
.build();
assert_eq!(params.parameter_declarations.len(), 4);
let vehicle_param = ¶ms.parameter_declarations[0];
assert_eq!(vehicle_param.name.to_string(), "vehicle_name");
assert_eq!(vehicle_param.parameter_type, ParameterType::String);
assert_eq!(vehicle_param.value.to_string(), "ego");
}
#[test]
fn test_parameterized_value_builder() {
let literal_value = ParameterizedValueBuilder::literal(42.0).build();
assert!(matches!(literal_value, Value::Literal(42.0)));
let param_value = ParameterizedValueBuilder::<f64>::parameter("speed").build();
assert!(matches!(param_value, Value::Parameter(ref name) if name == "speed"));
let expr_value = ParameterizedValueBuilder::<f64>::expression("$speed * 2").build();
assert!(matches!(expr_value, Value::Expression(ref expr) if expr == "$speed * 2"));
}
#[test]
fn test_parameter_context() {
let context = ParameterContext::new()
.add_parameter("speed", "30.0")
.add_parameter("vehicle", "sedan");
assert_eq!(context.get_parameter("speed"), Some("30.0"));
assert_eq!(context.get_parameter("vehicle"), Some("sedan"));
assert_eq!(context.get_parameter("unknown"), None);
let resolved = context.resolve_parameter("speed").unwrap();
assert_eq!(resolved, "30.0");
}
#[test]
fn test_parameter_utils() {
assert_eq!(utils::parameter_ref("speed"), "${speed}");
assert!(utils::is_parameter_ref("${speed}"));
assert!(!utils::is_parameter_ref("speed"));
assert_eq!(utils::extract_parameter_name("${speed}"), Some("speed"));
assert_eq!(utils::extract_parameter_name("speed"), None);
}
}