morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
morph::bridge::BridgeHandler< Model, Sharing > Class Template Reference

RAII wrapper that binds a single model type to a Bridge. More...

#include <bridge.hpp>

Public Member Functions

 BridgeHandler (Bridge &bridge, ::morph::exec::IExecutor *guiExec)
 Constructs and registers the handler using the default model factory.
 BridgeHandler (Bridge &bridge, ::morph::exec::IExecutor *guiExec, std::shared_ptr< detail::HandlerBinding > binding)
 Constructs the handler with a pre-built binding (for dependency injection).
 ~BridgeHandler ()
 Deregisters the binding from the bridge, on the owner.
 BridgeHandler (const BridgeHandler &)=delete
BridgeHandler & operator= (const BridgeHandler &)=delete
template<typename Action>
::morph::async::Completion< typename ::morph::model::ActionTraits< Action >::Result > execute (Action action)
 Dispatches action via the underlying Bridge and returns a Completion.
template<typename Action>
::morph::async::Completion< typename ::morph::model::ActionTraits< Action >::Result > execute (Action action, ::core::async::StopToken stop)
 Dispatches action as execute(action) does, cancellable through stop.
template<typename M = Model>
requires kShared
void attach (const ::morph::model::PrimaryKeyOf< M > &key)
 Attaches (or re-points) this handler to the instance for key.
template<typename M = Model>
requires kShared
std::optional<::morph::model::PrimaryKeyOf< M > > primary ()
 This handler's current primary key, or nullopt if unattached.
template<typename M = Model>
requires kShared
::morph::async::Completion< std::vector<::morph::model::PrimaryKeyOf< M > > > instances ()
 Snapshot of the live shared instance keys for Model.
::morph::async::Completion< std::string > executeJson (std::string_view actionType, std::string_view bodyJson)
 Type-erased execute: looks up the action by its registered string id and dispatches it through ActionExecuteRegistry.
bool servesAction (std::string_view actionId) const noexcept
 Whether Model has an action registered under actionId, without invoking it.
::morph::exec::IExecutor * guiExecutor () const noexcept
 The executor used to deliver this handler's Completion callbacks.
::morph::exec::IExecutor & owner () const noexcept
 The executor this handler and its bridge belong to.
bool onOwner () const noexcept
 Whether the calling thread is on this handler's owner.
bool isBound () const noexcept
 Whether this handler currently has a live backend instance.
template<typename R>
void subscribe (std::function< void(R)> cb)
 Subscribes to results of type R produced on the attached instance.
template<typename R>
void subscribe (const ::morph::async::CallbackScope &scope, std::function< void(R)> cb)
 Subscribes to results of type R, gated on scope.
template<typename R>
void subscribe (::morph::async::CallbackToken token, std::function< void(R)> cb)
 Subscribes to results of type R, gated on an already-issued token.
template<typename R>
void unsubscribe ()
 Removes this handler's subscription for R.
const std::shared_ptr< detail::HandlerBinding > & binding () const
 Returns the underlying HandlerBinding.

Static Public Attributes

static constexpr bool kShared = std::is_same_v<Sharing, AllowShared>
 Whether this handler participates in the shared instance directory.

Detailed Description

template<typename Model, typename Sharing = NoSharing>
class morph::bridge::BridgeHandler< Model, Sharing >

RAII wrapper that binds a single model type to a Bridge.

On construction, registers a HandlerBinding on the bridge. On destruction, deregisters it. The handler is non-copyable, and belongs to its bridge's owner: it is used and destroyed there.

Instance subscriptions
Beyond the one-shot execute(action) -> Completion<R> API, a handler can observe the instance it is attached to:
  • subscribe<R>(cb) fires whenever an R is produced on that instance, by any handler attached to it.
  • unsubscribe<R>() drops the callback.
Template Parameters
ModelConcrete model type.
SharingNoSharing (the default) or AllowShared.

Definition at line 2583 of file bridge.hpp.

Constructor & Destructor Documentation

◆ BridgeHandler() [1/2]

template<typename Model, typename Sharing = NoSharing>
morph::bridge::BridgeHandler< Model, Sharing >::BridgeHandler ( Bridge & bridge,
::morph::exec::IExecutor * guiExec )
inline

Constructs and registers the handler using the default model factory.

