camel_language_api/
lib.rs1pub mod error;
9pub mod eval;
10pub mod language_limits;
11
12pub use async_trait::async_trait;
13pub use camel_api::Value;
14pub use camel_api::body::Body;
15pub use camel_api::exchange::Exchange;
16pub use camel_api::message::Message;
17pub use camel_api::{ErrorPosition, ExpressionErrorClass};
18pub use error::LanguageError;
19pub use eval::{
20 EvalMeta, LanguageExpressionEval, LanguagePredicateEval, is_expression_detail_cause,
21 to_expression_failed,
22};
23pub use language_limits::{
24 JsEngineConfig, JsLimitsConfig, LanguagesConfig, MinijinjaEngineConfig, MinijinjaLimitsConfig,
25 RhaiEngineConfig, RhaiLimitsConfig,
26};
27
28pub trait Language: Send + Sync {
30 fn name(&self) -> &'static str;
31 fn create_expression(&self, script: &str) -> Result<Box<dyn Expression>, LanguageError>;
32 fn create_predicate(&self, script: &str) -> Result<Box<dyn Predicate>, LanguageError>;
33
34 fn create_mutating_expression(
36 &self,
37 _script: &str,
38 ) -> Result<Box<dyn MutatingExpression>, LanguageError> {
39 Err(LanguageError::NotSupported {
40 feature: "mutating expressions".into(),
41 language: self.name().into(),
42 })
43 }
44
45 fn create_mutating_predicate(
47 &self,
48 _script: &str,
49 ) -> Result<Box<dyn MutatingPredicate>, LanguageError> {
50 Err(LanguageError::NotSupported {
51 feature: "mutating predicates".into(),
52 language: self.name().into(),
53 })
54 }
55}
56
57#[async_trait]
59pub trait Expression: Send + Sync {
60 async fn evaluate(&self, exchange: &Exchange) -> Result<Value, LanguageError>;
61}
62
63#[async_trait]
66pub trait MutatingExpression: Send + Sync {
67 async fn evaluate(&self, exchange: &mut Exchange) -> Result<Value, LanguageError>;
68}
69
70#[async_trait]
72pub trait Predicate: Send + Sync {
73 async fn matches(&self, exchange: &Exchange) -> Result<bool, LanguageError>;
74}
75
76#[async_trait]
81pub trait MutatingPredicate: Send + Sync {
82 async fn matches(&self, exchange: &mut Exchange) -> Result<bool, LanguageError>;
83}
84
85#[cfg(test)]
86mod tests {
87 use super::*;
88
89 struct MockLanguage;
91
92 impl Language for MockLanguage {
93 fn name(&self) -> &'static str {
94 "mock"
95 }
96
97 fn create_expression(&self, _script: &str) -> Result<Box<dyn Expression>, LanguageError> {
98 Ok(Box::new(MockExpression))
99 }
100
101 fn create_predicate(&self, _script: &str) -> Result<Box<dyn Predicate>, LanguageError> {
102 Ok(Box::new(MockPredicate))
103 }
104 }
105
106 struct MockExpression;
107
108 #[async_trait]
109 impl Expression for MockExpression {
110 async fn evaluate(&self, _exchange: &Exchange) -> Result<Value, LanguageError> {
111 Ok(Value::String("mock".into()))
112 }
113 }
114
115 struct MockPredicate;
116
117 #[async_trait]
118 impl Predicate for MockPredicate {
119 async fn matches(&self, _exchange: &Exchange) -> Result<bool, LanguageError> {
120 Ok(true)
121 }
122 }
123
124 #[test]
125 fn mock_language_returns_name() {
126 let lang = MockLanguage;
127 assert_eq!(lang.name(), "mock");
128 }
129
130 #[tokio::test]
131 async fn mock_language_creates_expression_and_evaluates() {
132 let lang = MockLanguage;
133 let expr = lang.create_expression("any").unwrap();
134 let ex = Exchange::new(Message::default());
135 let result = expr.evaluate(&ex).await.unwrap();
136 assert_eq!(result.as_str().unwrap(), "mock");
137 }
138
139 #[tokio::test]
140 async fn mock_language_creates_predicate_and_matches() {
141 let lang = MockLanguage;
142 let pred = lang.create_predicate("any").unwrap();
143 let ex = Exchange::new(Message::default());
144 assert!(pred.matches(&ex).await.unwrap());
145 }
146
147 #[test]
148 fn default_mutating_expression_returns_not_supported() {
149 let lang = MockLanguage;
150 let result = lang.create_mutating_expression("any");
151 assert!(matches!(result, Err(LanguageError::NotSupported { .. })));
152 if let Err(LanguageError::NotSupported { feature, language }) = result {
153 assert_eq!(feature, "mutating expressions");
154 assert_eq!(language, "mock");
155 }
156 }
157
158 #[test]
159 fn default_mutating_predicate_returns_not_supported() {
160 let lang = MockLanguage;
161 let result = lang.create_mutating_predicate("any");
162 assert!(matches!(result, Err(LanguageError::NotSupported { .. })));
163 }
164
165 #[test]
166 fn language_trait_is_send_sync() {
167 fn assert_send_sync<T: Send + Sync>() {}
168 assert_send_sync::<MockLanguage>();
169 }
170}