1use std::sync::Arc;
17use indexmap::IndexMap;
18
19use super::value::Val;
20use super::EvalError;
21use super::super::ast::KindType;
22
23#[inline]
26pub fn is_truthy(v: &Val) -> bool {
27 match v {
28 Val::Null => false,
29 Val::Bool(b) => *b,
30 Val::Int(n) => *n != 0,
31 Val::Float(f) => *f != 0.0,
32 Val::Str(s) => !s.is_empty(),
33 Val::Arr(a) => !a.is_empty(),
34 Val::Obj(m) => !m.is_empty(),
35 }
36}
37
38#[inline]
39pub fn kind_matches(v: &Val, ty: KindType) -> bool {
40 matches!((v, ty),
41 (Val::Null, KindType::Null) |
42 (Val::Bool(_), KindType::Bool) |
43 (Val::Int(_), KindType::Number) |
44 (Val::Float(_), KindType::Number) |
45 (Val::Str(_), KindType::Str) |
46 (Val::Arr(_), KindType::Array) |
47 (Val::Obj(_), KindType::Object)
48 )
49}
50
51#[inline]
52pub fn vals_eq(a: &Val, b: &Val) -> bool {
53 match (a, b) {
54 (Val::Null, Val::Null) => true,
55 (Val::Bool(x), Val::Bool(y)) => x == y,
56 (Val::Str(x), Val::Str(y)) => x == y,
57 (Val::Int(x), Val::Int(y)) => x == y,
58 (Val::Float(x), Val::Float(y)) => x == y,
59 (Val::Int(x), Val::Float(y)) => (*x as f64) == *y,
60 (Val::Float(x), Val::Int(y)) => *x == (*y as f64),
61 _ => false,
62 }
63}
64
65#[inline]
66pub fn cmp_vals(a: &Val, b: &Val) -> std::cmp::Ordering {
67 match (a, b) {
68 (Val::Int(x), Val::Int(y)) => x.cmp(y),
69 (Val::Float(x), Val::Float(y)) => x.partial_cmp(y).unwrap_or(std::cmp::Ordering::Equal),
70 (Val::Int(x), Val::Float(y)) => (*x as f64).partial_cmp(y).unwrap_or(std::cmp::Ordering::Equal),
71 (Val::Float(x), Val::Int(y)) => x.partial_cmp(&(*y as f64)).unwrap_or(std::cmp::Ordering::Equal),
72 (Val::Str(x), Val::Str(y)) => x.cmp(y),
73 (Val::Bool(x), Val::Bool(y)) => x.cmp(y),
74 _ => std::cmp::Ordering::Equal,
75 }
76}
77
78#[inline]
82pub fn val_to_key(v: &Val) -> String {
83 match v {
84 Val::Str(s) => s.to_string(),
85 Val::Int(n) => n.to_string(),
86 Val::Float(f) => f.to_string(),
87 Val::Bool(b) => b.to_string(),
88 Val::Null => "null".to_string(),
89 other => val_to_string(other),
90 }
91}
92
93#[inline]
94pub fn val_to_string(v: &Val) -> String {
95 match v {
96 Val::Str(s) => s.to_string(),
97 Val::Int(n) => n.to_string(),
98 Val::Float(f) => f.to_string(),
99 Val::Bool(b) => b.to_string(),
100 Val::Null => "null".to_string(),
101 other => {
102 let sv: serde_json::Value = other.clone().into();
103 serde_json::to_string(&sv).unwrap_or_default()
104 }
105 }
106}
107
108#[inline] pub fn val_int(n: i64) -> Val { Val::Int(n) }
111#[inline] pub fn val_float(f: f64) -> Val { Val::Float(f) }
112#[inline] pub fn val_str(s: &str) -> Val { Val::Str(Arc::from(s)) }
113#[inline] pub fn val_key(s: &str) -> Arc<str> { Arc::from(s) }
114
115pub fn add_vals(a: Val, b: Val) -> Result<Val, EvalError> {
118 match (a, b) {
119 (Val::Int(x), Val::Int(y)) => Ok(Val::Int(x + y)),
120 (Val::Float(x), Val::Float(y)) => Ok(Val::Float(x + y)),
121 (Val::Int(x), Val::Float(y)) => Ok(Val::Float(x as f64 + y)),
122 (Val::Float(x), Val::Int(y)) => Ok(Val::Float(x + y as f64)),
123 (Val::Str(x), Val::Str(y)) => Ok(Val::Str(Arc::from(format!("{}{}", x, y).as_str()))),
124 (Val::Arr(x), Val::Arr(y)) => {
125 let mut v = Arc::try_unwrap(x).unwrap_or_else(|a| (*a).clone());
126 v.extend_from_slice(&y);
127 Ok(Val::arr(v))
128 }
129 _ => Err(EvalError("+ not supported between these types".into())),
130 }
131}
132
133pub fn num_op<Fi, Ff>(a: Val, b: Val, fi: Fi, ff: Ff) -> Result<Val, EvalError>
134where
135 Fi: Fn(i64, i64) -> i64,
136 Ff: Fn(f64, f64) -> f64,
137{
138 match (a, b) {
139 (Val::Int(x), Val::Int(y)) => Ok(Val::Int(fi(x, y))),
140 (Val::Float(x), Val::Float(y)) => Ok(Val::Float(ff(x, y))),
141 (Val::Int(x), Val::Float(y)) => Ok(Val::Float(ff(x as f64, y))),
142 (Val::Float(x), Val::Int(y)) => Ok(Val::Float(ff(x, y as f64))),
143 _ => Err(EvalError("arithmetic on non-numbers".into())),
144 }
145}
146
147pub fn flatten_val(v: Val, depth: usize) -> Val {
150 match v {
151 Val::Arr(a) if depth > 0 => {
152 let mut out = Vec::new();
153 let items = Arc::try_unwrap(a).unwrap_or_else(|a| (*a).clone());
154 for item in items {
155 match item {
156 Val::Arr(_) => if let Val::Arr(inner) = flatten_val(item, depth - 1) {
157 out.extend(Arc::try_unwrap(inner).unwrap_or_else(|a| (*a).clone()));
158 },
159 other => out.push(other),
160 }
161 }
162 Val::arr(out)
163 }
164 other => other,
165 }
166}
167
168pub fn zip_arrays(a: Val, b: Val, longest: bool, fill: Val) -> Result<Val, EvalError> {
169 let av = a.as_array().map(|a| a.to_vec()).unwrap_or_default();
170 let bv = b.as_array().map(|b| b.to_vec()).unwrap_or_default();
171 let len = if longest { av.len().max(bv.len()) } else { av.len().min(bv.len()) };
172 Ok(Val::arr((0..len).map(|i| Val::arr(vec![
173 av.get(i).cloned().unwrap_or_else(|| fill.clone()),
174 bv.get(i).cloned().unwrap_or_else(|| fill.clone()),
175 ])).collect()))
176}
177
178pub fn cartesian(arrays: &[Vec<Val>]) -> Vec<Vec<Val>> {
179 arrays.iter().fold(vec![vec![]], |acc, arr| {
180 acc.into_iter().flat_map(|prefix| {
181 arr.iter().map(move |item| {
182 let mut row = prefix.clone();
183 row.push(item.clone());
184 row
185 }).collect::<Vec<_>>()
186 }).collect()
187 })
188}
189
190pub fn field_exists_nested(v: &Val, path: &str) -> bool {
193 let mut parts = path.splitn(2, '.');
194 let first = parts.next().unwrap_or("");
195 match (v.get(first), parts.next()) {
196 (Some(v), _) if v.is_null() => false,
197 (Some(_), None) => true,
198 (Some(child), Some(rest)) => field_exists_nested(child, rest),
199 (None, _) => false,
200 }
201}
202
203pub fn deep_merge(base: Val, other: Val) -> Val {
206 match (base, other) {
207 (Val::Obj(bm), Val::Obj(om)) => {
208 let mut map = Arc::try_unwrap(bm).unwrap_or_else(|m| (*m).clone());
209 for (k, v) in Arc::try_unwrap(om).unwrap_or_else(|m| (*m).clone()) {
210 let existing = map.shift_remove(&k);
211 map.insert(k, match existing {
212 Some(e) => deep_merge(e, v),
213 None => v,
214 });
215 }
216 Val::obj(map)
217 }
218 (_, other) => other,
219 }
220}
221
222pub fn deep_merge_concat(base: Val, other: Val) -> Val {
225 match (base, other) {
226 (Val::Obj(bm), Val::Obj(om)) => {
227 let mut map = Arc::try_unwrap(bm).unwrap_or_else(|m| (*m).clone());
228 for (k, v) in Arc::try_unwrap(om).unwrap_or_else(|m| (*m).clone()) {
229 let existing = map.shift_remove(&k);
230 map.insert(k, match existing {
231 Some(e) => deep_merge_concat(e, v),
232 None => v,
233 });
234 }
235 Val::obj(map)
236 }
237 (Val::Arr(ba), Val::Arr(oa)) => {
238 let mut a = Arc::try_unwrap(ba).unwrap_or_else(|a| (*a).clone());
239 for v in Arc::try_unwrap(oa).unwrap_or_else(|a| (*a).clone()) { a.push(v); }
240 Val::arr(a)
241 }
242 (_, other) => other,
243 }
244}
245
246pub fn obj2(k1: &str, v1: Val, k2: &str, v2: Val) -> Val {
250 let mut m = IndexMap::with_capacity(2);
251 m.insert(val_key(k1), v1);
252 m.insert(val_key(k2), v2);
253 Val::obj(m)
254}