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

Makes a blocking backend reach its caller without blocking it — and without touching the backend. More...

#include <backend.hpp>

Inheritance diagram for morph::backend::SynchronousBackendAdapter:

Public Types

using BindPromise = ::morph::async::Completion<::morph::exec::detail::ModelId>::Promise
 The producer side of a bindModel/promoteModel completion.

Public Member Functions

 SynchronousBackendAdapter (std::shared_ptr< detail::IBackend > inner, ::morph::exec::IExecutor &blockingExec)
 Wraps inner, running every one of its verbs on blockingExec.
 ~SynchronousBackendAdapter () override
 Waits for every queued and in-flight call; see "Ordering" above.
 SynchronousBackendAdapter (const SynchronousBackendAdapter &)=delete
SynchronousBackendAdapter & operator= (const SynchronousBackendAdapter &)=delete
 SynchronousBackendAdapter (SynchronousBackendAdapter &&)=delete
SynchronousBackendAdapter & operator= (SynchronousBackendAdapter &&)=delete
detail::IBackend & wrapped () const noexcept
 The wrapped backend.
::morph::async::Completion<::morph::exec::detail::ModelId > bindModel (detail::BindRequest request, ::morph::exec::IExecutor &cbExec) override
 Acquires a model instance without blocking the calling thread.
::morph::async::Completion<::morph::exec::detail::ModelId > promoteModel (detail::PromoteRequest request, ::morph::exec::IExecutor &cbExec) override
 Files an already-live instance under a key without blocking the caller.
void setOwner (const ::morph::exec::detail::OwnerAffinity &owner) override
 Records the caller's owner. Not forwarded: the wrapped backend's owner is this adapter's control strand.
::morph::exec::detail::ModelId registerModel (const std::string &typeId, std::function< std::unique_ptr<::morph::model::detail::IModelHolder >()> factory) override
 Runs the wrapped backend's registerModel on the strand and waits for it.
::morph::exec::detail::ModelId registerModelWithContext (const std::string &typeId, std::function< std::unique_ptr<::morph::model::detail::IModelHolder >()> factory, std::string_view contextKey) override
 Runs the wrapped backend's registerModelWithContext on the strand and waits for it.
void assignPrimary (::morph::exec::detail::ModelId mid, const std::string &typeId, std::string_view primary) override
 Runs the wrapped backend's assignPrimary on the strand and waits for it.
std::vector< std::string > listInstances (const std::string &typeId) override
 Runs the wrapped backend's listInstances on the strand and waits for it.
void deregisterModel (::morph::exec::detail::ModelId mid) override
 Queues the wrapped backend's deregisterModel.
::morph::async::Completion< std::shared_ptr< void > > execute (::morph::exec::detail::ModelId mid, detail::ActionCall call, ::morph::exec::IExecutor *cbExec) override
 Queues the dispatch on the strand and returns its Completion at once.
void executeInto (::morph::exec::detail::ModelId mid, detail::ActionCall call, ::morph::exec::IExecutor *cbExec, std::shared_ptr<::morph::async::detail::ISettleSink > sink) override
 Queues the wrapped backend's executeInto on the strand.
void notifyBackendChanged () override
 Queues the wrapped backend's notifyBackendChanged.
void cancelPending (const std::exception_ptr &exc) override
 Rejects the binds this adapter produced, then queues the wrapped backend's own cancelPending.
void setReconnectHandler (std::function< void()> handler, ::morph::exec::IExecutor *exec) override
 Queues the installation on the wrapped backend.
void setEventHandler (std::function< void(::morph::wire::EventBody)> handler, ::morph::exec::IExecutor *exec) override
 Queues the installation on the wrapped backend.
void setConnectHandler (const std::function< void()> &handler) override
 Queues the installation on the wrapped backend.
void setDisconnectHandler (const std::function< void()> &handler) override
 Queues the installation on the wrapped backend.
void setSession (::morph::session::Context session) override
 Queues the session on the wrapped backend.

Detailed Description

Makes a blocking backend reach its caller without blocking it — and without touching the backend.

A decorator, not a base class: it wraps an existing IBackend and runs every one of its verbs on one control strand over an executor this adapter names. That strand is the wrapped backend's one owner, so a backend that keeps its state without a lock (LocalBackend) stays correct behind it, and the caller's thread never pays for a blocking control call.

What it does and does not change
The wrapped backend still blocks — nothing here makes a nested event loop or a socket round trip non-blocking. What changes is which thread pays: bindModel returns at once with an unsettled Completion, settled from the strand when the wrapped backend's bind has run there, and execute returns at once too. A single-threaded WASM main thread has no such executor to offer and is therefore not what this adapter is for; that case needs a backend with a genuinely non-blocking path.
Why the executor is required rather than optional
"Where does the blocking happen" is the only question this class exists to answer, so it is a constructor parameter with no default.
Ordering
Every verb is queued on the one strand, so the wrapped backend sees them one at a time and in the order they were issued. ~SynchronousBackendAdapter waits for every queued and in-flight call, so a reply can never land in a destroyed adapter; the executor must therefore still be running tasks when this adapter is destroyed (see docs/spec/concurrency_and_lifetimes.md, "Destruction ordering"). The single-threaded WebAssembly build has no thread to wait for: there the calls still queued are dropped.
Owner
The adapter itself belongs to its caller's owner (setOwner): bindModel, promoteModel and cancelPending keep the list of pending binds there, without a lock. The synchronous verbs (registerModel, registerModelWithContext, assignPrimary, listInstances) wait for the strand, so they must not be called from the executor's only thread.

