oneline_template/template/
template_builder.rs1use crate::template::template_build_error::TemplateBuildError;
2use crate::template::template::Template;
3use crate::template::argument_types_differ_error::ArgumentTypesDifferError;
4use crate::function_executor::FunctionExecutor;
5use crate::template::syntax::function_call_token::FunctionCallToken;
6use crate::function_executor::FunctionArgumentType;
7use crate::template::syntax::syntax::Syntax;
8use crate::template::syntax::function_call_argument_token::FunctionCallArgumentToken;
9use crate::template::syntax::token::Token;
10use crate::template::syntax::template_token::TemplateToken;
11use crate::functions;
12use std::str::FromStr;
13use std::collections::HashMap;
14
15
16pub struct TemplateBuilder {
18 functions: HashMap<String, Box<dyn FunctionExecutor>>,
19}
20
21impl TemplateBuilder {
22 pub fn new() -> TemplateBuilder {
24 return TemplateBuilder::new_empty()
25 .with_function(functions::bool::ToString)
26 .with_function(functions::bool::UnwrapOr)
27 .with_function(functions::float::ToString)
28 .with_function(functions::int::Abs)
29 .with_function(functions::int::Hex)
30 .with_function(functions::int::HexFmt)
31 .with_function(functions::int::ToString)
32 .with_function(functions::string::Trim)
33 .with_function(functions::string::UnwrapOr)
34 .with_function(functions::string::TrimStart)
35 .with_function(functions::string::TrimEnd)
36 .with_function(functions::string::SubStr)
37 .with_function(functions::uint::Hex)
38 .with_function(functions::uint::HexFmt)
39 .with_function(functions::uint::ToString)
40 .with_function(functions::debug::DebugType);
41 }
42
43 pub fn new_empty() -> TemplateBuilder {
45 return TemplateBuilder {
46 functions: HashMap::new(),
47 }
48 }
49
50 pub fn with_function(mut self, function_executor: impl FunctionExecutor + 'static) -> Self {
52 let function_executor: Box<dyn FunctionExecutor> = Box::new(function_executor);
53 let schema = function_executor.schema();
54 let function_name = schema.get_function_name().clone();
55 let _ = self.functions.insert(function_name, function_executor);
56 return self;
57 }
58
59 fn validate_function_call(&self, function_call: &FunctionCallToken) -> Result<(), TemplateBuildError> {
60 let function_name = function_call.get_function_name().as_string_ref();
61 let function_executor = match self.functions.get(function_name) {
62 Some(function_executor) => {function_executor},
63 None => {
64 return Err(TemplateBuildError::FunctionNotFound(function_name.to_string()));
65 },
66 };
67 let schema = function_executor.schema();
68 if function_call.get_arguments().len() != schema.get_arguments().len() {
69 return Err(TemplateBuildError::ArgumentsLengthDiffer(function_name.to_string()));
70 }
71 let iterator = function_call.get_arguments().iter().zip(schema.get_arguments().iter());
72 for (argument_index, (actual_argument, expected_argument)) in iterator.enumerate() {
73 let actual_argument_type = match actual_argument {
74 FunctionCallArgumentToken::String(..) => FunctionArgumentType::String,
75 FunctionCallArgumentToken::Bool(..) => FunctionArgumentType::Bool,
76 FunctionCallArgumentToken::UInt(..) => FunctionArgumentType::UInt,
77 FunctionCallArgumentToken::Int(..) => FunctionArgumentType::Int,
78 };
79 let expected_argument_type = expected_argument.get_type();
80 if &actual_argument_type != expected_argument_type {
81 return Err(ArgumentTypesDifferError::new(function_name.to_string(), argument_index).into());
82 }
83 }
84 return Ok(());
85 }
86
87 fn validate_template_token(&self, token: &TemplateToken) -> Result<(), TemplateBuildError> {
88 let token = token.get_field_read_token();
89 for function_call in token.get_function_calls().iter() {
90 self.validate_function_call(function_call)?;
91 }
92 return Ok(());
93 }
94
95 fn validate_syntax(&self, syntax: &Syntax) -> Result<(), TemplateBuildError> {
96 for token in syntax.iter_tokens() {
97 match token {
98 Token::Text(..) => {},
99 Token::Template(token) => {
100 self.validate_template_token(token)?;
101 },
102 }
103 }
104 return Ok(());
105 }
106
107 pub fn build(self, format: &str) -> Result<Template, TemplateBuildError> {
109 let syntax = Syntax::from_str(format)?;
110 self.validate_syntax(&syntax)?;
111 let template = Template::new(syntax, self.functions);
112 return Ok(template);
113 }
114}