Skip to main content

reifydb_core/event/
macro.rs

1// SPDX-License-Identifier: Apache-2.0
2// Copyright (c) 2025 ReifyDB
3
4#[macro_export]
5macro_rules! define_event {
6	// Handle empty structs (e.g., OnStartEvent)
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	// Handle non-empty structs with fields
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		// create unique inner module name
44		::paste::paste! {
45			// Inner struct with all fields
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			// Wrapper struct with Arc
63			$(#[$meta])*
64			#[derive(Debug)]
65			$vis struct $name {
66				inner: std::sync::Arc<[<__inner_ $name:snake>]::Inner>,
67			}
68
69			// Clone implementation (cheap Arc clone)
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			// Constructor and accessor methods
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			// Event trait implementation
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::{
115		sync::{Arc, Mutex},
116		thread,
117	};
118
119	use reifydb_runtime::{SharedRuntimeConfig, actor::system::ActorSystem};
120
121	use crate::event::{Event, EventBus, EventListener};
122
123	define_event! {
124		pub struct DefineTestEvent {
125			pub data: Vec<i32>,
126			pub name: String,
127		}
128	}
129
130	define_event! {
131		pub struct EmptyDefineEvent {}
132	}
133
134	#[test]
135	fn test_define_event_cheap_clone() {
136		let large_vec = vec![0; 10_000];
137		let event = DefineTestEvent::new(large_vec, "test".to_string());
138
139		// Clone should be cheap (just Arc increment)
140		let clone1 = event.clone();
141		let clone2 = event.clone();
142
143		// Verify they share the same Arc by comparing pointers
144		assert!(Arc::ptr_eq(&event.inner, &clone1.inner));
145		assert!(Arc::ptr_eq(&event.inner, &clone2.inner));
146
147		// Data should be accessible
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 test_define_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		// Test that we get references, not owned values
161		let _data_ref: &Vec<i32> = event.data();
162		let _name_ref: &String = event.name();
163	}
164
165	#[test]
166	fn test_define_event_empty_struct() {
167		let event = EmptyDefineEvent::new();
168		let clone = event.clone();
169
170		// Should compile and work
171		drop(event);
172		drop(clone);
173	}
174
175	#[test]
176	fn test_define_event_implements_event_trait() {
177		let event = DefineTestEvent::new(vec![42], "test".to_string());
178
179		// Test Event trait methods
180		let any_ref = event.as_any();
181		assert!(any_ref.downcast_ref::<DefineTestEvent>().is_some());
182
183		let event2 = DefineTestEvent::new(vec![99], "test2".to_string());
184		let any_box = event2.into_any();
185		assert!(any_box.downcast::<DefineTestEvent>().is_ok());
186	}
187
188	#[test]
189	fn test_define_event_send_sync() {
190		// This test verifies that events are Send + Sync
191		fn assert_send<T: Send>() {}
192		fn assert_sync<T: Sync>() {}
193
194		assert_send::<DefineTestEvent>();
195		assert_sync::<DefineTestEvent>();
196
197		// Test that we can actually send across threads
198		let event = DefineTestEvent::new(vec![1, 2, 3], "thread_test".to_string());
199		let handle = thread::spawn(move || {
200			assert_eq!(event.data(), &vec![1, 2, 3]);
201		});
202		handle.join().unwrap();
203	}
204
205	#[test]
206	fn test_define_event_with_event_bus() {
207		let actor_system = ActorSystem::new(SharedRuntimeConfig::default().actor_system_config());
208		let event_bus = EventBus::new(&actor_system);
209
210		// Create a listener for DefineTestEvent
211		#[derive(Clone)]
212		struct DefineTestListener {
213			counter: Arc<Mutex<i32>>,
214		}
215
216		impl EventListener<DefineTestEvent> for DefineTestListener {
217			fn on(&self, event: &DefineTestEvent) {
218				let mut c = self.counter.lock().unwrap();
219				*c += event.data().len() as i32;
220			}
221		}
222
223		let listener = DefineTestListener {
224			counter: Arc::new(Mutex::new(0)),
225		};
226
227		event_bus.register::<DefineTestEvent, DefineTestListener>(listener.clone());
228
229		// Emit event
230		event_bus.emit(DefineTestEvent::new(vec![1, 2, 3], "test".to_string()));
231		event_bus.wait_for_completion();
232		assert_eq!(*listener.counter.lock().unwrap(), 3);
233
234		// Emit another
235		event_bus.emit(DefineTestEvent::new(vec![1, 2, 3, 4, 5], "test2".to_string()));
236		event_bus.wait_for_completion();
237		assert_eq!(*listener.counter.lock().unwrap(), 8);
238	}
239}