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