zen_engine/model/
decision_content.rs

1use ahash::{HashMap, HashMapExt};
2use serde::{Deserialize, Serialize};
3use std::sync::Arc;
4use zen_expression::compiler::Opcode;
5use zen_expression::{ExpressionKind, Isolate};
6use zen_types::decision::{DecisionEdge, DecisionNode, DecisionNodeKind};
7
8#[derive(Clone, Debug, Eq, PartialEq, Hash)]
9pub struct CompilationKey {
10    pub kind: ExpressionKind,
11    pub source: Arc<str>,
12}
13#[derive(Clone, Debug, PartialEq, Deserialize, Serialize, Default)]
14#[serde(rename_all = "camelCase")]
15pub struct DecisionContent {
16    pub nodes: Vec<Arc<DecisionNode>>,
17    pub edges: Vec<Arc<DecisionEdge>>,
18
19    #[serde(skip)]
20    pub compiled_cache: Option<Arc<HashMap<CompilationKey, Vec<Opcode>>>>,
21}
22
23impl DecisionContent {
24    pub fn compile(&mut self) {
25        let mut compiled_cache: HashMap<CompilationKey, Vec<Opcode>> = HashMap::new();
26        let mut isolate = Isolate::new();
27
28        for node in &self.nodes {
29            match &node.kind {
30                DecisionNodeKind::ExpressionNode { content } => {
31                    for expression in content.expressions.iter() {
32                        if expression.key.is_empty() || expression.value.is_empty() {
33                            continue;
34                        }
35
36                        let key = CompilationKey {
37                            kind: ExpressionKind::Standard,
38                            source: Arc::clone(&expression.value),
39                        };
40
41                        if compiled_cache.contains_key(&key) {
42                            continue;
43                        }
44
45                        if let Ok(comp_expression) = isolate.compile_standard(&expression.value) {
46                            compiled_cache.insert(key, comp_expression.bytecode().to_vec());
47                        }
48                    }
49                }
50                DecisionNodeKind::DecisionTableNode { content } => {
51                    for rule in content.rules.iter() {
52                        for input in content.inputs.iter() {
53                            let Some(rule_value) = rule.get(&input.id) else {
54                                continue;
55                            };
56
57                            if rule_value.is_empty() {
58                                continue;
59                            }
60
61                            match &input.field {
62                                None => {
63                                    let key = CompilationKey {
64                                        kind: ExpressionKind::Standard,
65                                        source: Arc::clone(rule_value),
66                                    };
67
68                                    if !compiled_cache.contains_key(&key) {
69                                        if let Ok(comp_expression) =
70                                            isolate.compile_standard(rule_value)
71                                        {
72                                            compiled_cache
73                                                .insert(key, comp_expression.bytecode().to_vec());
74                                        }
75                                    }
76                                }
77                                Some(_field) => {
78                                    let key = CompilationKey {
79                                        kind: ExpressionKind::Unary,
80                                        source: Arc::clone(rule_value),
81                                    };
82
83                                    if !compiled_cache.contains_key(&key) {
84                                        if let Ok(comp_expression) =
85                                            isolate.compile_unary(rule_value)
86                                        {
87                                            compiled_cache
88                                                .insert(key, comp_expression.bytecode().to_vec());
89                                        }
90                                    }
91                                }
92                            }
93                        }
94
95                        for output in content.outputs.iter() {
96                            let Some(rule_value) = rule.get(&output.id) else {
97                                continue;
98                            };
99
100                            if rule_value.is_empty() {
101                                continue;
102                            }
103
104                            let key = CompilationKey {
105                                kind: ExpressionKind::Standard,
106                                source: Arc::clone(rule_value),
107                            };
108
109                            if !compiled_cache.contains_key(&key) {
110                                if let Ok(comp_expression) = isolate.compile_standard(rule_value) {
111                                    compiled_cache.insert(key, comp_expression.bytecode().to_vec());
112                                }
113                            }
114                        }
115                    }
116                }
117
118                _ => {}
119            }
120        }
121
122        self.compiled_cache.replace(Arc::new(compiled_cache));
123    }
124}