plux_rs/function/
function.rs1use std::fmt::{Debug, Display};
2
3use crate::variable::Variable;
4
5use super::Arg;
6
7pub trait Function: Send + Sync {
8 type Output: Send + Sync;
9
10 fn name(&self) -> String;
11 fn inputs(&self) -> Vec<Arg>;
12 fn output(&self) -> Option<Arg>;
13 fn call(&self, args: &[Variable]) -> Self::Output;
14}
15
16impl<O: Send + Sync> PartialEq for dyn Function<Output = O> {
17 fn eq(&self, other: &Self) -> bool {
18 self.name() == other.name()
19 && self.inputs() == other.inputs()
20 && self.output() == other.output()
21 }
22}
23
24impl<O: Send + Sync> Eq for dyn Function<Output = O> {}
25
26impl<O: Send + Sync> Display for dyn Function<Output = O> {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 write!(
34 f,
35 "{}({}) -> {}",
36 self.name(),
37 self.inputs()
38 .iter()
39 .map(|x| format!("{x}"))
40 .collect::<Vec<_>>()
41 .join(", "),
42 match self.output() {
43 Some(arg) => format!("{}({})", arg.name, arg.ty),
44 None => "void".to_string(),
45 }
46 )
47 }
48}
49
50impl<O: Send + Sync> Debug for dyn Function<Output = O> {
51 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
52 Display::fmt(self, f)
53 }
54}
55
56pub type FunctionOutput = Result<Option<Variable>, Box<dyn std::error::Error + Send + Sync>>;
57
58pub struct DynamicFunction {
59 name: String,
60 inputs: Vec<Arg>,
61 output: Option<Arg>,
62 ptr: Box<dyn Fn(&[Variable]) -> FunctionOutput + Send + Sync>,
63}
64
65impl DynamicFunction {
66 pub fn new<S, F>(name: S, inputs: Vec<Arg>, output: Option<Arg>, ptr: F) -> Self
67 where
68 S: Into<String>,
69 F: Fn(&[Variable]) -> FunctionOutput + Send + Sync + 'static,
70 {
71 Self {
72 name: name.into(),
73 inputs,
74 output,
75 ptr: Box::new(ptr),
76 }
77 }
78}
79
80impl Function for DynamicFunction {
81 type Output = FunctionOutput;
82
83 fn name(&self) -> String {
84 self.name.clone()
85 }
86
87 fn inputs(&self) -> Vec<Arg> {
88 self.inputs.clone()
89 }
90
91 fn output(&self) -> Option<Arg> {
92 self.output.clone()
93 }
94
95 fn call(&self, args: &[Variable]) -> Self::Output {
96 (self.ptr)(args)
97 }
98}
99
100#[test]
101fn function_call() {
102 use crate::variable::VariableType;
103
104 let func = DynamicFunction::new(
106 "add",
107 vec![
108 Arg::new("a", VariableType::I32),
109 Arg::new("b", VariableType::I32),
110 ],
111 Some(Arg::new("c", VariableType::I32)),
112 |args| -> FunctionOutput {
113 let a = args[0].parse_ref::<i32>();
114 let b = args[1].parse_ref::<i32>();
115
116 let c = a + b;
117
118 println!("{} + {} = {}", a, b, c);
119
120 Ok(Some(c.into()))
121 },
122 );
123
124 let c = func.call(&[1.into(), 2.into()]);
126
127 assert!(c.is_ok());
128 assert_eq!(c.unwrap(), Some(3.into()));
129}
130
131#[test]
132fn parallel_call() {
133 use crate::variable::VariableType;
134 use std::{sync::Arc, thread, time::Duration};
135
136 let func = DynamicFunction::new(
138 "log",
139 vec![Arg::new("n", VariableType::I32)],
140 None,
141 |args| -> FunctionOutput {
142 let n = args[0].parse_ref::<i32>();
143
144 println!("Step {n}");
145
146 Ok(None)
147 },
148 );
149
150 let func = Arc::new(func);
152
153 let mut handles = vec![];
154 for i in 0..10 {
155 let func = func.clone();
156 let args: Arc<[Variable]> = Arc::new([i.into()]);
157
158 handles.push(thread::spawn(move || {
159 thread::sleep(Duration::from_secs(1));
160
161 let result = func.call(&args.as_ref());
162
163 assert!(result.is_ok());
164 assert_eq!(result.unwrap(), None);
165 }));
166 }
167
168 for handle in handles {
169 handle.join().unwrap();
170 }
171}