Skip to main content

CommandHandlerRegistry.ixx File

Registry for mapping command types to their handlers. More...

Included Headers

#include <concepts> #include <vector> #include <cassert> #include <helios.engine.runtime.messaging.command.types> #include <helios.engine.ecs.types.ComponentTypeId>

Namespaces Index

namespacehelios
namespaceengine

Main engine module aggregating core infrastructure and game systems. More...

namespaceruntime

Runtime infrastructure for game execution and lifecycle orchestration. More...

namespacemessaging

Communication infrastructure for commands and events. More...

namespacecommand

Compile-time typed command buffering and handler routing. More...

Classes Index

structCommandHandlerEntry

Type-erased storage entry for a registered command handler. More...

structCommandHandlerRef<CommandType>

Typed reference wrapper for invoking a registered handler. More...

classCommandHandlerRegistry

Registry that maps CommandType types to handler instances via function pointers. More...

Description

Registry for mapping command types to their handlers.

File Listing

The file content with the documentation metadata removed is:

1/**
2 * @file CommandHandlerRegistry.ixx
3 * @brief Registry for mapping command types to their handlers.
4 */
5module;
6
7#include <concepts>
8#include <vector>
9#include <cassert>
10
11export module helios.engine.runtime.messaging.command.CommandHandlerRegistry;
12
13import helios.engine.ecs.types.ComponentTypeId;
14import helios.engine.runtime.messaging.command.types;
15
16using namespace helios::engine::ecs::types;
18
19
21
22 /**
23 * @brief Type-erased storage entry for a registered command handler.
24 */
26 /**
27 * @brief Pointer to the owning object (the handler instance).
28 */
29 void* owner = nullptr;
30
31 /**
32 * @brief Type-erased static trampoline function that casts owner and command to concrete types.
33 */
34 bool (*submitFn)(void*, const void*) noexcept = nullptr;
35 };
36
37 /**
38 * @brief Typed reference wrapper for invoking a registered handler.
39 *
40 * @tparam CommandType The specific command type this reference handles.
41 */
42 template<typename CommandType>
44
45 /**
46 * @brief Pointer to the handler instance.
47 */
48 void* owner = nullptr;
49
50 /**
51 * @brief Type-erased trampoline for command dispatch.
52 */
53 bool (*submitFn)(void*, const void*) noexcept = nullptr;
54
55 /**
56 * @brief Checks if this reference points to a valid handler.
57 *
58 * @return True if both owner and submitFn are non-null.
59 */
60 [[nodiscard]] explicit operator bool() const noexcept {
61 return owner && submitFn;
62 }
63
64 /**
65 * @brief Submits a command to the referenced handler.
66 *
67 * @param cmd The command instance to submit.
68 * @return True if the command was accepted/handled.
69 */
70 bool submit(const CommandType& cmd) const noexcept {
71 return submitFn(owner, &cmd);
72 }
73
74 };
75
76 /**
77 * @brief Registry that maps CommandType types to handler instances via function pointers.
78 *
79 * @details The CommandHandlerRegistry provides a mechanism to decouple command producers (systems)
80 * from command consumers (managers). Handlers are registered by reference, and the registry
81 * stores a type-erased "trampoline" function that allows invoking the handler's `submit(const Cmd&)`
82 * method without knowing the concrete handler type at the call site.
83 *
84 * This avoids virtual inheritance (TypedCommandHandler) and allows any class with a matching
85 * `submit` signature to act as a handler.
86 *
87 * Lookup is O(1) based on the CommandTypeId.
88 */
90
91 /**
92 * @brief Dense vector of handler entries, indexed by CommandTypeId value.
93 */
94 std::vector<CommandHandlerEntry> entries_;
95
96 public:
97
98 /**
99 * @brief Registers an object as the handler for a specific command type.
100 *
101 * @details The handler object must provide a method:
102 * `bool submit(const CommandType&) noexcept`.
103 * Upon registration, a static lambda (trampoline) is generated to handle type
104 * erasure and casting.
105 *
106 * @tparam CommandType The command type to handle.
107 * @tparam OwningT The concrete type of the handler object.
108 *
109 * @param owner Reference to the handler instance. Must outlive the registry (usually Owned by GameWorld/ResourceRegistry).
110 *
111 * @pre No handler is currently registered for this command type.
112 */
113 template<typename CommandType, typename OwningT>
114 void registerHandler(OwningT& owner) {
115 static_assert(requires(OwningT& x, const CommandType& c) {
116 { x.submit(c) } noexcept -> std::same_as<bool>;
117 });
118
119 const auto idx = CommandTypeId::id<CommandType>().value();
120
121 if (entries_.size() <= idx) {
122 entries_.resize(idx + 1);
123 }
124
125 assert(entries_[idx].owner == nullptr && "Handler already registered for this command type");
126
127 entries_[idx] = CommandHandlerEntry{
128 &owner,
129 +[](void* owner, const void* cmd) noexcept -> bool {
130 return static_cast<OwningT*>(owner)->submit(*static_cast<const CommandType*>(cmd));
131 }
132 };
133 }
134
135 /**
136 * @brief Checks if a handler is registered for the specified command type.
137 *
138 * @tparam CommandType The command type to check.
139 *
140 * @return True if a valid handler exists.
141 */
142 template<typename CommandType>
143 [[nodiscard]] bool has() const noexcept {
144 const auto idx = CommandTypeId::id<CommandType>().value();
145
146 if (idx >= entries_.size()) {
147 return false;
148 }
149
150 const auto& entry = entries_[idx];
151 return entry.owner && entry.submitFn;
152 }
153
154 /**
155 * @brief Retrieves a typed reference to the registered handler.
156 *
157 * @tparam CommandType The command type.
158 *
159 * @return A CommandHandlerRef wrapper. Can be checked for validity via operator bool().
160 */
161 template<typename CommandType>
162 [[nodiscard]] CommandHandlerRef<CommandType> tryHandler() const noexcept {
163 const auto idx = CommandTypeId::id<CommandType>().value();
164
165 if (idx >= entries_.size()) {
166 return {};
167 }
168
169 const auto& entry = entries_[idx];
170
171 if (!entry.owner || !entry.submitFn) {
172 return {};
173 }
174
175 return CommandHandlerRef<CommandType>{ entry.owner, entry.submitFn };
176 }
177
178 /**
179 * @brief Directly submits a command to its registered handler.
180 *
181 * @tparam CommandType The command type.
182 *
183 * @param cmd The command instance.
184 *
185 * @return True if a handler was found and it returned true; false otherwise.
186 */
187 template<typename CommandType>
188 bool submit(const CommandType& cmd) const noexcept {
189 if (auto handler = tryHandler<CommandType>()) {
190 return handler.submit(cmd);
191 }
192 return false;
193 }
194
195 };
196
197} // namespace

Generated via doxygen2docusaurus 2.0.0 by Doxygen 1.15.0.