fastn_resolved/evalexpr/context/
mod.rs1use std::{collections::HashMap, iter};
8
9use fastn_resolved::evalexpr::{
10 function::Function,
11 value::{value_type::ValueType, Value},
12 EvalexprError, EvalexprResult,
13};
14
15mod predefined;
16
17pub trait Context {
19 fn get_value(&self, identifier: &str) -> Option<&Value>;
21
22 fn call_function(&self, identifier: &str, argument: &Value) -> EvalexprResult<Value>;
25}
26
27pub trait ContextWithMutableVariables: Context {
29 fn set_value(&mut self, _identifier: String, _value: Value) -> EvalexprResult<()> {
31 Err(EvalexprError::ContextNotMutable)
32 }
33}
34
35pub trait ContextWithMutableFunctions: Context {
37 fn set_function(&mut self, _identifier: String, _function: Function) -> EvalexprResult<()> {
39 Err(EvalexprError::ContextNotMutable)
40 }
41}
42
43pub trait IterateVariablesContext<'a> {
47 type VariableIterator: 'a + Iterator<Item = (String, Value)>;
49 type VariableNameIterator: 'a + Iterator<Item = String>;
51
52 fn iter_variables(&'a self) -> Self::VariableIterator;
54
55 fn iter_variable_names(&'a self) -> Self::VariableNameIterator;
57}
58
59#[derive(Debug, Default)]
70pub struct EmptyContext;
71
72impl Context for EmptyContext {
73 fn get_value(&self, _identifier: &str) -> Option<&Value> {
74 None
75 }
76
77 fn call_function(&self, identifier: &str, _argument: &Value) -> EvalexprResult<Value> {
78 Err(EvalexprError::FunctionIdentifierNotFound(
79 identifier.to_string(),
80 ))
81 }
82}
83
84impl<'a> IterateVariablesContext<'a> for EmptyContext {
85 type VariableIterator = iter::Empty<(String, Value)>;
86 type VariableNameIterator = iter::Empty<String>;
87
88 fn iter_variables(&self) -> Self::VariableIterator {
89 iter::empty()
90 }
91
92 fn iter_variable_names(&self) -> Self::VariableNameIterator {
93 iter::empty()
94 }
95}
96
97#[derive(Clone, Debug, Default)]
103pub struct HashMapContext {
104 variables: HashMap<String, Value>,
105 functions: HashMap<String, Function>,
106}
107
108impl HashMapContext {
109 pub fn new() -> Self {
111 Default::default()
112 }
113}
114
115impl Context for HashMapContext {
116 fn get_value(&self, identifier: &str) -> Option<&Value> {
117 self.variables.get(identifier)
118 }
119
120 fn call_function(&self, identifier: &str, argument: &Value) -> EvalexprResult<Value> {
121 if let Some(function) = self.functions.get(identifier) {
122 function.call(argument)
123 } else {
124 Err(EvalexprError::FunctionIdentifierNotFound(
125 identifier.to_string(),
126 ))
127 }
128 }
129}
130
131impl ContextWithMutableVariables for HashMapContext {
132 fn set_value(&mut self, identifier: String, value: Value) -> EvalexprResult<()> {
133 if let Some(existing_value) = self.variables.get_mut(&identifier) {
134 if ValueType::from(&existing_value) == ValueType::from(&value) {
135 *existing_value = value;
136 return Ok(());
137 } else {
138 return Err(EvalexprError::expected_type(existing_value, value));
139 }
140 }
141
142 self.variables.insert(identifier, value);
144 Ok(())
145 }
146}
147
148impl ContextWithMutableFunctions for HashMapContext {
149 fn set_function(&mut self, identifier: String, function: Function) -> EvalexprResult<()> {
150 self.functions.insert(identifier, function);
151 Ok(())
152 }
153}
154
155impl<'a> IterateVariablesContext<'a> for HashMapContext {
156 type VariableIterator = std::iter::Map<
157 std::collections::hash_map::Iter<'a, String, Value>,
158 fn((&String, &Value)) -> (String, Value),
159 >;
160 type VariableNameIterator =
161 std::iter::Cloned<std::collections::hash_map::Keys<'a, String, Value>>;
162
163 fn iter_variables(&'a self) -> Self::VariableIterator {
164 self.variables
165 .iter()
166 .map(|(string, value)| (string.clone(), value.clone()))
167 }
168
169 fn iter_variable_names(&'a self) -> Self::VariableNameIterator {
170 self.variables.keys().cloned()
171 }
172}
173
174#[macro_export]
189macro_rules! context_map {
190 ( ($ctx:expr) $k:expr => Function::new($($v:tt)*) ) =>
192 { $crate::context_map!(($ctx) $k => Function::new($($v)*),) };
193 ( ($ctx:expr) $k:expr => $v:expr ) =>
194 { $crate::context_map!(($ctx) $k => $v,) };
195 ( ($ctx:expr) ) => { Ok(()) };
197
198 ( ($ctx:expr) $k:expr => Function::new($($v:tt)*) , $($tt:tt)*) => {{
200 $crate::evalexpr::ContextWithMutableFunctions::set_function($ctx, $k.into(), $crate::evalexpr::Function::new($($v)*))
201 .and($crate::context_map!(($ctx) $($tt)*))
202 }};
203 ( ($ctx:expr) $k:expr => $v:expr , $($tt:tt)*) => {{
205 $crate::evalexpr::ContextWithMutableVariables::set_value($ctx, $k.into(), $v.into())
206 .and($crate::context_map!(($ctx) $($tt)*))
207 }};
208
209 ( $($tt:tt)* ) => {{
211 let mut context = $crate::evalexpr::HashMapContext::new();
212 $crate::context_map!((&mut context) $($tt)*)
213 .map(|_| context)
214 }};
215}