morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
morph::async::Completion< T > Class Template Reference

Move-only handle representing the eventual result of an asynchronous operation. More...

#include <completion.hpp>

Classes

class  Promise
 Producer-side handle paired with a Completion<T> by makeSettleable(). More...

Public Member Functions

 Completion ()=default
 Constructs an empty (no-op) completion.
 Completion (std::shared_ptr< detail::CompletionState< T > > statePtr, ::morph::exec::IExecutor *execPtr)
 Constructs a completion backed by statePtr, delivering callbacks via execPtr.
 Completion (Completion &&) noexcept=default
 Move constructor — transfers ownership of the underlying state.
Completion & operator= (Completion &&) noexcept=default
 Move assignment — transfers ownership of the underlying state.
 Completion (const Completion &)=delete
Completion & operator= (const Completion &)=delete
Completion & then (std::function< void(const T &)> handler)
 Registers a success callback.
Completion & onError (std::function< void(std::exception_ptr)> handler)
 Registers an error callback.
Completion & then (const CallbackScope &scope, std::function< void(const T &)> handler)
 Registers a success callback gated on scope's lifetime and stop state.
Completion & then (CallbackToken token, std::function< void(const T &)> handler)
 Registers a success callback gated on an already-issued token.
Completion & onError (const CallbackScope &scope, std::function< void(std::exception_ptr)> handler)
 Registers an error callback gated on scope's lifetime and stop state.
Completion & onError (CallbackToken token, std::function< void(std::exception_ptr)> handler)
 Registers an error callback gated on an already-issued token.
Completion & thenDetached (std::function< void(const T &)> handler)
 Registers a success callback whose lifetime is deliberately unmanaged.
Completion & onErrorDetached (std::function< void(std::exception_ptr)> handler)
 Registers an error callback whose lifetime is deliberately unmanaged.
detail::CompletionAwaiter< T > operator co_await () &&
 Awaits this completion from a coroutine, consuming it.
std::shared_ptr< detail::CompletionState< T > > state () const
 Returns the underlying shared state (for advanced / internal use).

Static Public Member Functions

static std::pair< Completion< T >, Promise > makeSettleable (::morph::exec::IExecutor *execPtr)
 Constructs a Completion<T>/Promise<T> pair sharing one settleable state.

Detailed Description

template<typename T>
class morph::async::Completion< T >

Move-only handle representing the eventual result of an asynchronous operation.

Callbacks are posted to the IExecutor supplied at construction time, so they always run on the intended thread (e.g. the GUI thread).

Thread safety
A completion belongs to the executor supplied at construction, its owner. It may be settled from any thread: the first settle wins, and its delivery is posted to the owner, where every registered callback runs. then() and onError() must be called on the owner – inside one of its tasks, or on its own thread outside them (a Qt slot, a test body). Calling them from another executor's task is a contract violation, asserted in a debug build. co_await may be used from any coroutine: it posts its attach to the owner when it is not running there.
Orphan detection
If a Completion is destroyed before an onError() handler is attached and the operation has already failed, the exception is logged as an orphan error.
Lifetime and stop gating
Because delivery always goes through an executor, the receiver can be destroyed — or simply lose interest — before the handler runs. Pass a morph::async::CallbackScope (or one of its CallbackTokens) as the first argument to then() / onError() and the handler is refused unless the scope is still alive and un-stopped at delivery time. thenDetached() / onErrorDetached() are the same ungated attachments as then(fn) / onError(fn), spelled so a deliberately unmanaged callback says so. See callback_scope.hpp and docs/spec/core/callback_scope.md.
Value-handling contract
T need only be move-constructible; that is the whole type requirement. Copyability is a per-handler obligation, reported where the handler is written rather than imposed on the whole instantiation:
  • a handler taking const T& costs zero copies;
  • a handler taking T by value costs exactly one, at its own parameter binding, and requires T to be copyable.

The budget does not depend on how many handlers are attached, nor on whether they attached before or after the completion settled. The value is observed, never consumed: no handler can move out of the stored value, so a then() attached after settling still sees the genuine result. A handler that wants to consume takes T by value and moves out of its own copy. See docs/spec/core/completion.md, "Value-handling contract".

Template Parameters
TType of the success value. Must be move-constructible.

