|
| 1 | +use crate::define::Result; |
| 2 | +use crate::function::InnerFunction; |
| 3 | +use crate::value::Value; |
| 4 | +use core::clone::Clone; |
| 5 | +use std::collections::HashMap; |
| 6 | +use std::sync::{Arc, Mutex}; |
| 7 | + |
| 8 | +#[derive(Clone)] |
| 9 | +pub enum ContextValue { |
| 10 | + Variable(Value), |
| 11 | + Function(Arc<InnerFunction>), |
| 12 | +} |
| 13 | + |
| 14 | +pub struct Context(pub Arc<Mutex<HashMap<String, ContextValue>>>); |
| 15 | + |
| 16 | +impl Context { |
| 17 | + pub fn new() -> Self { |
| 18 | + Context(Arc::new(Mutex::new(HashMap::new()))) |
| 19 | + } |
| 20 | + |
| 21 | + pub fn set_func(&mut self, name: &str, func: Arc<InnerFunction>) { |
| 22 | + self.set(name, ContextValue::Function(func.clone())); |
| 23 | + } |
| 24 | + |
| 25 | + pub fn set_variable(&mut self, name: &str, value: Value) { |
| 26 | + self.set(name, ContextValue::Variable(value)); |
| 27 | + } |
| 28 | + |
| 29 | + pub fn set(&mut self, name: &str, v: ContextValue) { |
| 30 | + self.0.lock().unwrap().insert(name.to_string(), v); |
| 31 | + } |
| 32 | + |
| 33 | + pub fn get_func(&self, name: &str) -> Option<Arc<InnerFunction>> { |
| 34 | + // ⚡ Bolt Optimization: Avoid unnecessary `.clone()` on the inner function |
| 35 | + // by directly taking ownership of the value returned by `get()` |
| 36 | + let value = self.get(name)?; |
| 37 | + match value { |
| 38 | + ContextValue::Function(func) => Some(func), |
| 39 | + ContextValue::Variable(_) => None, |
| 40 | + } |
| 41 | + } |
| 42 | + |
| 43 | + pub fn get_variable(&self, name: &str) -> Option<Value> { |
| 44 | + // ⚡ Bolt Optimization: Avoid unnecessary `.clone()` on the inner variable |
| 45 | + // by directly taking ownership of the value returned by `get()` |
| 46 | + let value = self.get(name)?; |
| 47 | + match value { |
| 48 | + ContextValue::Variable(v) => Some(v), |
| 49 | + ContextValue::Function(_) => None, |
| 50 | + } |
| 51 | + } |
| 52 | + |
| 53 | + pub fn get(&self, name: &str) -> Option<ContextValue> { |
| 54 | + // ⚡ Bolt Optimization: Minimize lock duration and avoid multi-step lookups |
| 55 | + self.0.lock().unwrap().get(name).cloned() |
| 56 | + } |
| 57 | + |
| 58 | + pub fn value(&self, name: &str) -> Result<Value> { |
| 59 | + // ⚡ Bolt Optimization: Avoid double map lookups (no `is_none()` followed by `unwrap()`) |
| 60 | + let value = self.get(name); |
| 61 | + match value { |
| 62 | + Some(ContextValue::Variable(v)) => Ok(v), |
| 63 | + Some(ContextValue::Function(func)) => func(Vec::new()), |
| 64 | + None => Ok(Value::None), |
| 65 | + } |
| 66 | + } |
| 67 | +} |
| 68 | + |
| 69 | +/// |
| 70 | +///```rust |
| 71 | +/// use expression_engine::create_context; |
| 72 | +/// use expression_engine::Value; |
| 73 | +/// let a = create_context!("d" => 3.5, "c" => Arc::new(|params| { |
| 74 | +/// Ok(Value::from(3)) |
| 75 | +/// })); |
| 76 | +///``` |
| 77 | +/// |
| 78 | +/// |
| 79 | +#[macro_export] |
| 80 | +macro_rules! create_context { |
| 81 | + (($ctx:expr) $k:expr => Arc::new($($v:tt)*), $($tt:tt)*) => {{ |
| 82 | + $ctx.set_func($k, Arc::new($($v)*)); |
| 83 | + $crate::create_context!(($ctx) $($tt)*); |
| 84 | + }}; |
| 85 | + |
| 86 | + (($ctx:expr) $k:expr => $v:expr, $($tt:tt)*) => {{ |
| 87 | + $ctx.set_variable($k, Value::from($v)); |
| 88 | + $crate::create_context!(($ctx) $($tt)*); |
| 89 | + }}; |
| 90 | + |
| 91 | + (($ctx:expr) $k:expr => Arc::new($($v:tt)*)) => {{ |
| 92 | + $ctx.set_func($k, Arc::new($($v)*)); |
| 93 | + }}; |
| 94 | + |
| 95 | + (($ctx:expr) $k:expr => $v:expr) => {{ |
| 96 | + $ctx.set_variable($k, Value::from($v)); |
| 97 | + }}; |
| 98 | + |
| 99 | + (($ctx:expr)) => {}; |
| 100 | + |
| 101 | + ($($tt:tt)*) => {{ |
| 102 | + use std::sync::Arc; |
| 103 | + let mut ctx = $crate::Context::new(); |
| 104 | + $crate::create_context!((&mut ctx) $($tt)*); |
| 105 | + ctx |
| 106 | + }}; |
| 107 | +} |
0 commit comments