1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
macro_rules! handler {
    (
        $context:path,
        $(#[doc = $doc:literal])+
        $name:ident,
        $(#[doc = $doc_if:literal])+
        $name_if:ident,
    ) => {
        $(#[doc = $doc])+
        pub fn $name<H, F>(&mut self, handler: H)
        where
            H: (Fn(std::sync::Arc<$context>) -> F) + Send + Sync + 'static,
            F: std::future::Future<Output = ()> + Send + 'static,
        {
            let set: fn(&mut Self, H) = paste::expr!(|event_loop, handler| {
                event_loop.[<$name _handlers>].push(Box::new(move |context| {
                    tokio::spawn(handler(context));
                }))
            });

            set(self, handler)
        }

        $(#[doc = $doc_if])+
        pub fn $name_if<H, HF, P, PF>(
            &mut self,
            predicate: P,
            handler: H,
        ) where
            H: (Fn(Arc<$context>) -> HF)
                + Send
                + Sync
                + 'static,
            HF: Future<Output = ()> + Send + 'static,
            P: (Fn(Arc<$context>) -> PF)
                + Send
                + Sync
                + 'static,
            PF: Future<Output = bool> + Send + 'static,
        {
            let predicate = Arc::new(predicate);
            let handler = Arc::new(handler);
            self.$name(move |context| {
                let predicate = Arc::clone(&predicate);
                let handler = Arc::clone(&handler);
                async move {
                    if predicate(Arc::clone(&context)).await {
                        handler(context).await
                    }
                }
            });
        }

        paste::item! {
            #[allow(dead_code)]
            fn [<will_handle_ $name>](&self) -> bool {
                !self.[<$name _handlers>].is_empty()
            }
        }

        paste::item! {
            fn [<run_ $name _handlers>](&self, context: std::sync::Arc<$context>) {
                &self.[<$name _handlers>].iter().for_each(|handler| {
                    handler(context.clone());
                });
            }
        }
    };
}