synwire_core/runnables/
lambda.rs1use std::sync::Arc;
4
5use crate::BoxFuture;
6use crate::error::SynwireError;
7use crate::runnables::config::RunnableConfig;
8use crate::runnables::core::RunnableCore;
9use serde_json::Value;
10
11type LambdaFn = Arc<dyn Fn(Value) -> BoxFuture<'static, Result<Value, SynwireError>> + Send + Sync>;
13
14pub struct RunnableLambda {
29 func: LambdaFn,
30 name: String,
31}
32
33impl RunnableLambda {
34 pub fn new<F>(func: F) -> Self
36 where
37 F: Fn(Value) -> BoxFuture<'static, Result<Value, SynwireError>> + Send + Sync + 'static,
38 {
39 Self {
40 func: Arc::new(func),
41 name: "RunnableLambda".into(),
42 }
43 }
44
45 #[must_use]
47 pub fn with_name(mut self, name: impl Into<String>) -> Self {
48 self.name = name.into();
49 self
50 }
51}
52
53impl RunnableCore for RunnableLambda {
54 fn invoke<'a>(
55 &'a self,
56 input: Value,
57 _config: Option<&'a RunnableConfig>,
58 ) -> BoxFuture<'a, Result<Value, SynwireError>> {
59 (self.func)(input)
60 }
61
62 fn name(&self) -> &str {
63 &self.name
64 }
65}
66
67#[cfg(test)]
68#[allow(clippy::unwrap_used)]
69mod tests {
70 use super::*;
71
72 #[tokio::test]
73 async fn test_lambda_invokes() {
74 let lambda = RunnableLambda::new(|v: Value| {
75 Box::pin(async move {
76 let s = v.as_str().unwrap_or("").to_uppercase();
77 Ok(Value::from(s))
78 })
79 });
80
81 let result = lambda.invoke(Value::from("hello"), None).await.unwrap();
82 assert_eq!(result, Value::from("HELLO"));
83 }
84
85 #[tokio::test]
86 async fn test_lambda_with_name() {
87 let lambda =
88 RunnableLambda::new(|v: Value| Box::pin(async move { Ok(v) })).with_name("my_func");
89 assert_eq!(lambda.name(), "my_func");
90 }
91
92 #[tokio::test]
93 async fn test_lambda_default_name() {
94 let lambda = RunnableLambda::new(|v: Value| Box::pin(async move { Ok(v) }));
95 assert_eq!(lambda.name(), "RunnableLambda");
96 }
97}