variant_config/resolver/
json_config_resolver.rs

1use crate::dsl::{FnJitter, VariantValue};
2use hashbrown::HashMap;
3use serde_json::Value;
4use std::cell::RefCell;
5use std::collections::BTreeMap;
6
7struct NodeCandidateResolver {
8    index: usize,
9    condition: FnJitter,
10}
11
12impl NodeCandidateResolver {
13    pub fn new(index: usize, on: &str) -> anyhow::Result<Self> {
14        let jitter = FnJitter::new(on)?;
15        Ok(Self {
16            index,
17            condition: jitter,
18        })
19    }
20
21    pub unsafe fn free_memory(self) {
22        self.condition.free_memory();
23    }
24}
25
26pub struct JsonConfigResolver {
27    condition_path: String,
28    value_path: String,
29    json: Value,
30    node_resolvers: BTreeMap<String, RefCell<Vec<NodeCandidateResolver>>>,
31}
32
33impl JsonConfigResolver {
34    pub fn new(json: Value) -> anyhow::Result<JsonConfigResolver> {
35        Self::new_with_custom_path(json, "if".to_owned(), "value".to_owned())
36    }
37
38    pub fn new_with_custom_path(
39        json: Value,
40        condition_path: String,
41        value_path: String,
42    ) -> anyhow::Result<Self> {
43        let mut r = Self {
44            condition_path,
45            value_path,
46            json: Value::default(),
47            node_resolvers: BTreeMap::new(),
48        };
49        r.set_json(json)?;
50        Ok(r)
51    }
52
53    pub fn resolve(&self, ctx: &HashMap<String, VariantValue>) -> Value {
54        let mut ret = self.json.clone();
55        if !self.node_resolvers.is_empty() {
56            for (path, resolvers) in self.node_resolvers.iter().rev() {
57                if let Some(ptr_mut) = ret.pointer_mut(path) {
58                    let mut match_value = Value::Null;
59                    for resolver in resolvers.borrow().iter() {
60                        if resolver.condition.evaluate(ctx) {
61                            let k = format!("/{}/{}", resolver.index, self.value_path);
62                            if let Some(v) = ptr_mut.pointer(&k) {
63                                match_value = v.clone();
64                                break;
65                            }
66                        }
67                    }
68                    *ptr_mut = match_value;
69                }
70            }
71        }
72        ret
73    }
74
75    fn set_json(&mut self, json: Value) -> anyhow::Result<()> {
76        let mut path = Vec::new();
77        self.parse_variants(&json, &mut path)?;
78        self.json = json;
79        Ok(())
80    }
81
82    fn parse_variants(&mut self, node: &Value, path: &mut Vec<String>) -> anyhow::Result<()> {
83        match node {
84            Value::Array(vec) => {
85                if !vec.is_empty() {
86                    let is_variant_array = vec.iter().all(|i| self.is_variant_array(i));
87                    let mut node_resolvers: Vec<NodeCandidateResolver>;
88                    if is_variant_array {
89                        node_resolvers = Vec::with_capacity(vec.len());
90                    } else {
91                        node_resolvers = Vec::with_capacity(0);
92                    }
93                    for (idx, item) in vec.iter().enumerate() {
94                        if is_variant_array {
95                            let value = item.get(&self.value_path).unwrap();
96                            if let Some(v) = item.get(&self.condition_path) {
97                                match v {
98                                    Value::String(on) => {
99                                        let r = NodeCandidateResolver::new(idx, on)?;
100                                        node_resolvers.push(r);
101                                    }
102                                    Value::Null => {
103                                        let r = NodeCandidateResolver::new(idx, "1")?;
104                                        node_resolvers.push(r);
105                                    }
106                                    Value::Bool(true) => {
107                                        let r = NodeCandidateResolver::new(idx, "1")?;
108                                        node_resolvers.push(r);
109                                    }
110                                    Value::Number(n) => {
111                                        let r = NodeCandidateResolver::new(idx, &n.to_string())?;
112                                        node_resolvers.push(r);
113                                    }
114                                    _ => {}
115                                }
116                            }
117
118                            path.push(format!("{}", idx));
119                            path.push(self.value_path.to_string());
120                            self.parse_variants(value, path)?;
121                            path.pop();
122                            path.pop();
123                        } else {
124                            path.push(format!("{}", idx));
125                            self.parse_variants(item, path)?;
126                            path.pop();
127                        }
128                    }
129                    if is_variant_array {
130                        self.node_resolvers
131                            .insert(merge_json_path(path), RefCell::new(node_resolvers));
132                    }
133                }
134            }
135            Value::Object(map) => {
136                for (k, v) in map {
137                    path.push(k.clone());
138                    self.parse_variants(v, path)?;
139                    path.pop();
140                }
141            }
142            _ => {}
143        }
144        Ok(())
145    }
146
147    fn is_variant_array(&self, v: &Value) -> bool {
148        if v.is_object() && v.get(&self.value_path).is_some() {
149            if let Some(c) = v.get(&self.condition_path) {
150                return !c.is_array() && !c.is_object();
151            }
152        }
153        false
154    }
155
156    fn get_keys(&self) -> Vec<String> {
157        self.node_resolvers.keys().cloned().collect()
158    }
159}
160
161impl Drop for JsonConfigResolver {
162    fn drop(&mut self) {
163        for k in self.get_keys() {
164            if let Some(v) = self.node_resolvers.remove(&k) {
165                let mut vec = v.borrow_mut();
166                while vec.len() > 0 {
167                    let r = vec.remove(0);
168                    unsafe { r.free_memory() };
169                }
170            }
171        }
172    }
173}
174
175fn merge_json_path(path: &[String]) -> String {
176    format!("/{}", path.join("/"))
177}