dsntk_feel/
scope.rs

1//! Implementation of the `FEEL` scope.
2
3use crate::context::FeelContext;
4use crate::values::Value;
5use crate::{Name, QualifiedName};
6use dsntk_common::Jsonify;
7use std::cell::RefCell;
8use std::fmt;
9
10/// This macro creates a default scope.
11#[macro_export]
12macro_rules! scope {
13  () => {{
14    FeelScope::default()
15  }};
16}
17
18/// The `FEEL` scope.
19pub struct FeelScope {
20  /// The stack of contexts.
21  stack: RefCell<Vec<FeelContext>>,
22}
23
24impl Default for FeelScope {
25  /// Creates a default [FeelScope] containing single default [FeelContext].
26  fn default() -> Self {
27    Self {
28      stack: RefCell::new(vec![FeelContext::default()]),
29    }
30  }
31}
32
33impl From<FeelContext> for FeelScope {
34  /// Creates a [FeelScope] from [FeelContext].
35  fn from(ctx: FeelContext) -> Self {
36    Self { stack: RefCell::new(vec![ctx]) }
37  }
38}
39
40impl fmt::Display for FeelScope {
41  /// Converts [FeelScope] to text.
42  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43    write!(f, "[{}]", self.stack.borrow_mut().iter().map(|ctx| ctx.to_string()).collect::<Vec<String>>().join(", "))
44  }
45}
46
47impl Jsonify for FeelScope {
48  /// Converts this [FeelScope] to JSON text.
49  fn jsonify(&self) -> String {
50    format!("[{}]", self.stack.borrow_mut().iter().map(|ctx| ctx.to_string()).collect::<Vec<String>>().join(", "))
51  }
52}
53
54impl FeelScope {
55  /// Temporary - remove
56  pub fn contexts(&self) -> Vec<FeelContext> {
57    self.stack.borrow().clone()
58  }
59
60  /// Creates a new and empty [FeelScope].
61  pub fn new() -> Self {
62    Self { stack: RefCell::new(vec![]) }
63  }
64
65  /// Pushes a context on the top of the scope stack.
66  pub fn push(&self, ctx: FeelContext) {
67    self.stack.borrow_mut().push(ctx)
68  }
69
70  /// Appends the content of another scope at the end of this scope.
71  pub fn append(&self, other: FeelScope) {
72    self.stack.borrow_mut().append(&mut other.stack.borrow_mut());
73  }
74
75  /// Takes and returns a context from the top of the stack.
76  pub fn pop(&self) -> Option<FeelContext> {
77    self.stack.borrow_mut().pop()
78  }
79
80  /// Peeks a context from the top of the stack.
81  /// If the stack is empty, the default context is returned.
82  pub fn peek(&self) -> Option<FeelContext> {
83    self.stack.borrow().last().cloned()
84  }
85
86  /// Returns a value of an entry with specified name.
87  /// Entries are searched from the last to the first context,
88  /// (from top to bottom of the stack).
89  pub fn get_value(&self, name: &Name) -> Option<Value> {
90    for context in self.stack.borrow().iter().rev() {
91      if let Some(value) = context.get_entry(name) {
92        return Some(value.clone());
93      }
94    }
95    None
96  }
97
98  /// Searches for a value under so called `qualified` name build from
99  /// multiple names passed as an argument.
100  pub fn search(&self, names: &[Name]) -> Option<Value> {
101    for context in self.stack.borrow().iter().rev() {
102      if let Some(value) = context.search_deep(names) {
103        return Some(value.clone());
104      }
105    }
106    None
107  }
108
109  /// Searches for a value of an entry pointed by specified qualified name.
110  pub fn search_entry(&self, qname: &QualifiedName) -> Option<Value> {
111    for context in self.stack.borrow().iter().rev() {
112      if let Some(value) = context.search_entry(qname) {
113        return Some(value.clone());
114      }
115    }
116    None
117  }
118
119  /// Sets a specified value for entry name in [FeelContext] placed on the top of the scope stack.
120  pub fn set_value(&self, name: &Name, value: Value) {
121    if let Some(context) = self.stack.borrow_mut().last_mut() {
122      context.set_entry(name, value);
123    }
124  }
125
126  /// Sets a null value for entry name in [FeelContext] placed on the top of the scope stack.
127  pub fn set_name(&self, name: Name) {
128    if let Some(context) = self.stack.borrow_mut().last_mut() {
129      context.set_null(name);
130    }
131  }
132}