variant_config/resolver/
json_config_resolver.rs1use 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}