morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
morph::bridge::ActionExecuteRegistry Class Reference

Type-erased, JSON-in/JSON-out execute path for actions whose concrete C++ type is only known by its registered string id at the call site (e.g. a schema-driven GUI that reads action names out of a JSON Schema at runtime). More...

#include <bridge.hpp>

Public Types

using Executor = std::function<::morph::async::Completion<std::string>(void*, std::string_view)>
 Deserialises bodyJson, dispatches through the handler's Bridge, and resolves with the JSON-encoded result.

Public Member Functions

template<typename Model, typename Action>
void registerAction (std::string_view modelId, std::string_view actionId)
 Registers the executors for (Model, Action) under the given string ids.
template<typename Sharing>
::morph::async::Completion< std::string > execute (std::string_view modelId, std::string_view actionId, void *handler, std::string_view bodyJson) const
 Looks up and invokes the executor for (modelId, actionId), specialised for the caller's own Sharing policy.
template<typename Sharing>
bool contains (std::string_view modelId, std::string_view actionId) const noexcept
 Checks whether an executor is registered for (modelId, actionId), specialised for the caller's own Sharing policy, without invoking it.

Static Public Member Functions

static ActionExecuteRegistry & instance ()
 Returns the process-level singleton registry.

Detailed Description

Type-erased, JSON-in/JSON-out execute path for actions whose concrete C++ type is only known by its registered string id at the call site (e.g. a schema-driven GUI that reads action names out of a JSON Schema at runtime).

Populated automatically by BRIDGE_REGISTER_ACTION — no action-specific code is required at any call site. Every entry calls through the real BridgeHandler<Model>::execute<Action>() (so sessions, backend switches, and completions all behave exactly as they do for hand-written call sites), unlike morph::model::detail::ActionDispatcher, which calls Model::execute directly against an already-owned model holder and is only ever used server-side.

HARD REQUIREMENT (other direction of the same constraint documented on morph::model::detail::registerActionExecutorOnce in registry.hpp): registration into this registry happens via registerActionExecutorOnce<Model, Action>, which BRIDGE_REGISTER_ACTION calls unconditionally but which is only defined here, in bridge.hpp. Every translation unit that calls BRIDGE_REGISTER_ACTION must therefore include this header (directly or transitively), or that translation unit's static initializer will fail to link.

Definition at line 62 of file bridge.hpp.

Member Typedef Documentation

◆ Executor

using morph::bridge::ActionExecuteRegistry::Executor = std::function<::morph::async::Completion<std::string>(void*, std::string_view)>

Deserialises bodyJson, dispatches through the handler's Bridge, and resolves with the JSON-encoded result.

Definition at line 66 of file bridge.hpp.

Member Function Documentation

◆ registerAction()

template<typename Model, typename Action>
void morph::bridge::ActionExecuteRegistry::registerAction ( std::string_view modelId,
std::string_view actionId )
inline

Registers the executors for (Model, Action) under the given string ids.

Populates one Executor per Sharing policy the framework defines (NoSharing and AllowShared), keyed by (modelId, actionId, typeid(Sharing)), rather than a single executor that unconditionally assumes NoSharing. A handler whose Sharing is anything else must be dispatched through the matching executor: the wrong one static_casts handlerVoid to the wrong BridgeHandler<Model, Sharing> instantiation, so kShared resolves incorrectly inside it and a payload-/result-keyed action's attach-or-promote step silently never runs. Both executors' bodies are otherwise byte-for-byte identical (built once, from the same generic lambda template, instantiated for NoSharing and again for AllowShared — the only two sharing tags morph::bridge defines), so this costs one extra closure per registered action, not per call. Defined out-of-line after BridgeHandler to avoid forward reference issues.

Template Parameters
ModelModel type whose handler will execute the action.
ActionAction type to register.
Parameters
modelIdString id the model is registered under.
actionIdString id the action is registered under.

Out-of-line definition of ActionExecuteRegistry::registerAction. Placed here after BridgeHandler is fully defined so we can safely cast and call its methods.

Builds one executor per Sharing policy the framework defines (NoSharing, AllowShared) from the same generic-lambda template, static_casting handlerVoid to the matching BridgeHandler<Model, Sharing>* in each — see bridge.md's design-decision entry for why a single NoSharing-only executor is unsound for a shared handler.

Definition at line 3063 of file bridge.hpp.

◆ execute()

template<typename Sharing>
::morph::async::Completion< std::string > morph::bridge::ActionExecuteRegistry::execute ( std::string_view modelId,
std::string_view actionId,
void * handler,
std::string_view bodyJson ) const
inlinenodiscard

Looks up and invokes the executor for (modelId, actionId), specialised for the caller's own Sharing policy.

Template Parameters
SharingNoSharing or AllowShared — the caller's own sharing policy.
Parameters
modelIdString id of the target model.
actionIdString id of the action to execute.
handlerType-erased BridgeHandler<Model, Sharing>* matching modelId.
bodyJsonJSON-encoded action payload.
Returns
Completion that resolves with the JSON-encoded action result.
Exceptions
std::runtime_errorif no executor was registered for that triple.

Definition at line 101 of file bridge.hpp.

◆ contains()

template<typename Sharing>
bool morph::bridge::ActionExecuteRegistry::contains ( std::string_view modelId,
std::string_view actionId ) const
inlinenodiscardnoexcept

Checks whether an executor is registered for (modelId, actionId), specialised for the caller's own Sharing policy, without invoking it.

registerAction always files both the NoSharing and AllowShared executors for a given (Model, Action) pair (see its own doc comment), so for any action registered via BRIDGE_REGISTER_ACTION this answers the same for either Sharing – the template parameter exists for symmetry with execute<Sharing> and to stay correct if that ever changes, not because the two currently disagree.

Template Parameters
SharingNoSharing or AllowShared — the caller's own sharing policy.
Parameters
modelIdString id of the target model.
actionIdString id of the action to check.
Returns
true if execute<Sharing>(modelId, actionId, ...) would find an executor.

Definition at line 130 of file bridge.hpp.

◆ instance()

ActionExecuteRegistry & morph::bridge::ActionExecuteRegistry::instance ( )
inlinestatic

Returns the process-level singleton registry.

Returns
Reference to the singleton ActionExecuteRegistry.

Definition at line 209 of file bridge.hpp.


The documentation for this class was generated from the following file: