1use std::sync::Arc;
2
3use sofie_core::Result;
4
5use crate::{BoxFuture, Outcome, Reply, Resolve};
6
7pub trait Call<C, Args>: Clone + Send + Sync + 'static {
8 type Outcome: Outcome + 'static;
9
10 fn call(&self, context: &mut C) -> impl Future<Output = Result<Self::Outcome>> + Send;
11}
12
13macro_rules! call {
14 ($($argument:ident),*) => {
15 impl<C, F, Fut, O, $($argument,)*> Call<C, ($($argument,)*)> for F
16 where
17 C: Send,
18 F: Fn($($argument),*) -> Fut + Clone + Send + Sync + 'static,
19 Fut: Future<Output = Result<O>> + Send,
20 O: Outcome + 'static,
21 $($argument: Resolve<C> + Send,)*
22 {
23 type Outcome = O;
24
25 #[allow(non_snake_case, unused_variables, reason = "arguments are named after their types")]
26 fn call(&self, context: &mut C) -> impl Future<Output = Result<O>> + Send {
27 async move {
28 $(let $argument = $argument::resolve(context).await?;)*
29 self($($argument),*).await
30 }
31 }
32 }
33 };
34}
35
36macro_rules! calls {
37 () => {
38 call!();
39 };
40 ($first:ident $(, $rest:ident)*) => {
41 call!($first $(, $rest)*);
42 calls!($($rest),*);
43 };
44}
45
46calls!(T1, T2, T3, T4, T5, T6, T7, T8, T9, T10, T11, T12);
47
48pub trait AnyOutcome: Outcome {
49 fn into_reply(self: Box<Self>) -> Result<Reply>;
50}
51
52impl<O: Outcome> AnyOutcome for O {
53 fn into_reply(self: Box<Self>) -> Result<Reply> {
54 (*self).reply()
55 }
56}
57
58pub type Run<C> =
59 Arc<dyn for<'c> Fn(&'c mut C) -> BoxFuture<'c, Result<Box<dyn AnyOutcome>>> + Send + Sync>;
60
61pub fn erase<C: Send + 'static, Args, F: Call<C, Args>>(function: F) -> Run<C> {
62 Arc::new(move |context| {
63 let function = function.clone();
64 Box::pin(async move {
65 let outcome = function.call(context).await?;
66 Ok(Box::new(outcome) as Box<dyn AnyOutcome>)
67 })
68 })
69}
70
71#[derive(Clone, Copy, Debug, PartialEq, Eq)]
72pub enum Trigger {
73 Queued,
75 On(&'static str),
76 Every(crate::worker::Cadence),
77}
78
79pub struct Entry<C> {
80 pub name: &'static str,
81 pub trigger: Trigger,
82 pub run: Run<C>,
83}