moduforge_rules_engine/
engine.rs

1use std::future::Future;
2use std::sync::Arc;
3
4use crate::decision::Decision;
5use crate::handler::custom_node_adapter::{CustomNodeAdapter, NoopCustomNode};
6use crate::handler::graph::DecisionGraphResponse;
7use crate::loader::{
8    ClosureLoader, DecisionLoader, LoaderResponse, LoaderResult, NoopLoader,
9};
10use crate::model::DecisionContent;
11use crate::EvaluationError;
12use moduforge_rules_expression::variable::Variable;
13
14/// 决策引擎结构体,用于生成和评估决策
15#[derive(Debug, Clone)]
16pub struct DecisionEngine<Loader, CustomNode>
17where
18    Loader: DecisionLoader + 'static,
19    CustomNode: CustomNodeAdapter + 'static,
20{
21    loader: Arc<Loader>,
22    adapter: Arc<CustomNode>,
23}
24
25#[derive(Debug, Default)]
26pub struct EvaluationOptions {
27    pub trace: Option<bool>,
28    pub max_depth: Option<u8>,
29}
30
31impl Default for DecisionEngine<NoopLoader, NoopCustomNode> {
32    fn default() -> Self {
33        Self {
34            loader: Arc::new(NoopLoader::default()),
35            adapter: Arc::new(NoopCustomNode::default()),
36        }
37    }
38}
39
40impl<L: DecisionLoader + 'static, A: CustomNodeAdapter + 'static>
41    DecisionEngine<L, A>
42{
43    pub fn new(
44        loader: Arc<L>,
45        adapter: Arc<A>,
46    ) -> Self {
47        Self { loader, adapter }
48    }
49
50    pub fn with_adapter<CustomNode>(
51        self,
52        adapter: Arc<CustomNode>,
53    ) -> DecisionEngine<L, CustomNode>
54    where
55        CustomNode: CustomNodeAdapter,
56    {
57        DecisionEngine { loader: self.loader, adapter }
58    }
59
60    pub fn with_loader<Loader>(
61        self,
62        loader: Arc<Loader>,
63    ) -> DecisionEngine<Loader, A>
64    where
65        Loader: DecisionLoader,
66    {
67        DecisionEngine { loader, adapter: self.adapter }
68    }
69
70    pub fn with_closure_loader<F, O>(
71        self,
72        loader: F,
73    ) -> DecisionEngine<ClosureLoader<F>, A>
74    where
75        F: Fn(String) -> O + Sync + Send,
76        O: Future<Output = LoaderResponse> + Send,
77    {
78        DecisionEngine {
79            loader: Arc::new(ClosureLoader::new(loader)),
80            adapter: self.adapter,
81        }
82    }
83
84    /// 使用 key 评估决策
85    pub async fn evaluate<K>(
86        &self,
87        key: K,
88        context: Variable,
89    ) -> Result<DecisionGraphResponse, Box<EvaluationError>>
90    where
91        K: AsRef<str>,
92    {
93        self.evaluate_with_opts(key, context, Default::default()).await
94    }
95    /// 使用 State 和选项评估决策
96    ///
97    /// 使用 RAII 模式确保 State 的异常安全管理
98    pub async fn evaluate_with_state_and_opts<K, S: Send + Sync + 'static>(
99        &self,
100        key: K,
101        context: Variable,
102        state: Arc<S>,
103        options: EvaluationOptions,
104    ) -> Result<DecisionGraphResponse, Box<EvaluationError>>
105    where
106        K: AsRef<str>,
107    {
108        // 使用 StateGuard 自动管理 State 生命周期
109        let _guard = moduforge_rules_expression::StateGuard::new(state);
110
111        // 执行评估,即使发生异常,State 也会被正确清理
112        self.evaluate_with_opts(key, context, options).await
113    }
114    /// 使用 State 评估决策
115    ///
116    /// 使用 RAII 模式确保 State 的异常安全管理
117    pub async fn evaluate_with_state<K, S: Send + Sync + 'static>(
118        &self,
119        key: K,
120        context: Variable,
121        state: Arc<S>,
122    ) -> Result<DecisionGraphResponse, Box<EvaluationError>>
123    where
124        K: AsRef<str>,
125    {
126        // 使用 StateGuard 自动管理 State 生命周期
127        let _guard = moduforge_rules_expression::StateGuard::new(state);
128
129        // 执行评估,即使发生异常,State 也会被正确清理
130        self.evaluate(key, context).await
131    }
132
133    /// 使用 key 评估决策,并使用高级选项
134    pub async fn evaluate_with_opts<K>(
135        &self,
136        key: K,
137        context: Variable,
138        options: EvaluationOptions,
139    ) -> Result<DecisionGraphResponse, Box<EvaluationError>>
140    where
141        K: AsRef<str>,
142    {
143        let content = self.loader.load(key.as_ref()).await?;
144        let decision = self.create_decision(content);
145        decision.evaluate_with_opts(context, options).await
146    }
147
148    /// 从 DecisionContent 创建决策,用于更简单的绑定创建
149    pub fn create_decision(
150        &self,
151        content: Arc<DecisionContent>,
152    ) -> Decision<L, A> {
153        Decision::from(content)
154            .with_loader(self.loader.clone())
155            .with_adapter(self.adapter.clone())
156    }
157
158    /// 根据 loader 获取决策
159    pub async fn get_decision(
160        &self,
161        key: &str,
162    ) -> LoaderResult<Decision<L, A>> {
163        let content = self.loader.load(key).await?;
164        Ok(self.create_decision(content))
165    }
166
167    pub fn loader(&self) -> &L {
168        self.loader.as_ref()
169    }
170
171    pub fn adapter(&self) -> &A {
172        self.adapter.as_ref()
173    }
174}