Definition at line 694 of file backend.hpp.

Member Typedef Documentation

◆ BindPromise

The producer side of a bindModel/promoteModel completion.

Named because cancelPending has to hold these weakly; see trackPending.

Definition at line 727 of file backend.hpp.

Constructor & Destructor Documentation

◆ SynchronousBackendAdapter()

morph::backend::SynchronousBackendAdapter::SynchronousBackendAdapter ( std::shared_ptr< detail::IBackend > inner,
::morph::exec::IExecutor & blockingExec )
inline

Wraps inner, running every one of its verbs on blockingExec.

Parameters
innerBackend to wrap. Owned (shared): the adapter keeps it alive for as long as any call it queued is still in flight. Must not be null.
blockingExecExecutor the wrapped backend's calls run on. Borrowed: it must outlive this adapter and keep running tasks until the destructor's wait has completed.
Exceptions
std::invalid_argumentif inner is null.

Definition at line 705 of file backend.hpp.

◆ ~SynchronousBackendAdapter()

morph::backend::SynchronousBackendAdapter::~SynchronousBackendAdapter ( )
inlineoverride

Waits for every queued and in-flight call; see "Ordering" above.

Definition at line 714 of file backend.hpp.

Member Function Documentation

◆ wrapped()

detail::IBackend & morph::backend::SynchronousBackendAdapter::wrapped ( ) const
inlinenodiscardnoexcept

The wrapped backend.

Returns
Reference to the backend passed at construction; never null.

Definition at line 731 of file backend.hpp.

◆ bindModel()

::morph::async::Completion<::morph::exec::detail::ModelId > morph::backend::SynchronousBackendAdapter::bindModel ( detail::BindRequest request,
::morph::exec::IExecutor & cbExec )
inlineoverride

Acquires a model instance without blocking the calling thread.

Queues the wrapped backend's bindModel on the control strand and returns. Exactly one of the returned Completion's then/onError handlers runs, on cbExec.

Parameters
requestOwning bind request; moved from.
cbExecExecutor the continuation is delivered on. Borrowed: it must outlive the returned Completion.
Returns
A Completion resolved with the bound ModelId, or rejected with the wrapped backend's failure.

Definition at line 743 of file backend.hpp.

◆ promoteModel()

::morph::async::Completion<::morph::exec::detail::ModelId > morph::backend::SynchronousBackendAdapter::promoteModel ( detail::PromoteRequest request,
::morph::exec::IExecutor & cbExec )
inlineoverride

Files an already-live instance under a key without blocking the caller.

The promote counterpart of bindModel above, on the same strand and with the same settling rules.

Parameters
requestOwning promote request; moved from.
cbExecExecutor the continuation is delivered on. Borrowed: it must outlive the returned Completion.
Returns
A Completion resolved with request.mid, or rejected.

Definition at line 760 of file backend.hpp.

◆ setOwner()

void morph::backend::SynchronousBackendAdapter::setOwner ( const ::morph::exec::detail::OwnerAffinity & owner)
inlineoverride

Records the caller's owner. Not forwarded: the wrapped backend's owner is this adapter's control strand.

Parameters
ownerThe caller's owner.

Definition at line 772 of file backend.hpp.

◆ registerModel()

::morph::exec::detail::ModelId morph::backend::SynchronousBackendAdapter::registerModel ( const std::string & typeId,
std::function< std::unique_ptr<::morph::model::detail::IModelHolder >()> factory )
inlineoverride

Runs the wrapped backend's registerModel on the strand and waits for it.

Parameters
typeIdString type-id of the model to instantiate.
factoryCallable that constructs the IModelHolder.
Returns
The wrapped backend's ModelId.

Definition at line 778 of file backend.hpp.

◆ registerModelWithContext()

::morph::exec::detail::ModelId morph::backend::SynchronousBackendAdapter::registerModelWithContext ( const std::string & typeId,
std::function< std::unique_ptr<::morph::model::detail::IModelHolder >()> factory,
std::string_view contextKey )
inlineoverride

Runs the wrapped backend's registerModelWithContext on the strand and waits for it.

Parameters
typeIdString type-id of the model to instantiate.
factoryCallable that constructs the IModelHolder.
contextKeyStable identity of the new instance; empty if none.
Returns
The wrapped backend's ModelId.

Definition at line 791 of file backend.hpp.

◆ assignPrimary()

void morph::backend::SynchronousBackendAdapter::assignPrimary ( ::morph::exec::detail::ModelId mid,
const std::string & typeId,
std::string_view primary )
inlineoverride

