Skip to main content

atom_engine/filters/
component.rs

1use serde_json::{json, Value};
2use std::collections::HashMap;
3use tera::Function;
4
5use super::FilterResult;
6
7pub fn slot_filter(name: &Value, _: &HashMap<String, Value>) -> FilterResult {
8    let slot_name = name.as_str().unwrap_or("default").trim_start_matches('$');
9    let slot_key = format!("__slot_{}", slot_name);
10    if let Some(slot_content) = name.get(&slot_key) {
11        return Ok(slot_content.clone());
12    }
13    Ok(Value::String(String::new()))
14}
15
16pub fn has_slot_filter(name: &Value, _: &HashMap<String, Value>) -> FilterResult {
17    let slot_name = name.as_str().unwrap_or("default").trim_start_matches('$');
18    let slot_key = format!("__slot_{}", slot_name);
19    Ok(Value::Bool(name.get(&slot_key).is_some()))
20}
21
22pub fn stack_filter(name: &Value, _: &HashMap<String, Value>) -> FilterResult {
23    let stack_name = name.as_str().unwrap_or("");
24    let stack_key = format!("__stack_{}", stack_name);
25    Ok(name
26        .get(&stack_key)
27        .cloned()
28        .unwrap_or(Value::String(String::new())))
29}
30
31pub fn scoped_slot_filter(args: &Value, _: &HashMap<String, Value>) -> FilterResult {
32    let slot_name = args
33        .get("slot")
34        .and_then(|v| v.as_str())
35        .unwrap_or("default");
36    let data_key = args.get("key").and_then(|v| v.as_str()).unwrap_or("item");
37    let default_value = args.get("default");
38
39    let _slot_key = format!("__scoped_slot_{}", slot_name);
40    let data_key_full = format!("__scoped_data_{}_{}", slot_name, data_key);
41
42    if let Some(data) = args.get(&data_key_full) {
43        return Ok(data.clone());
44    }
45
46    Ok(default_value.cloned().unwrap_or(Value::Null))
47}
48
49pub fn with_scoped_data_filter(args: &Value, _: &HashMap<String, Value>) -> FilterResult {
50    let slot_name = args
51        .get("slot")
52        .and_then(|v| v.as_str())
53        .unwrap_or("default");
54    let data = args.get("data").cloned().unwrap_or(Value::Null);
55
56    let mut result = json!({
57        "slot": slot_name,
58        "data": data,
59    });
60
61    if let Some(obj) = result.as_object_mut() {
62        if let Some(data_obj) = data.as_object() {
63            for (key, value) in data_obj {
64                obj.insert(
65                    format!("__scoped_data_{}_{}", slot_name, key),
66                    value.clone(),
67                );
68            }
69        }
70    }
71
72    Ok(result)
73}
74
75pub struct PushFn;
76
77impl Function for PushFn {
78    fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
79        let stack_name = args
80            .get("name")
81            .and_then(|v| v.as_str())
82            .unwrap_or("default");
83        let content = args.get("content").and_then(|v| v.as_str()).unwrap_or("");
84        let stack_key = format!("__stack_{}", stack_name);
85        Ok(Value::String(format!("{}__push__ {}", stack_key, content)))
86    }
87}
88
89pub struct PrependFn;
90
91impl Function for PrependFn {
92    fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
93        let stack_name = args
94            .get("name")
95            .and_then(|v| v.as_str())
96            .unwrap_or("default");
97        let content = args.get("content").and_then(|v| v.as_str()).unwrap_or("");
98        let stack_key = format!("__stack_{}", stack_name);
99        Ok(Value::String(format!(
100            "{}__prepend__ {}",
101            stack_key, content
102        )))
103    }
104}
105
106pub struct SetSlotFn;
107
108impl Function for SetSlotFn {
109    fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
110        let slot_name = args
111            .get("name")
112            .and_then(|v| v.as_str())
113            .unwrap_or("default")
114            .trim_start_matches('$');
115        let content = args.get("content").and_then(|v| v.as_str()).unwrap_or("");
116        let slot_key = format!("__slot_{}", slot_name);
117        Ok(Value::String(format!("{} {}", slot_key, content)))
118    }
119}
120
121pub struct OnceFn;
122
123impl Function for OnceFn {
124    fn call(&self, args: &HashMap<String, Value>) -> FilterResult {
125        let key = args
126            .get("key")
127            .and_then(|v| v.as_str())
128            .unwrap_or("default");
129        let hash = simple_hash(key);
130        let content = args.get("content").and_then(|v| v.as_str()).unwrap_or("");
131        Ok(json!({ "key": hash, "content": content }))
132    }
133}
134
135fn simple_hash(s: &str) -> u64 {
136    let mut hash: u64 = 0;
137    for (i, c) in s.bytes().enumerate() {
138        hash = hash.wrapping_add((c as u64).wrapping_mul(31_u64.wrapping_pow(i as u32)));
139    }
140    hash
141}