1use std::{borrow::Cow, future::Future};
4
5use async_trait::async_trait;
6use serde::{de::DeserializeOwned, Serialize};
7use serde_json::Error;
8use specta::{function::FunctionDataType, Type, TypeMap};
9
10use crate::util::TripleS;
11
12#[async_trait]
15pub trait GenericProcedure<Cx: Send + Sync> {
16 async fn run(&self, cx: Cx, data: String) -> Result<String, Error>;
19
20 fn specta_type(&self, name: Cow<'static, str>, map: &mut TypeMap) -> FunctionDataType;
22}
23
24#[async_trait]
25impl<
26 Cx: TripleS + Clone,
27 Output: Send + Sync + Serialize + Type,
28 Arg: Send + Sync + 'static + DeserializeOwned + Type,
29 > GenericProcedure<Cx> for WrappedProcedure<Cx, Output, Arg>
30{
31 async fn run(&self, cx: Cx, mut data: String) -> Result<String, Error> {
32 if data.is_empty() {
33 data = String::from("null");
34 }
35
36 serde_json::to_string(&self.0.exec(cx, serde_json::from_str(&data)?).await)
37 }
38
39 fn specta_type(&self, name: Cow<'static, str>, map: &mut TypeMap) -> FunctionDataType {
40 self.0.specta_type(name, map)
41 }
42}
43
44pub struct WrappedProcedure<
49 Cx: TripleS + Clone,
50 Output: Send + Sync + Serialize + Type,
51 Arg: Send + Sync + 'static + DeserializeOwned + Type,
52>(Box<dyn Procedure<Cx, Output, Arg> + Send + Sync>);
53
54#[async_trait]
56pub trait Procedure<
57 Cx: TripleS + Clone,
58 Output: Send + Sync + Serialize + Type,
59 Arg: Send + Sync + DeserializeOwned + Type,
60>
61{
62 async fn exec(&self, cx: Cx, data: Arg) -> Output;
64}
65
66pub trait TypedProcedure<
68 Cx: TripleS + Clone,
69 Output: Send + Sync + Serialize + Type,
70 Arg: Send + Sync + DeserializeOwned + Type,
71>: Procedure<Cx, Output, Arg>
72{
73 fn specta_type(&self, name: Cow<'static, str>, map: &mut TypeMap) -> FunctionDataType;
75}
76
77#[async_trait]
78impl<
79 Cx: TripleS + Clone,
80 Output: Send + Sync + Serialize + Type,
81 Fut: Future<Output = Output> + Send,
82 Arg: Send + Sync + 'static + DeserializeOwned + Type,
83 Func: (Fn(Cx, Arg) -> Fut) + Send + Sync + 'static,
84 > Procedure<Cx, Output, Arg> for Func
85{
86 async fn exec(&self, cx: Cx, data: Arg) -> Output {
87 self(cx, data).await
88 }
89}
90
91impl<
92 Cx: TripleS + Clone,
93 Output: Send + Sync + Serialize + Type,
94 Arg: Send + Sync + 'static + DeserializeOwned + Type,
95 Proc: Procedure<Cx, Output, Arg> + ?Sized,
96 > TypedProcedure<Cx, Output, Arg> for Proc
97{
98 fn specta_type(&self, name: Cow<'static, str>, map: &mut TypeMap) -> FunctionDataType {
99 FunctionDataType {
100 args: vec![("data".into(), Arg::reference(map, &[]).inner)],
101 asyncness: true,
102 deprecated: None,
103 name,
104 docs: "".into(),
105 result: Some(Output::reference(map, &[]).inner),
106 }
107 }
108}
109
110pub fn wrap<
113 Cx: TripleS + Clone,
114 Output: Send + Sync + Serialize + Type,
115 Arg: Send + Sync + 'static + DeserializeOwned + Type,
116 Proc: Procedure<Cx, Output, Arg> + Send + Sync + 'static,
117>(
118 proc: Proc,
119) -> WrappedProcedure<Cx, Output, Arg> {
120 WrappedProcedure(Box::new(proc))
121}