Runs the wrapped backend's assignPrimary on the strand and waits for it.

Parameters
midLive instance to promote.
typeIdModel type id — the directory's first key component.
primaryCanonical string encoding of the key to file it under.

Definition at line 804 of file backend.hpp.

◆ listInstances()

std::vector< std::string > morph::backend::SynchronousBackendAdapter::listInstances ( const std::string & typeId)
inlineoverride

Runs the wrapped backend's listInstances on the strand and waits for it.

Parameters
typeIdString type-id to enumerate.
Returns
The wrapped backend's snapshot of live shared instance keys.

Definition at line 815 of file backend.hpp.

◆ deregisterModel()

void morph::backend::SynchronousBackendAdapter::deregisterModel ( ::morph::exec::detail::ModelId mid)
inlineoverride

Queues the wrapped backend's deregisterModel.

Parameters
midInstance to release.

Definition at line 821 of file backend.hpp.

◆ execute()

::morph::async::Completion< std::shared_ptr< void > > morph::backend::SynchronousBackendAdapter::execute ( ::morph::exec::detail::ModelId mid,
detail::ActionCall call,
::morph::exec::IExecutor * cbExec )
inlineoverride

Queues the dispatch on the strand and returns its Completion at once.

Parameters
midInstance to dispatch against.
callThe action call to dispatch.
cbExecExecutor the resulting Completion's callbacks are posted on.
Returns
A Completion settled by the wrapped backend.

Definition at line 830 of file backend.hpp.

◆ executeInto()

void morph::backend::SynchronousBackendAdapter::executeInto ( ::morph::exec::detail::ModelId mid,
detail::ActionCall call,
::morph::exec::IExecutor * cbExec,
std::shared_ptr<::morph::async::detail::ISettleSink > sink )
inlineoverride

Queues the wrapped backend's executeInto on the strand.

Parameters
midInstance to dispatch against.
callThe action call to dispatch.
cbExecExecutor for delivering callbacks attached to the caller's own completion.
sinkWhere the wrapped backend settles the outcome.

Definition at line 845 of file backend.hpp.

◆ notifyBackendChanged()

void morph::backend::SynchronousBackendAdapter::notifyBackendChanged ( )
inlineoverride

Queues the wrapped backend's notifyBackendChanged.

Definition at line 857 of file backend.hpp.

◆ cancelPending()

void morph::backend::SynchronousBackendAdapter::cancelPending ( const std::exception_ptr & exc)
inlineoverride

Rejects the binds this adapter produced, then queues the wrapped backend's own cancelPending.

A bindModel here settles from a task on the strand, holding a promise the wrapped backend never sees, so the wrapped backend's cancelPending reaches nothing of it: without this a bind cancelled by ~Bridge or by switchBackend would go on to resolve successfully afterwards.

Each queued bind carries a cancellation flag beside its promise, set here before the promise is rejected: a bind still queued sees it when it reaches the head of the strand and never reaches the wrapped backend, so no instance is created that nothing will deregister. A bind already running on the strand cannot be recalled; its completion stays rejected. The wrapped backend's own pending calls are cancelled on the strand, in order with everything queued before this call.

Parameters
excException delivered to every still-pending completion, this adapter's own and then the wrapped backend's.

Definition at line 878 of file backend.hpp.

◆ setReconnectHandler()

void morph::backend::SynchronousBackendAdapter::setReconnectHandler ( std::function< void()> handler,
::morph::exec::IExecutor * exec )
inlineoverride

Queues the installation on the wrapped backend.

Parameters
handlerCallable posted to exec after a successful reconnect; nullptr clears.
execExecutor the handler is posted to.

Definition at line 894 of file backend.hpp.

◆ setEventHandler()

void morph::backend::SynchronousBackendAdapter::setEventHandler ( std::function< void(::morph::wire::EventBody)> handler,
::morph::exec::IExecutor * exec )
inlineoverride

Queues the installation on the wrapped backend.

Parameters
handlerCallable posted to exec once per event; nullptr clears.
execExecutor the handler is posted to.

Definition at line 903 of file backend.hpp.

◆ setConnectHandler()

void morph::backend::SynchronousBackendAdapter::setConnectHandler ( const std::function< void()> & handler)
inlineoverride

Queues the installation on the wrapped backend.

Parameters
handlerCallable invoked after every successful connect; nullptr clears.

Definition at line 912 of file backend.hpp.

◆ setDisconnectHandler()

void morph::backend::SynchronousBackendAdapter::setDisconnectHandler ( const std::function< void()> & handler)
inlineoverride

Queues the installation on the wrapped backend.

Parameters
handlerCallable invoked whenever the transport drops; nullptr clears.

Definition at line 918 of file backend.hpp.

◆ setSession()

void morph::backend::SynchronousBackendAdapter::setSession ( ::morph::session::Context session)
inlineoverride

Queues the session on the wrapped backend.

Parameters
sessionSession stamped onto every subsequently built control envelope.

Definition at line 924 of file backend.hpp.


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