moonshine_util/
event.rs

1//! Utilities related to Bevy [`Event`] system.
2
3use bevy_app::{App, Plugin};
4use bevy_ecs::prelude::*;
5use bevy_ecs::system::IntoObserverSystem;
6use std::marker::PhantomData;
7use std::sync::Mutex;
8
9use crate::Static;
10
11/// An [`Event`]-like trait for events that may only trigger a single observer.
12///
13/// # Usage
14///
15/// Standard Bevy events are always read-only and accessible by by reference because
16/// each event can trigger many observers.
17///
18/// However, sometimes you may need to consume the event data to avoid unnecessary cloning and
19/// you know that you will only have a single observer for that event.
20///
21/// For these cases, you can use the [`SingleEvent`] trait which.
22///
23/// See also:
24/// - [`OnSingle`]
25/// - [`add_single_observer`](AddSingleObserver::add_single_observer)
26/// - [`trigger_single`](TriggerSingle::trigger_single)
27pub trait SingleEvent: Static {}
28
29/// Trait used to register single observers for [`SingleEvent`]s.
30pub trait AddSingleObserver {
31    /// Checks if an observer is registered for a given [`SingleEvent`].
32    fn has_single_observer<E: SingleEvent>(&self) -> bool;
33
34    /// Adds a single observer for a given [`SingleEvent`] and guarantees that it's the only one registered.
35    ///
36    /// # Panic
37    /// This will panic if an observer for the same event is already registered.
38    fn add_single_observer<E: SingleEvent, B: Bundle, M>(
39        self,
40        observer: impl IntoSingleObserverSystem<E, B, M>,
41    ) -> Self;
42}
43
44impl AddSingleObserver for &mut App {
45    fn has_single_observer<E: SingleEvent>(&self) -> bool {
46        self.is_plugin_added::<SingleEventObserverPlugin<E>>()
47    }
48
49    fn add_single_observer<E: SingleEvent, B: Bundle, M>(
50        self,
51        observer: impl IntoSingleObserverSystem<E, B, M>,
52    ) -> Self {
53        if !self.is_plugin_added::<SingleEventObserverPlugin<E>>() {
54            self.add_plugins(SingleEventObserverPlugin::<E>::new());
55        } else {
56            panic!(
57                "a single observer is already registered for event: {}",
58                std::any::type_name::<E>()
59            );
60        }
61
62        self.add_observer(observer)
63    }
64}
65
66/// Trait used to trigger a [`SingleEvent`] via [`Commands`] or [`World`].
67pub trait TriggerSingle {
68    /// Triggers a [`SingleEvent`], similar to [`Commands::trigger`].
69    ///
70    // TODO: Support targets
71    fn trigger_single<E: SingleEvent>(self, event: E);
72}
73
74impl TriggerSingle for &mut Commands<'_, '_> {
75    fn trigger_single<E: SingleEvent>(self, event: E) {
76        self.trigger(SingleEventWrapper::new(event));
77    }
78}
79
80impl TriggerSingle for &mut World {
81    fn trigger_single<E: SingleEvent>(self, event: E) {
82        self.trigger(SingleEventWrapper::new(event));
83    }
84}
85
86#[doc(hidden)]
87pub trait IntoSingleObserverSystem<E: SingleEvent, B: Bundle, M>:
88    IntoObserverSystem<SingleEventWrapper<E>, B, M>
89{
90}
91
92impl<E: SingleEvent, B: Bundle, M, S> IntoSingleObserverSystem<E, B, M> for S where
93    S: IntoObserverSystem<SingleEventWrapper<E>, B, M>
94{
95}
96
97/// A standard [`Event`] which contains a [`SingleEvent`].
98///
99/// You should avoid using this directly and instead use [`OnSingle`] for better ergonomics.
100#[derive(Event)]
101pub struct SingleEventWrapper<E: SingleEvent>(Mutex<Option<E>>);
102
103impl<E: SingleEvent> SingleEventWrapper<E> {
104    fn new(event: E) -> Self {
105        Self(Mutex::new(Some(event)))
106    }
107
108    /// Consumes the [`SingleEvent`] and returns it.
109    ///
110    /// Returns [`None`] if the event has already been consumed.
111    pub fn consume(&self) -> Option<E> {
112        self.0.lock().unwrap().take()
113    }
114}
115
116/// Trigger for [`SingleEvent`] types.
117///
118/// Usage is identical to [`On`] but with the addition of the [`consume`](SingleEventWrapper::consume) method.
119pub type OnSingle<'w, 't, E, B = ()> = On<'w, 't, SingleEventWrapper<E>, B>;
120
121#[doc(hidden)]
122pub struct SingleEventObserverPlugin<E: SingleEvent>(PhantomData<E>);
123
124impl<E: SingleEvent> SingleEventObserverPlugin<E> {
125    fn new() -> Self {
126        Self(PhantomData)
127    }
128}
129
130impl<E: SingleEvent> Plugin for SingleEventObserverPlugin<E> {
131    fn build(&self, _: &mut App) {}
132}