atom_engine/filters/
system.rs1use serde_json::{json, Value};
2use std::collections::HashMap;
3use std::sync::atomic::{AtomicUsize, Ordering};
4use tera::{Error, Function};
5
6use super::FilterResult;
7
8pub struct DumpFn;
9
10impl Function for DumpFn {
11 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
12 for (key, value) in args {
13 eprintln!("[dump] {} = {:?}", key, value);
14 }
15 Ok(Value::Null)
16 }
17}
18
19pub struct LogFn;
20
21impl Function for LogFn {
22 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
23 for (key, value) in args {
24 eprintln!("[log] {} = {:?}", key, value);
25 }
26 Ok(Value::Null)
27 }
28}
29
30pub struct RangeFn;
31
32impl Function for RangeFn {
33 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
34 let end = args
35 .get("end")
36 .and_then(|v| v.as_i64())
37 .ok_or_else(|| Error::msg("Missing 'end' argument"))?;
38 let start = args.get("start").and_then(|v| v.as_i64()).unwrap_or(0);
39 let step = args.get("step_by").and_then(|v| v.as_i64()).unwrap_or(1);
40
41 let result: Vec<Value> = (start..end)
42 .step_by(step as usize)
43 .map(|i| json!(i))
44 .collect();
45 Ok(Value::Array(result))
46 }
47}
48
49pub struct NowFn;
50
51impl Function for NowFn {
52 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
53 use chrono::Utc;
54 let _utc = args.get("utc").and_then(|v| v.as_bool()).unwrap_or(false);
55 let timestamp = args
56 .get("timestamp")
57 .and_then(|v| v.as_bool())
58 .unwrap_or(false);
59
60 if timestamp {
61 let now = Utc::now();
62 Ok(json!(now.timestamp()))
63 } else {
64 let now = Utc::now();
65 Ok(Value::String(now.to_rfc3339()))
66 }
67 }
68}
69
70pub struct CycleFn {
71 index: AtomicUsize,
72}
73
74impl CycleFn {
75 pub fn new() -> Self {
76 CycleFn {
77 index: AtomicUsize::new(0),
78 }
79 }
80}
81
82impl Default for CycleFn {
83 fn default() -> Self {
84 Self::new()
85 }
86}
87
88impl Function for CycleFn {
89 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
90 let values: Vec<Value> = (0..)
91 .map(|i| args.get(&format!("{}", i)))
92 .take_while(|v| v.is_some())
93 .map(|v| v.unwrap().clone())
94 .collect();
95 if values.is_empty() {
96 return Ok(Value::Null);
97 }
98 let idx = self.index.fetch_add(1, Ordering::SeqCst) % values.len();
99 Ok(values[idx].clone())
100 }
101}
102
103pub struct UuidFn;
104
105impl Function for UuidFn {
106 fn call(&self, _: &HashMap<String, Value>) -> FilterResult {
107 Ok(Value::String(uuid::Uuid::new_v4().to_string()))
108 }
109}
110
111pub struct RandomFn;
112
113impl Function for RandomFn {
114 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
115 use rand::Rng;
116 let mut rng = rand::thread_rng();
117 let min = args.get("min").and_then(|v| v.as_i64()).unwrap_or(0);
118 let max = args.get("max").and_then(|v| v.as_i64()).unwrap_or(100);
119 let result = rng.gen_range(min..=max);
120 Ok(Value::Number(result.into()))
121 }
122}
123
124pub struct ChoiceFn;
125
126impl Function for ChoiceFn {
127 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
128 use rand::seq::SliceRandom;
129 use rand::thread_rng;
130 let array = args
131 .get("array")
132 .ok_or_else(|| Error::msg("Missing array"))?;
133 let arr = array
134 .as_array()
135 .ok_or_else(|| Error::msg("Expected array"))?;
136 if arr.is_empty() {
137 return Ok(Value::Null);
138 }
139 let mut rng = thread_rng();
140 let choice = arr.choose(&mut rng).cloned();
141 Ok(choice.unwrap_or(Value::Null))
142 }
143}
144
145pub struct FileExistsFn;
146
147impl Function for FileExistsFn {
148 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
149 let path = args.get("path").and_then(|v| v.as_str()).unwrap_or("");
150 Ok(Value::Bool(std::path::Path::new(path).exists()))
151 }
152}
153
154pub struct EnvFn;
155
156impl Function for EnvFn {
157 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
158 let key = args.get("key").and_then(|v| v.as_str()).unwrap_or("");
159 Ok(Value::String(std::env::var(key).unwrap_or_default()))
160 }
161}
162
163pub struct Md5Fn;
164
165impl Function for Md5Fn {
166 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
167 use md5::{Digest, Md5};
168 let input = args.get("string").and_then(|v| v.as_str()).unwrap_or("");
169 let result = Md5::digest(input);
170 Ok(Value::String(hex::encode(result)))
171 }
172}
173
174pub struct Sha256Fn;
175
176impl Function for Sha256Fn {
177 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
178 use sha2::{Digest, Sha256};
179 let input = args.get("string").and_then(|v| v.as_str()).unwrap_or("");
180 let result = Sha256::digest(input);
181 Ok(Value::String(hex::encode(result)))
182 }
183}
184
185pub struct RepeatFn;
186
187impl Function for RepeatFn {
188 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
189 let count = args.get("count").and_then(|v| v.as_u64()).unwrap_or(1) as usize;
190 let content = args.get("content").and_then(|v| v.as_str()).unwrap_or("");
191 let separator = args.get("separator").and_then(|v| v.as_str()).unwrap_or("");
192
193 let result: Vec<String> = (0..count).map(|_| content.to_string()).collect();
194 Ok(Value::String(result.join(separator)))
195 }
196}
197
198pub struct TimesFn;
199
200impl Function for TimesFn {
201 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
202 let times = args.get("times").and_then(|v| v.as_u64()).unwrap_or(1) as usize;
203 let start = args.get("start").and_then(|v| v.as_i64()).unwrap_or(1);
204 let step = args.get("step").and_then(|v| v.as_i64()).unwrap_or(1);
205
206 let result: Vec<Value> = (0..times)
207 .map(|i| json!(start + (i as i64) * step))
208 .collect();
209 Ok(Value::Array(result))
210 }
211}
212
213pub struct LoopFn;
214
215impl Function for LoopFn {
216 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
217 let from = args.get("from").and_then(|v| v.as_i64()).unwrap_or(0);
218 let to = args.get("to").and_then(|v| v.as_i64()).unwrap_or(10);
219 let step = args.get("step").and_then(|v| v.as_i64()).unwrap_or(1);
220 let include = args
221 .get("inclusive")
222 .and_then(|v| v.as_bool())
223 .unwrap_or(false);
224
225 let end = if include { to + 1 } else { to };
226
227 let result: Vec<Value> = (from..end)
228 .step_by(step as usize)
229 .map(|i| json!({"index": i, "value": i}))
230 .collect();
231 Ok(Value::Array(result))
232 }
233}
234
235pub struct IterateFn;
236
237impl Function for IterateFn {
238 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
239 let array = args
240 .get("array")
241 .ok_or_else(|| Error::msg("Missing array"))?;
242 let arr = array
243 .as_array()
244 .ok_or_else(|| Error::msg("Expected array"))?;
245 let limit = args.get("limit").and_then(|v| v.as_u64()).unwrap_or(0) as usize;
246 let skip = args.get("skip").and_then(|v| v.as_u64()).unwrap_or(0) as usize;
247
248 let iter: Vec<Value> = arr
249 .iter()
250 .skip(skip)
251 .take(if limit > 0 { limit } else { arr.len() })
252 .enumerate()
253 .map(|(i, v)| serde_json::json!({"index": i, "value": v, "key": i}))
254 .collect();
255 Ok(Value::Array(iter))
256 }
257}
258
259pub struct ObjectFn;
260
261impl Function for ObjectFn {
262 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
263 let keys = args
264 .get("keys")
265 .and_then(|v| v.as_array())
266 .cloned()
267 .unwrap_or_default();
268 let values = args
269 .get("values")
270 .and_then(|v| v.as_array())
271 .cloned()
272 .unwrap_or_default();
273
274 let mut obj = serde_json::Map::new();
275 for (i, key) in keys.iter().enumerate() {
276 if let Some(k) = key.as_str() {
277 let v = values.get(i).cloned().unwrap_or(Value::Null);
278 obj.insert(k.to_string(), v);
279 }
280 }
281 Ok(Value::Object(obj))
282 }
283}
284
285pub struct MergeFn;
286
287impl Function for MergeFn {
288 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
289 let arr1 = args
290 .get("array1")
291 .and_then(|v| v.as_array())
292 .cloned()
293 .unwrap_or_default();
294 let arr2 = args
295 .get("array2")
296 .and_then(|v| v.as_array())
297 .cloned()
298 .unwrap_or_default();
299
300 let mut result = arr1;
301 result.extend(arr2);
302 Ok(Value::Array(result))
303 }
304}
305
306pub struct ChunkFn;
307
308impl Function for ChunkFn {
309 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
310 let array = args
311 .get("array")
312 .ok_or_else(|| Error::msg("Missing array"))?;
313 let arr = array
314 .as_array()
315 .ok_or_else(|| Error::msg("Expected array"))?;
316 let size = args.get("size").and_then(|v| v.as_u64()).unwrap_or(2) as usize;
317
318 let chunks: Vec<Value> = arr
319 .chunks(size)
320 .map(|chunk| Value::Array(chunk.to_vec()))
321 .collect();
322 Ok(Value::Array(chunks))
323 }
324}
325
326pub struct ZipFn;
327
328impl Function for ZipFn {
329 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
330 let arrays = args
331 .get("arrays")
332 .and_then(|v| v.as_array())
333 .cloned()
334 .unwrap_or_default();
335
336 if arrays.is_empty() {
337 return Ok(Value::Array(Vec::new()));
338 }
339
340 let max_len = arrays
341 .iter()
342 .map(|a| a.as_array().map(|a| a.len()).unwrap_or(0))
343 .max()
344 .unwrap_or(0);
345
346 let result: Vec<Value> = (0..max_len)
347 .map(|i| {
348 let items: Vec<Value> = arrays
349 .iter()
350 .filter_map(|a| a.as_array().and_then(|arr| arr.get(i).cloned()))
351 .collect();
352 Value::Array(items)
353 })
354 .collect();
355 Ok(Value::Array(result))
356 }
357}
358
359pub struct CompactFn;
360
361impl Function for CompactFn {
362 fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
363 let array = args
364 .get("array")
365 .ok_or_else(|| Error::msg("Missing array"))?;
366 let arr = array
367 .as_array()
368 .ok_or_else(|| Error::msg("Expected array"))?;
369
370 let result: Vec<Value> = arr
371 .iter()
372 .filter(|v| !v.is_null() && !v.as_array().map(|a| a.is_empty()).unwrap_or(false))
373 .cloned()
374 .collect();
375 Ok(Value::Array(result))
376 }
377}