On the bridge's owner the bind is issued here; a backend that settles it before returning has bound the handler when this returns. Anywhere else — inside a running action on a pool thread — the registration is posted to the owner. Either way nothing waits: a call made before the bind settles is held and dispatched when it does.

Parameters
bridgeThe bridge to register on. Borrowed: it must outlive every call made on this handler.
guiExecExecutor used to deliver Completion callbacks: the bridge's owner, or an executor that runs its tasks on the owner's thread (a debug build checks it once). Borrowed: it must outlive this handler.

Definition at line 2602 of file bridge.hpp.

◆ BridgeHandler() [2/2]

template<typename Model, typename Sharing = NoSharing>
morph::bridge::BridgeHandler< Model, Sharing >::BridgeHandler ( Bridge & bridge,
::morph::exec::IExecutor * guiExec,
std::shared_ptr< detail::HandlerBinding > binding )
inline

Constructs the handler with a pre-built binding (for dependency injection).

Registers binding exactly as the constructor above registers its own.

Parameters
bridgeThe bridge to register on. Borrowed, on the same terms as the constructor above.
guiExecExecutor for callback delivery, on the same terms as the constructor above.
bindingPre-built binding whose factory captures injected dependencies. Its contextKey must be set before this call.

Definition at line 2617 of file bridge.hpp.

◆ ~BridgeHandler()

template<typename Model, typename Sharing = NoSharing>
morph::bridge::BridgeHandler< Model, Sharing >::~BridgeHandler ( )
inline

Deregisters the binding from the bridge, on the owner.

Every call still held for a bind in flight is rejected with HandlerDestroyedError. Destroyed after its bridge — still on the owner — it finds the bridge's token expired and deregisters nothing; on one thread that check is exact.

Definition at line 2640 of file bridge.hpp.

Member Function Documentation

◆ execute() [1/2]

template<typename Model, typename Sharing = NoSharing>
template<typename Action>
::morph::async::Completion< typename ::morph::model::ActionTraits< Action >::Result > morph::bridge::BridgeHandler< Model, Sharing >::execute ( Action action)
inline

Dispatches action via the underlying Bridge and returns a Completion.

The bridge's currently-installed default session is attached automatically. A call made before the handler's bind has settled is held and dispatched when it does; a failed bind rejects it with the bind's error.

Template Parameters
ActionConcrete action type registered with BRIDGE_REGISTER_ACTION.
Parameters
actionAction to execute (moved into the dispatch).
Returns
Completion that resolves on the GUI executor. A payload- or result-keyed action's attach/promote step never throws out of this call, even when the backend refuses it (e.g. a remote server at LimitPolicy::maxLiveModels, a transport error, or an unauthorized attach) — the failure is instead delivered through the returned Completion's .onError(...), exactly like any other dispatch failure.

Definition at line 2667 of file bridge.hpp.

◆ execute() [2/2]

template<typename Model, typename Sharing = NoSharing>
template<typename Action>
::morph::async::Completion< typename ::morph::model::ActionTraits< Action >::Result > morph::bridge::BridgeHandler< Model, Sharing >::execute ( Action action,
::core::async::StopToken stop )
inline

Dispatches action as execute(action) does, cancellable through stop.

A stop on stop before the call settles cancels it: the returned Completion is rejected with core::async::OperationCancelled, posted to the GUI executor from the thread that requested the stop, and the call's stop source is asked to stop. A handler returning a Task, on a LocalBackend, sees that stop at its next stop-aware co_await; a synchronous handler runs to its end, and a remote server's handler runs on, since no cancel crosses the wire. Either way the call's own outcome, later, reaches nobody. A token already stopped rejects the call the same way without dispatching it.

The call stays counted as pending until the backend settles it, as a call the execute deadline settled does.

Template Parameters
ActionConcrete action type registered with BRIDGE_REGISTER_ACTION.
Parameters
actionAction to execute (moved into the dispatch).
stopThe caller's cancel. Observed until the call settles; a token that can never be stopped makes this execute(action).
Returns
Completion that resolves on the GUI executor, or rejects with core::async::OperationCancelled once stop is stopped.

Definition at line 2716 of file bridge.hpp.

◆ attach()

template<typename Model, typename Sharing = NoSharing>
template<typename M = Model>
requires kShared
void morph::bridge::BridgeHandler< Model, Sharing >::attach ( const ::morph::model::PrimaryKeyOf< M > & key)
inline

