matugen_parser/
context.rs1use std::collections::HashMap;
2
3use indexmap::IndexMap;
4
5use crate::value::Value;
6
7#[allow(dead_code)]
8#[derive(Debug, Clone)]
9pub struct RuntimeContext {
10 global: Context,
11 pub scopes: Vec<HashMap<String, Value>>,
12}
13
14impl<'a> RuntimeContext {
15 pub fn new(global: Context) -> Self {
16 Self {
17 global,
18 scopes: Vec::new(),
19 }
20 }
21
22 pub fn resolve_path<I>(&self, path: I) -> Option<Value>
23 where
24 I: IntoIterator<Item = &'a str>,
25 {
26 let mut iter = path.into_iter();
27 let first = iter.next()?;
28 let mut current = self.get_from_scopes(first)?;
29
30 for key in iter {
31 current = match current {
32 Value::Map(map) => map.get(key)?.clone(),
33 _ => {
34 return None;
35 }
36 };
37 }
38
39 Some(current)
40 }
41
42 fn get_from_scopes(&self, key: &str) -> Option<Value> {
43 for scope in self.scopes.iter().rev() {
44 if let Some(val) = scope.get(key) {
45 return Some(val.clone());
46 }
47 }
48 None
49 }
50
51 pub fn push_scope(&mut self) {
52 self.scopes.push(HashMap::new());
53 }
54
55 pub fn pop_scope(&mut self) {
56 self.scopes.pop();
57 }
58
59 pub fn insert(&mut self, key: impl Into<String>, value: Value) {
60 if let Some(scope) = self.scopes.last_mut() {
61 scope.insert(key.into(), value);
62 } else {
63 self.scopes.push(HashMap::from([(key.into(), value)]));
64 }
65 }
66}
67
68#[derive(Debug, Clone)]
69pub struct Context {
70 pub data: IndexMap<String, Value>,
71}
72
73impl Default for Context {
74 fn default() -> Self {
75 Self::new()
76 }
77}
78
79impl Context {
80 pub fn new() -> Self {
81 Self {
82 data: IndexMap::new(),
83 }
84 }
85
86 pub fn merge(&mut self, incoming: &IndexMap<String, Value>) {
87 merge_nested(&mut self.data, incoming);
88 }
89
90 pub fn merge_value(&mut self, incoming: Value) {
91 match incoming {
92 Value::Map(map) => {
93 merge_nested(&mut self.data, &map);
94 }
95 _ => panic!(""),
96 }
97 }
98
99 fn json_to_value_map(&self, json: serde_json::Value) -> Option<IndexMap<String, Value>> {
100 match Value::from(json) {
101 Value::Map(map) => Some(map),
102 _ => None,
103 }
104 }
105
106 pub fn merge_json(&mut self, json: serde_json::Value) {
107 if let Some(map) = self.json_to_value_map(json) {
108 self.merge(&map);
109 } else {
110 panic!("Expected a JSON object to merge into context.");
111 }
112 }
113
114 pub fn delete_key(&mut self, key: &str) {
115 self.data.swap_remove(key);
116 }
117
118 pub fn remove_path<'a, I>(&mut self, path: I) -> bool
119 where
120 I: IntoIterator<Item = &'a str>,
121 {
122 let mut iter = path.into_iter();
123 let Some(first) = iter.next() else {
124 return false;
125 };
126
127 let mut current = &mut self.data;
128 let mut last_key = first;
129
130 for key in iter {
131 match current.get_mut(last_key) {
132 Some(Value::Map(map)) => {
133 current = map;
134 last_key = key;
135 }
136 _ => return false,
137 }
138 }
139
140 current.swap_remove(last_key).is_some()
141 }
142
143 pub fn data(&self) -> &IndexMap<String, Value> {
144 &self.data
145 }
146}
147
148fn merge_nested(target: &mut IndexMap<String, Value>, source: &IndexMap<String, Value>) {
149 for (key, value) in source {
150 match (target.get_mut(key), value) {
151 (Some(Value::Map(target_obj)), Value::Map(source_obj)) => {
152 merge_nested(target_obj, source_obj);
153 }
154 _ => {
155 target.insert(key.clone(), value.clone());
156 }
157 }
158 }
159}