Skip to content

Commit 61c5931

Browse files
committed
Add event system architecture and usage guidelines
Introduces a documentation file outlining the generic event system's architecture, usage patterns, best practices, and thread safety considerations. Includes code examples for creating events, emitters, listeners, and managing listener lifetimes.
1 parent e7845e2 commit 61c5931

File tree

1 file changed

+152
-0
lines changed

1 file changed

+152
-0
lines changed

.cursor/rules/event-system.mdc

Lines changed: 152 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,152 @@
1+
---
2+
alwaysApply: true
3+
description: Generic event system architecture and usage patterns
4+
---
5+
6+
# Generic Event System Rules
7+
8+
This project uses a comprehensive, type-safe event system built on top of C++ templates and inheritance. Understanding this system is crucial for working with any event-driven components.
9+
10+
## Core Architecture
11+
12+
### Base Event Class
13+
14+
All events inherit from [Event](mdc:src/foundation/event.h) which provides:
15+
16+
- Automatic timestamp generation
17+
- Virtual `GetTypeName()` method for debugging
18+
- Type-safe event hierarchy
19+
20+
### Event Emitter Pattern
21+
22+
Classes that emit events inherit from `EventEmitter<BaseEventType>` from [event_emitter.h](mdc:src/foundation/event_emitter.h):
23+
24+
- Provides compile-time type safety
25+
- Supports both synchronous and asynchronous event emission
26+
- Thread-safe listener management
27+
- Automatic background thread management for async events
28+
29+
## Event Types
30+
31+
Events are organized into hierarchies based on their domain. Each hierarchy has a base event class that other specific events inherit from. This provides type safety and allows listeners to register for either specific events or entire categories.
32+
33+
## Usage Patterns
34+
35+
### Creating Event Classes
36+
37+
```cpp
38+
class MyCustomEvent : public Event {
39+
public:
40+
MyCustomEvent(const std::string& data) : data_(data) {}
41+
42+
const std::string& GetData() const { return data_; }
43+
std::string GetTypeName() const override { return "MyCustomEvent"; }
44+
45+
private:
46+
std::string data_;
47+
};
48+
```
49+
50+
### Creating Event Emitters
51+
52+
```cpp
53+
class MyClass : public EventEmitter<MyCustomEvent> {
54+
public:
55+
void DoSomething() {
56+
// Synchronous emission
57+
Emit<MyCustomEvent>("some data");
58+
59+
// Asynchronous emission
60+
EmitAsync<MyCustomEvent>("async data");
61+
}
62+
};
63+
```
64+
65+
### Adding Event Listeners
66+
67+
```cpp
68+
// Using lambda functions
69+
auto listener_id = emitter.AddListener<MyCustomEvent>(
70+
[](const MyCustomEvent& event) {
71+
std::cout << "Received: " << event.GetData() << std::endl;
72+
}
73+
);
74+
75+
// Using custom listener class
76+
class MyListener : public EventListener<MyCustomEvent> {
77+
public:
78+
void OnEvent(const MyCustomEvent& event) override {
79+
// Handle event
80+
}
81+
};
82+
83+
MyListener listener;
84+
auto listener_id = emitter.AddListener<MyCustomEvent>(&listener);
85+
```
86+
87+
### Removing Listeners
88+
89+
```cpp
90+
// Remove by ID
91+
emitter.RemoveListener(listener_id);
92+
93+
// Remove all listeners for specific event type
94+
emitter.RemoveAllListeners<MyCustomEvent>();
95+
96+
// Remove all listeners
97+
emitter.RemoveAllListeners();
98+
```
99+
100+
## Best Practices
101+
102+
1. **Always inherit from appropriate base event class** - Don't inherit directly from `Event` unless creating a new event hierarchy
103+
2. **Use specific event types** - Prefer `EventListener<SpecificEvent>` over `EventListener<Event>` for type safety
104+
3. **Implement GetTypeName()** - Always override this method for debugging purposes
105+
4. **Use const references** - Event handlers should accept `const EventType&` parameters
106+
5. **Manage listener lifetimes** - Ensure listener objects remain valid while registered
107+
6. **Prefer async emission for heavy operations** - Use `EmitAsync` for events that might trigger expensive operations
108+
7. **Use RAII for listener management** - Store listener IDs and remove them in destructors
109+
110+
## Thread Safety
111+
112+
- Event emission is thread-safe
113+
- Listener registration/removal is thread-safe
114+
- Async event processing uses a dedicated background thread
115+
- Event handlers may be called from different threads depending on emission method
116+
117+
## Common Patterns
118+
119+
### Singleton Event Emitters
120+
121+
Many managers (WindowManager, DisplayManager) are singletons that emit events:
122+
123+
```cpp
124+
auto& manager = WindowManager::GetInstance();
125+
manager.AddListener<WindowCreatedEvent>([](const WindowCreatedEvent& event) {
126+
// Handle window creation
127+
});
128+
```
129+
130+
### Event Forwarding
131+
132+
Platform-specific implementations often forward system events to the generic event system:
133+
134+
```cpp
135+
void PlatformWindow::OnSystemEvent(const SystemEvent& sys_event) {
136+
// Convert to generic event and emit
137+
WindowEvent generic_event(sys_event.GetWindowId());
138+
emitter_.Emit(generic_event);
139+
}
140+
```
141+
142+
### Event Filtering
143+
144+
Listeners can filter events by checking specific types:
145+
146+
```cpp
147+
emitter.AddListener<WindowEvent>([](const WindowEvent& event) {
148+
if (auto moved_event = dynamic_cast<const WindowMovedEvent*>(&event)) {
149+
// Handle only window moved events
150+
}
151+
});
152+
```

0 commit comments

Comments
 (0)