amico_core/traits/
handlers.rs

1use anyhow::Result;
2use evenio::event::EventMut;
3
4use crate::ecs;
5
6use super::System;
7
8/// The Observer trait is used to observe events.
9///
10/// Observers watch for an event and process it, without
11/// modifying the event and affecting the state of the world.
12pub trait Observer {
13    /// The event type that the Observer observes.
14    type Event: ecs::GlobalEvent + 'static;
15
16    /// The observe method is called when the Observer is notified of an event.
17    ///
18    /// The method receives a reference to the event and returns a Result.
19    fn observe(&self, event: &<Self::Event as ecs::Event>::This<'_>) -> Result<()>;
20
21    /// Converts the Observer into a SystemHandler.
22    fn to_system(self) -> SystemHandler<Self, PhantomMediator>
23    where
24        Self: Sized,
25    {
26        SystemHandler::Observer(self)
27    }
28}
29
30/// The Mediator trait is used to mediate events.
31///
32/// Mediators watch for an event and process it, and finally
33/// take ownership of the event.
34///
35/// After processing, Mediators may send new events to the world.
36pub trait Mediator {
37    /// The event type that the Mediator mediates.
38    type Event: ecs::GlobalEvent + ecs::Event<Mutability = ecs::Mutable>;
39
40    /// The event type that the Mediator sends.
41    type EventsToSend: ecs::EventSet;
42
43    /// The mediate method is called when the Mediator is notified of an event.
44    ///
45    /// The method receives a mutable reference to the event and a sender to send
46    /// new events to the world.
47    fn mediate(
48        &self,
49        event: &mut EventMut<'_, Self::Event>,
50        sender: ecs::Sender<Self::EventsToSend>,
51    ) -> Result<()>;
52
53    /// Converts the Mediator into a SystemHandler.
54    fn to_system(self) -> SystemHandler<PhantomObserver, Self>
55    where
56        Self: Sized,
57    {
58        SystemHandler::Mediator(self)
59    }
60}
61
62/// The placeholder event for the observer and mediator to use in SystemHandler.
63#[derive(ecs::GlobalEvent)]
64pub struct PhantomEvent;
65
66/// The placeholder observer for SystemHandler.
67pub struct PhantomObserver;
68
69/// The placeholder mediator for SystemHandler.
70pub struct PhantomMediator;
71
72impl Observer for PhantomObserver {
73    type Event = PhantomEvent;
74
75    fn observe(&self, _event: &<Self::Event as ecs::Event>::This<'_>) -> Result<()> {
76        Ok(())
77    }
78}
79
80impl Mediator for PhantomMediator {
81    type Event = PhantomEvent;
82    type EventsToSend = ();
83
84    fn mediate(
85        &self,
86        _event: &mut EventMut<'_, Self::Event>,
87        _sender: ecs::Sender<Self::EventsToSend>,
88    ) -> Result<()> {
89        Ok(())
90    }
91}
92
93/// The SystemHandler is a middleware to convert an Observer or Mediator into a System.
94pub enum SystemHandler<
95    O: Observer + 'static = PhantomObserver,
96    M: Mediator + 'static = PhantomMediator,
97> {
98    /// The Observer handler variant.
99    Observer(O),
100
101    /// The Mediator handler variant.
102    Mediator(M),
103}
104
105impl<O, M> System for SystemHandler<O, M>
106where
107    O: Observer + 'static,
108    M: Mediator + 'static,
109{
110    fn register_to(self, mut registry: crate::world::HandlerRegistry) {
111        match self {
112            SystemHandler::Observer(observer) => {
113                registry.register(move |r: ecs::Receiver<O::Event>| {
114                    if let Err(err) = observer.observe(r.event) {
115                        tracing::error!("Error in observer: {}", err);
116                    }
117                })
118            }
119            SystemHandler::Mediator(mediator) => {
120                registry.register(
121                    move |mut r: ecs::ReceiverMut<M::Event>,
122                          sender: ecs::Sender<M::EventsToSend>| {
123                        if let Err(err) = mediator.mediate(&mut r.event, sender) {
124                            tracing::error!("Error in mediator: {}", err);
125                        }
126
127                        // Take ownership of the event after handling it.
128                        EventMut::take(r.event);
129                    },
130                )
131            }
132        }
133    }
134}
135
136#[cfg(test)]
137mod tests {
138    use evenio::prelude::*;
139
140    use crate::world::HandlerRegistry;
141
142    use super::*;
143
144    #[derive(ecs::GlobalEvent)]
145    struct TestEvent(i32);
146
147    #[derive(ecs::GlobalEvent)]
148    struct TestEvent2(i32);
149
150    struct TestObserver;
151
152    impl Observer for TestObserver {
153        type Event = TestEvent;
154
155        fn observe(&self, event: &<Self::Event as ecs::Event>::This<'_>) -> Result<()> {
156            let TestEvent(_) = event;
157            Ok(())
158        }
159    }
160
161    struct TestMediator;
162
163    impl Mediator for TestMediator {
164        type Event = TestEvent;
165        type EventsToSend = TestEvent2;
166
167        fn mediate(
168            &self,
169            event: &mut EventMut<'_, Self::Event>,
170            mut sender: ecs::Sender<Self::EventsToSend>,
171        ) -> Result<()> {
172            let num = event.0;
173
174            sender.send(TestEvent2(num * 2));
175
176            Ok(())
177        }
178    }
179
180    #[test]
181    fn test_mediator() {
182        // Initialize world.
183        let mut world = World::new();
184        let mediator = TestMediator;
185        let observer = TestObserver;
186
187        // Register handlers to World.
188        world.add_handler(|r: ecs::Receiver<TestEvent>| {
189            assert_eq!(r.event.0, 1);
190        });
191        world.add_handler(|r: ecs::Receiver<TestEvent2>| {
192            assert_eq!(r.event.0, 2);
193        });
194
195        mediator
196            .to_system()
197            .register_to(HandlerRegistry { world: &mut world });
198
199        observer
200            .to_system()
201            .register_to(HandlerRegistry { world: &mut world });
202
203        // Send event to World.
204        world.send(TestEvent(1));
205    }
206}