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
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
//! A macro to create event bundles for Bevy
//!
//! # Usage
//! ```ignore
//! event_set!([name] { [...events] });
//! ```
//!
//! This will create a struct that can be used to send events of all given
//! types through the [`SendEvent`] trait.
//!
//! # Example
//! ```
//! # use bevy::prelude::*;
//! use bevy_event_set::*;
//!
//! // Define your events
//! struct EventOne;
//! struct EventTwo;
//! struct EventThree(usize);
//!
//! // Create an event set named `MyEvents`
//! event_set!(MyEvents { EventOne, EventTwo, EventThree });
//!
//! // Use the event set in a system
//! fn event_emitter_system(mut events: MyEvents) {
//!     events.send(EventOne);
//!     events.send(EventTwo);
//!     events.send(EventThree(42));
//! }
//!
//! // Subscribe to events selectively in different systems
//! fn event_one_listener_system(events: Res<Events<EventOne>>) { }
//! fn event_two_listener_system(events: Res<Events<EventTwo>>) { }
//! fn event_three_listener_system(events: Res<Events<EventThree>>) { }
//!
//! // Add the event set to your app
//! App::build()
//!     .add_event_set::<MyEvents>();
//! ```

use bevy::app::AppBuilder;

/// Describes an event set
pub trait EventSet {
	fn apply(app: &mut AppBuilder);
}

/// Trait used to add `add_event_set` to the Bevy app builder
pub trait AddEventSet {
	/// Adds an event set to the app
	///
	/// # Example
	/// ```
	/// use bevy::prelude::*;
	/// use bevy_event_set::*;
	///
	/// struct MyEvent;
	/// event_set!(MyEventSet { MyEvent });
	///
	/// App::build().add_event_set::<MyEventSet>();
	/// ```
	fn add_event_set<E: EventSet>(&mut self) -> &mut Self;
}

impl AddEventSet for AppBuilder {
	fn add_event_set<E: EventSet>(&mut self) -> &mut Self {
		E::apply(self);
		self
	}
}

/// Allows an event set to send an event of a given type
pub trait SendEvent<T> {
	/// Sends an event to the event buffer
	///
	/// Calls [`Events.send`](bevy::app::Events::send()) on the Bevy event buffer of the corresponding type.
	fn send(&mut self, event: T);
}

/// Creates an event set
///
/// See the [crate-level documentation](./index.html) to see how to use this macro.
#[macro_export]
macro_rules! event_set {
	($name:ident {}) => {
		compile_error!("cannot make an empty event set");
	};
	($name:ident { $($event:ident),* $(,)? }) => {
		#[allow(non_snake_case)]
		#[derive(bevy::ecs::SystemParam)]
		pub struct $name<'a> {
			$(
				$event: bevy::ecs::ResMut<'a, bevy::app::Events<$event>>,
			)*
		}

		impl<'a> $crate::EventSet for $name<'a> {
			fn apply(app: &mut bevy::app::AppBuilder) {
				$(
					app.add_event::<$event>();
				)*
			}
		}

		$(
			impl<'a> $crate::SendEvent<$event> for $name<'a> {
				fn send(&mut self, event: $event) {
					self.$event.send(event)
				}
			}
		)*
	};
}

#[cfg(test)]
mod tests {
	// These tests just check if the macros compile

	use super::*;

	#[test]
	fn single() {
		struct TestEvent;
		event_set!(MyEvents { TestEvent });
		event_set!(MyEvents2 { TestEvent });
	}

	#[test]
	fn multiple() {
		struct TestEvent1(usize);
		struct TestEvent2 {
			number: usize,
		}

		event_set!(MyEvents {
			TestEvent1,
			TestEvent2
		});
	}

	#[test]
	fn add_to_builder() {
		use bevy::app::App;

		struct TestEvent;
		event_set!(MyEvents { TestEvent });

		App::build().add_event_set::<MyEvents>();
	}
}