Skip to main content

argentum_event_business/
lib.rs

1//! Event component
2//!
3//! The easiest way to work with events, listeners, and dispatchers
4//! Provides a macro to create and manage your own events
5
6///
7/// The way to create event and boilerplate to listening and dispatching
8///
9/// ```rust
10/// use argentum_event_business::event_boilerplate;
11///
12/// // Event type
13/// pub struct MyEvent {}
14///
15/// // Create a boilerplate
16/// event_boilerplate!(MyEvent, MyEventListenerTrait, MyEventDispatcher);
17///
18/// ```
19///
20/// It is equivalent of a code below.
21///
22/// ```rust
23/// use argentum_event_business::event_boilerplate;
24///
25/// pub struct MyEvent {}
26///
27/// pub trait MyEventListenerTrait {
28///     fn listen(&self, _e: &MyEvent) {}
29/// }
30///
31/// pub struct MyEventDispatcher<Listener: MyEventListenerTrait> {
32///     listeners: Vec<Listener>,
33/// }
34///
35/// impl<Listener: MyEventListenerTrait> MyEventDispatcher<Listener> {
36///     pub fn new(listeners: Vec<Listener>) -> MyEventDispatcher<Listener> {
37///         MyEventDispatcher { listeners }
38///     }
39///
40///     pub fn dispatch(&self, e: &MyEvent) {
41///         self.listeners.iter().for_each(move |l| {
42///             l.listen(e);
43///         });
44///     }
45/// }
46/// ```
47///
48/// Of course, you can do it manually but macro provides the shorter and easier way.
49///
50///
51/// Next step: create a listener
52///
53/// ```ignore
54/// pub struct MyListener {}
55///
56/// impl MyEventListenerTrait for MyListener {
57///     fn listen(&self, _e: &MyEvent) {
58///         println!("listened MyEvent")
59///     }
60/// }
61///```
62///
63/// Instantiate a listener, and a dispatcher. We mean that you will inject a dispatcher in your services
64///
65/// ```ignore
66/// let my_listener = MyListener {};
67/// let my_dispatcher = MyEventDispatcher::new(vec![my_listener]);
68/// ```
69///
70/// Now we can emit an event
71///
72/// ```ignore
73/// let e = MyEvent {};
74/// my_dispatcher.dispatch(&e);
75/// ```
76///
77#[macro_export]
78macro_rules! event_boilerplate {
79    ($event: ident, $listener_trait:ident, $dispatcher:ident) => {
80        pub trait $listener_trait {
81            fn listen(&self, _e: &$event) {}
82        }
83
84        pub struct $dispatcher<Listener: $listener_trait> {
85            listeners: Vec<Listener>,
86        }
87
88        impl<Listener: $listener_trait> $dispatcher<Listener> {
89            pub fn new(listeners: Vec<Listener>) -> $dispatcher<Listener> {
90                $dispatcher { listeners }
91            }
92
93            pub fn dispatch(&self, e: &$event) {
94                self.listeners.iter().for_each(move |l| {
95                    l.listen(e);
96                });
97            }
98        }
99    };
100}
101
102#[cfg(test)]
103mod test {
104    pub struct TestEvent {
105        user_id: u8,
106    }
107
108    impl TestEvent {
109        pub fn new(user_id: u8) -> TestEvent {
110            TestEvent { user_id }
111        }
112    }
113
114    event_boilerplate!(TestEvent, TestListenerTrait, TestEventDispatcher);
115
116    pub struct TestListener {}
117
118    impl TestListenerTrait for TestListener {
119        fn listen(&self, e: &TestEvent) {
120            println!("listened TestEvent for user. user_id {}", e.user_id)
121        }
122    }
123
124    #[test]
125    fn test() -> Result<(), &'static str> {
126        let listener = TestListener {};
127        let dispatcher = TestEventDispatcher::new(vec![listener]);
128
129        let event = TestEvent::new(1);
130        dispatcher.dispatch(&event);
131
132        assert_eq!(1, 1);
133
134        Ok(())
135    }
136}