Attaches (or re-points) this handler to the instance for key.

Creates the instance if no live instance holds key, otherwise joins the existing one. Re-pointing an already-attached handler releases the old instance, which survives only if another handler still holds it. A backend that settles before returning has attached the handler by the time this returns; otherwise calls made meanwhile are held until it has. A refused attach is logged and leaves the handler on the instance it held; a call held behind it is rejected with its error only when the handler has no instance to fall back to. A key that names no instance — an empty string, a strong id with no value — is refused the same way: a call through a handler with no instance is then rejected with std::invalid_argument or std::runtime_error respectively.

Template Parameters
MDefaulted to Model; never named explicitly. Present only so the signature is instantiated lazily, since PrimaryKeyOf is ill-formed for an unkeyed model.
Parameters
keyPrimary key of the instance to attach to.

Definition at line 2750 of file bridge.hpp.

◆ primary()

template<typename Model, typename Sharing = NoSharing>
template<typename M = Model>
requires kShared
std::optional<::morph::model::PrimaryKeyOf< M > > morph::bridge::BridgeHandler< Model, Sharing >::primary ( )
inlinenodiscard

This handler's current primary key, or nullopt if unattached.

Template Parameters
MDefaulted to Model; never named explicitly. See attach.
Returns
The attached key, or nullopt before the first attach settles.

Definition at line 2767 of file bridge.hpp.

◆ instances()

template<typename Model, typename Sharing = NoSharing>
template<typename M = Model>
requires kShared
::morph::async::Completion< std::vector<::morph::model::PrimaryKeyOf< M > > > morph::bridge::BridgeHandler< Model, Sharing >::instances ( )
inlinenodiscard

Snapshot of the live shared instance keys for Model.

Asynchronous even in local mode: the directory is backend state, and in remote mode answering costs a round trip. The result is a snapshot, stale the moment it arrives.

Template Parameters
MDefaulted to Model; never named explicitly. See attach.
Returns
Completion resolving on the GUI executor with the live keys.

Definition at line 2786 of file bridge.hpp.

◆ executeJson()

template<typename Model, typename Sharing = NoSharing>
::morph::async::Completion< std::string > morph::bridge::BridgeHandler< Model, Sharing >::executeJson ( std::string_view actionType,
std::string_view bodyJson )
inlinenodiscard

Type-erased execute: looks up the action by its registered string id and dispatches it through ActionExecuteRegistry.

Use this only when the concrete Action type is not known at the call site (e.g. a schema-driven UI reading action names out of a JSON Schema at runtime). Prefer the templated execute<Action>() whenever the type is known at compile time.

Parameters
actionTypeRegistered action type-id (the NAME passed to BRIDGE_REGISTER_ACTION).
bodyJsonJSON-encoded action body.
Returns
Completion resolving with the JSON-encoded result.
Exceptions
std::runtime_errorif actionType was never registered for Model.

Definition at line 2824 of file bridge.hpp.

◆ servesAction()

template<typename Model, typename Sharing = NoSharing>
bool morph::bridge::BridgeHandler< Model, Sharing >::servesAction ( std::string_view actionId) const
inlinenodiscardnoexcept

Whether Model has an action registered under actionId, without invoking it.

A pure existence check over ActionExecuteRegistry – the same registry executeJson dispatches through.

Parameters
actionIdAction type id to check.
Returns
true if executeJson(actionId, ...) would find a registered action.

Definition at line 2842 of file bridge.hpp.

◆ guiExecutor()

template<typename Model, typename Sharing = NoSharing>
::morph::exec::IExecutor * morph::bridge::BridgeHandler< Model, Sharing >::guiExecutor ( ) const
inlinenodiscardnoexcept

The executor used to deliver this handler's Completion callbacks.

Returns
The GUI/callback executor passed at construction.

Definition at line 2849 of file bridge.hpp.

◆ owner()

template<typename Model, typename Sharing = NoSharing>
::morph::exec::IExecutor & morph::bridge::BridgeHandler< Model, Sharing >::owner ( ) const
inlinenodiscardnoexcept

The executor this handler and its bridge belong to.

Returns
The bridge's owner.

Definition at line 2853 of file bridge.hpp.