Definition at line 466 of file completion.hpp.

Constructor & Destructor Documentation

◆ Completion()

template<typename T>
morph::async::Completion< T >::Completion ( std::shared_ptr< detail::CompletionState< T > > statePtr,
::morph::exec::IExecutor * execPtr )
inline

Constructs a completion backed by statePtr, delivering callbacks via execPtr.

Parameters
statePtrShared state produced by the backend.
execPtrThe completion's owner: settling posts the delivery there, and callbacks are attached and run there. It must be serial (IExecutor::isSerial): a pool or the inline executor is refused, asserted in a debug build. If nullptr, callbacks are never delivered — attaching one is a no-op.

Definition at line 478 of file completion.hpp.

Member Function Documentation

◆ operator=()

template<typename T>
Completion & morph::async::Completion< T >::operator= ( Completion< T > && )
defaultnoexcept

Move assignment — transfers ownership of the underlying state.

Returns
*this.

◆ then() [1/3]

template<typename T>
Completion & morph::async::Completion< T >::then ( std::function< void(const T &)> handler)
inline

Registers a success callback.

handler runs on the executor with the result value when the operation completes successfully. If the result has already been delivered, the callback is posted on its own. Call on the owner (see the class's thread-safety note).

Parameters
handlerCallable receiving the result. Take const T& to observe it for free; take T by value to get your own copy, at the cost of exactly one copy.
Returns
*this for chaining — a reference into this Completion, valid only for as long as it is.

Definition at line 512 of file completion.hpp.

◆ onError() [1/3]

template<typename T>
Completion & morph::async::Completion< T >::onError ( std::function< void(std::exception_ptr)> handler)
inline

Registers an error callback.

handler runs on the executor with the std::exception_ptr when the operation fails. If the failure has already been delivered, the callback is posted on its own. Attaching this handler suppresses orphan logging. Call on the owner (see the class's thread-safety note).

Parameters
handlerCallable receiving the exception pointer.
Returns
*this for chaining — a reference into this Completion, valid only for as long as it is.

Definition at line 529 of file completion.hpp.

◆ then() [2/3]

template<typename T>
Completion & morph::async::Completion< T >::then ( const CallbackScope & scope,
std::function< void(const T &)> handler )
inline

Registers a success callback gated on scope's lifetime and stop state.

Identical to then(handler) except that handler is wrapped in a CallbackToken gate at attach time: when the result is delivered, the handler runs only if scope is still alive and has not been stopped or reset(). Nothing else changes — the gate lives inside the stored handler, so fan-out, the attach-after-ready fire-now path and executor marshalling all behave exactly as they do for the ungated form.

Attaching also makes the call this completion reports on one the scope owns: when the call carries a stop source (a Bridge call whose handler returns a Task), stopping, resetting or destroying the scope before it settles requests stop on it.

The scope is observed weakly; attaching does not extend its lifetime.

Parameters
scopeReceiver-owned gate. Only a token for its current generation is captured, so a later reset() retires this attachment.
handlerCallable receiving the result. Take const T& to observe it for free; take T by value to get your own copy, at the cost of exactly one copy.
Returns
*this for chaining — a reference into this Completion, valid only for as long as it is.

Definition at line 559 of file completion.hpp.

◆ then() [3/3]

template<typename T>
Completion & morph::async::Completion< T >::then ( CallbackToken token,
std::function< void(const T &)> handler )
inline

Registers a success callback gated on an already-issued token.

The token-taking form of then(const CallbackScope&, handler), for callers that hold a token rather than the scope itself (a helper that was handed one, or code that captured a token before dispatching).

Parameters
tokenGate observing some receiver's CallbackScope. A default-constructed token suppresses unconditionally.
handlerCallable receiving the result. Take const T& to observe it for free; take T by value to get your own copy, at the cost of exactly one copy.
Returns
*this for chaining — a reference into this Completion, valid only for as long as it is.

Definition at line 575 of file completion.hpp.

◆ onError() [2/3]

template<typename T>
Completion & morph::async::Completion< T >::onError ( const CallbackScope & scope,
std::function< void(std::exception_ptr)> handler )
inline

Registers an error callback gated on scope's lifetime and stop state.

Identical to onError(handler) except that handler is wrapped in a CallbackToken gate at attach time.

Orphan logging is unaffected: attaching a gated handler suppresses it exactly as the ungated form does, and an error whose delivery the scope then refuses still counts as handled. Suppression is a deliberate act by the receiver, not a dropped error nobody asked about.

Parameters
scopeReceiver-owned gate; observed weakly.
handlerCallable receiving the exception pointer.
Returns
*this for chaining — a reference into this Completion, valid only for as long as it is.

Definition at line 596 of file completion.hpp.

◆ onError() [3/3]

template<typename T>
Completion & morph::async::Completion< T >::onError ( CallbackToken token,
std::function< void(std::exception_ptr)> handler )
inline

Registers an error callback gated on an already-issued token.

The token-taking form of onError(const CallbackScope&, handler).

Parameters
tokenGate observing some receiver's CallbackScope. A default-constructed token suppresses unconditionally.
handlerCallable receiving the exception pointer.
Returns
*this for chaining — a reference into this Completion, valid only for as long as it is.

Definition at line 610 of file completion.hpp.

◆ thenDetached()

template<typename T>
Completion & morph::async::Completion< T >::thenDetached ( std::function< void(const T &)> handler)
inline

Registers a success callback whose lifetime is deliberately unmanaged.

Exactly then(handler), spelled so that "no scope gates this" is a statement the author made on purpose and a reviewer can grep for. Use it when the handler genuinely owns everything it touches — it captures only values, or a shared_ptr it keeps alive itself.

Parameters
handlerCallable receiving the result. Take const T& to observe it for free; take T by value to get your own copy, at the cost of exactly one copy.
Returns
*this for chaining — a reference into this Completion, valid only for as long as it is.

Definition at line 628 of file completion.hpp.

◆ onErrorDetached()

template<typename T>
Completion & morph::async::Completion< T >::onErrorDetached ( std::function< void(std::exception_ptr)> handler)
inline

Registers an error callback whose lifetime is deliberately unmanaged.

The onError counterpart of thenDetached().

Parameters
handlerCallable receiving the exception pointer.
Returns
*this for chaining — a reference into this Completion, valid only for as long as it is.

Definition at line 639 of file completion.hpp.

◆ operator co_await()

template<typename T>
detail::CompletionAwaiter< T > morph::async::Completion< T >::operator co_await ( ) &&
inlinenodiscard

Awaits this completion from a coroutine, consuming it.

co_await std::move(completion) yields a copy of the settled value or rethrows the stored exception. The coroutine resumes in the resumption context it suspended in – a spawned task's executor, a Task handler's strand – or, with none, on this completion's executor, where then() handlers run. A stop requested on the awaiting coroutine's token withdraws the await and resumes it with core::async::OperationCancelled. Rvalue only: awaiting moves the state out, so an lvalue co_await would hide that the completion is empty afterwards. See docs/spec/core/coroutines.md.

Returns
The awaiter; not for direct use.

Definition at line 655 of file completion.hpp.

◆ state()

template<typename T>
std::shared_ptr< detail::CompletionState< T > > morph::async::Completion< T >::state ( ) const
inlinenodiscard

Returns the underlying shared state (for advanced / internal use).

Returns
Shared pointer to the completion state, or nullptr for empty completions.

Definition at line 664 of file completion.hpp.

◆ makeSettleable()

template<typename T>
std::pair< Completion< T >, Promise > morph::async::Completion< T >::makeSettleable ( ::morph::exec::IExecutor * execPtr)
inlinestaticnodiscard

Constructs a Completion<T>/Promise<T> pair sharing one settleable state.

The public "settleable promise" seam: lets a caller — typically test code — construct a Completion<T> it can resolve or reject on demand, without a full Bridge/IBackend round trip and without reaching into morph::async::detail::CompletionState<T>. Everything Completion(state, executor) already provided by hand is available through this factory instead: the returned Completion<T> is exactly what then()/onError() observe; the returned Promise is exactly what settles it.

Parameters
execPtrExecutor callbacks are posted on; nullptr for a write-only completion (see the two-argument constructor).
Returns
A {Completion<T>, Promise} pair sharing one CompletionState<T>.

Definition at line 738 of file completion.hpp.


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