Skip to main content

reifydb_core/event/
macro.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2026 ReifyDB
3
4#[macro_export]
5macro_rules! define_event {
6
7	(
8		$(#[$meta:meta])*
9		$vis:vis struct $name:ident {}
10	) => {
11		$(#[$meta])*
12		#[derive(Debug, Clone)]
13		$vis struct $name {}
14
15		impl $name {
16			#[allow(clippy::new_without_default)]
17			pub fn new() -> Self {
18				Self {}
19			}
20		}
21
22		impl $crate::event::Event for $name {
23			fn as_any(&self) -> &dyn std::any::Any {
24				self
25			}
26
27			fn into_any(self) -> Box<dyn std::any::Any + Send> {
28				Box::new(self)
29			}
30		}
31	};
32
33
34	(
35		$(#[$meta:meta])*
36		$vis:vis struct $name:ident {
37			$(
38				$(#[$field_meta:meta])*
39				$field_vis:vis $field:ident: $field_ty:ty
40			),* $(,)?
41		}
42	) => {
43
44		::paste::paste! {
45
46			#[doc(hidden)]
47			#[allow(non_snake_case)]
48			mod [<__inner_ $name:snake>] {
49				#[allow(unused_imports)]
50				use super::*;
51
52				#[derive(Debug)]
53				#[allow(dead_code)]
54				pub(super) struct Inner {
55					$(
56						$(#[$field_meta])*
57						pub(super) $field: $field_ty,
58					)*
59				}
60			}
61
62
63			$(#[$meta])*
64			#[derive(Debug)]
65			$vis struct $name {
66				inner: std::sync::Arc<[<__inner_ $name:snake>]::Inner>,
67			}
68
69
70			impl Clone for $name {
71				fn clone(&self) -> Self {
72					Self {
73						inner: std::sync::Arc::clone(&self.inner),
74					}
75				}
76			}
77
78
79			impl $name {
80				#[allow(clippy::too_many_arguments)]
81				#[allow(clippy::new_without_default)]
82				pub fn new($($field: $field_ty),*) -> Self {
83					Self {
84						inner: std::sync::Arc::new([<__inner_ $name:snake>]::Inner {
85							$($field),*
86						}),
87					}
88				}
89
90				$(
91					#[allow(dead_code)]
92					pub fn $field(&self) -> &$field_ty {
93						&self.inner.$field
94					}
95				)*
96			}
97
98
99			impl $crate::event::Event for $name {
100				fn as_any(&self) -> &dyn std::any::Any {
101					self
102				}
103
104				fn into_any(self) -> Box<dyn std::any::Any + Send> {
105					Box::new(self)
106				}
107			}
108		}
109	};
110}
111
112#[cfg(test)]
113mod tests {
114	use std::{sync::Arc, thread};
115
116	use reifydb_runtime::{
117		actor::system::ActorSystem,
118		context::clock::Clock,
119		pool::{PoolConfig, Pools},
120		sync::mutex::Mutex,
121	};
122
123	use crate::event::{Event, EventBus, EventListener};
124
125	define_event! {
126		pub struct DefineTestEvent {
127			pub data: Vec<i32>,
128			pub name: String,
129		}
130	}
131
132	define_event! {
133		pub struct EmptyDefineEvent {}
134	}
135
136	#[test]
137	fn testine_event_cheap_clone() {
138		let large_vec = vec![0; 10_000];
139		let event = DefineTestEvent::new(large_vec, "test".to_string());
140
141		// A clone must be an Arc bump, not a copy of the 10k payload.
142		let clone1 = event.clone();
143		let clone2 = event.clone();
144
145		assert!(Arc::ptr_eq(&event.inner, &clone1.inner));
146		assert!(Arc::ptr_eq(&event.inner, &clone2.inner));
147
148		assert_eq!(event.data().len(), 10_000);
149		assert_eq!(clone1.data().len(), 10_000);
150		assert_eq!(clone2.data().len(), 10_000);
151	}
152
153	#[test]
154	fn testine_event_field_access() {
155		let event = DefineTestEvent::new(vec![1, 2, 3], "my_event".to_string());
156
157		assert_eq!(event.data(), &vec![1, 2, 3]);
158		assert_eq!(event.name(), "my_event");
159
160		// The accessors must hand back references, not owned clones.
161		let _data_ref: &Vec<i32> = event.data();
162		let _name_ref: &String = event.name();
163	}
164
165	#[test]
166	fn testine_event_empty_struct() {
167		let event = EmptyDefineEvent::new();
168		let clone = event.clone();
169
170		let _ = clone;
171	}
172
173	#[test]
174	fn testine_event_implements_event_trait() {
175		let event = DefineTestEvent::new(vec![42], "test".to_string());
176
177		let any_ref = event.as_any();
178		assert!(any_ref.downcast_ref::<DefineTestEvent>().is_some());
179
180		let event2 = DefineTestEvent::new(vec![99], "test2".to_string());
181		let any_box = event2.into_any();
182		assert!(any_box.downcast::<DefineTestEvent>().is_ok());
183	}
184
185	#[test]
186	fn testine_event_send_sync() {
187		fn assert_send<T: Send>() {}
188		fn assert_sync<T: Sync>() {}
189
190		assert_send::<DefineTestEvent>();
191		assert_sync::<DefineTestEvent>();
192
193		let event = DefineTestEvent::new(vec![1, 2, 3], "thread_test".to_string());
194		let handle = thread::spawn(move || {
195			assert_eq!(event.data(), &vec![1, 2, 3]);
196		});
197		handle.join().unwrap();
198	}
199
200	#[test]
201	fn testine_event_with_event_bus() {
202		let pools = Pools::new(PoolConfig::default());
203		let actor_system = ActorSystem::new(pools, Clock::Real);
204		let event_bus = EventBus::new(&actor_system.spawner());
205
206		#[derive(Clone)]
207		struct DefineTestListener {
208			counter: Arc<Mutex<i32>>,
209		}
210
211		impl EventListener<DefineTestEvent> for DefineTestListener {
212			fn on(&self, event: &DefineTestEvent) {
213				let mut c = self.counter.lock();
214				*c += event.data().len() as i32;
215			}
216		}
217
218		let listener = DefineTestListener {
219			counter: Arc::new(Mutex::new(0)),
220		};
221
222		event_bus.register::<DefineTestEvent, DefineTestListener>(listener.clone());
223
224		event_bus.emit(DefineTestEvent::new(vec![1, 2, 3], "test".to_string()));
225		event_bus.wait_for_completion();
226		assert_eq!(*listener.counter.lock(), 3);
227
228		event_bus.emit(DefineTestEvent::new(vec![1, 2, 3, 4, 5], "test2".to_string()));
229		event_bus.wait_for_completion();
230		assert_eq!(*listener.counter.lock(), 8);
231	}
232}