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