◆ onOwner()

template<typename Model, typename Sharing = NoSharing>
bool morph::bridge::BridgeHandler< Model, Sharing >::onOwner ( ) const
inlinenodiscardnoexcept

Whether the calling thread is on this handler's owner.

Returns
True inside one of the owner's tasks, or on the thread that constructed the bridge outside them.

Definition at line 2858 of file bridge.hpp.

◆ isBound()

template<typename Model, typename Sharing = NoSharing>
bool morph::bridge::BridgeHandler< Model, Sharing >::isBound ( ) const
inlinenodiscardnoexcept

Whether this handler currently has a live backend instance.

A point-in-time atomic read, safe from any thread. Nothing needs to wait on it: a call made while the handler's bind is in flight is held until the bind settles.

Returns
true if the handler is currently bound to a ModelId.

Definition at line 2866 of file bridge.hpp.

◆ subscribe() [1/3]

template<typename Model, typename Sharing = NoSharing>
template<typename R>
void morph::bridge::BridgeHandler< Model, Sharing >::subscribe ( std::function< void(R)> cb)
inline

Subscribes to results of type R produced on the attached instance.

Fires whenever an R is produced on the instance this handler is attached to by a typed call — this handler's, another handler's sharing the instance, or another screen's. A RawHandler's call on the same instance notifies nobody: its result is JSON text, not an R.

One callback per (handler, R): subscribing again replaces the previous one. Callbacks are delivered on this handler's executor. Failed actions notify nobody; delivery is best-effort and unbuffered, with no replay.

Template Parameters
RResult/state type to observe.
Parameters
cbCallable receiving the value by value on the GUI executor.

Definition at line 2882 of file bridge.hpp.

◆ subscribe() [2/3]

template<typename Model, typename Sharing = NoSharing>
template<typename R>
void morph::bridge::BridgeHandler< Model, Sharing >::subscribe ( const ::morph::async::CallbackScope & scope,
std::function< void(R)> cb )
inline

Subscribes to results of type R, gated on scope.

Same subscription as subscribe<R>(cb), except that cb runs only while scope is alive and un-stopped. The sink itself is not pruned when the scope goes inactive: delivery is refused, the subscription entry stays until unsubscribe<R>() or handler destruction removes it.

Template Parameters
RResult/state type to observe.
Parameters
scopeReceiver-owned gate; observed weakly, and only its current generation is captured (a later reset() retires this sink).
cbCallable receiving the value by value on the GUI executor.

Definition at line 2900 of file bridge.hpp.

◆ subscribe() [3/3]

template<typename Model, typename Sharing = NoSharing>
template<typename R>
void morph::bridge::BridgeHandler< Model, Sharing >::subscribe ( ::morph::async::CallbackToken token,
std::function< void(R)> cb )
inline

Subscribes to results of type R, gated on an already-issued token.

The token-taking form of subscribe<R>(const CallbackScope&, cb).

Template Parameters
RResult/state type to observe.
Parameters
tokenGate observing some receiver's CallbackScope. A default-constructed token suppresses every delivery.
cbCallable receiving the value by value on the GUI executor.

Definition at line 2913 of file bridge.hpp.

◆ unsubscribe()

template<typename Model, typename Sharing = NoSharing>
template<typename R>
void morph::bridge::BridgeHandler< Model, Sharing >::unsubscribe ( )
inline

Removes this handler's subscription for R.

Template Parameters
RResult/state type to stop hearing about.

Definition at line 2920 of file bridge.hpp.

◆ binding()

template<typename Model, typename Sharing = NoSharing>
const std::shared_ptr< detail::HandlerBinding > & morph::bridge::BridgeHandler< Model, Sharing >::binding ( ) const
inlinenodiscard

Returns the underlying HandlerBinding.

Returns
Shared pointer to the binding owned by this handler — a reference into the handler, valid only for as long as it is. Copy it to keep the binding past that point.

Definition at line 2929 of file bridge.hpp.

Member Data Documentation

◆ kShared

template<typename Model, typename Sharing = NoSharing>
bool morph::bridge::BridgeHandler< Model, Sharing >::kShared = std::is_same_v<Sharing, AllowShared>
staticconstexpr

Whether this handler participates in the shared instance directory.

Definition at line 2586 of file bridge.hpp.


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