zen_engine/model/
decision_content.rs1use 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}