|
morph 0.1.0
Asynchronous bridge between GUI thread and business models
|
#include <charconv>#include <concepts>#include <stdexcept>#include <string>#include <string_view>#include <system_error>#include <type_traits>#include <utility>Go to the source code of this file.
Classes | |
| struct | morph::model::ModelKeyTraits< Model > |
| The key type of a model, when one has been declared for it. More... | |
| struct | morph::model::ActionKeyTraits< Action > |
| Declares where an action's model key comes from. More... | |
Concepts | |
| concept | morph::model::RawModelKey |
| Key types that are themselves a wire-encodable scalar. | |
| concept | morph::model::WrappedModelKey |
| Key types that wrap a RawModelKey — the ladder's strong ids. | |
| concept | morph::model::ModelKey |
| Key types a model may declare as its PrimaryKey. | |
| concept | morph::model::KeyedModel |
| Satisfied by model types that have a primary key, however it was named. | |
Macros | |
| #define | BRIDGE_MODEL_KEY(M, A, MEMBER) |
| Declares that action A is the one that defines model M's primary key. | |
| #define | BRIDGE_KEY_FROM(A, MEMBER) |
| Declares that action A also carries its model's primary key in MEMBER. | |
| #define | BRIDGE_MODEL_KEY_FROM_RESULT(M, A, MEMBER) |
| Declares that action A's result establishes its model's primary key. | |
| #define | BRIDGE_KEY_FROM_RESULT(A, MEMBER) |
| Declares that action A's result also establishes its model's key. | |
Typedefs | |
| template<KeyedModel M> | |
| using | morph::model::PrimaryKeyOf = detail::KeyTypeOf<M>::type |
| The primary key type of a keyed model. | |
Functions | |
| template<ModelKey K> | |
| std::string | morph::model::keyToString (const K &key) |
| Encodes a primary key as its canonical wire string. | |
| template<ModelKey K> | |
| K | morph::model::keyFromString (std::string_view text) |
| Decodes a primary key from its canonical wire string. | |
Primary keys for model instances.
A model type declares itself keyed by exposing a nested PrimaryKey type alias; the alias is detected structurally (a requires-expression), never by inheritance or a marker base — the same detection style morph::views::ViewTraits uses for a view's kind/query members. A model without the alias is unkeyed and behaves exactly as it always has.
Actions say which of their fields carries that key via BRIDGE_KEY_FROM, or — for an action that creates the entity rather than naming it — which field of their result establishes it, via BRIDGE_KEY_FROM_RESULT. Actions with neither declaration are keyless and run against whichever instance the handler is already attached to; that is the common case.
Keys travel the wire as strings (wire::Envelope::primary) regardless of their C++ type, so the directory in RemoteServer needs exactly one map type rather than one per key type. See docs/spec/core/shared_instances.md.
Definition in file model_key.hpp.
| #define BRIDGE_MODEL_KEY | ( | M, | |
| A, | |||
| MEMBER ) |
Declares that action A is the one that defines model M's primary key.
One line does both jobs, so the model's own class body needs to say nothing about keys: the key type is deduced from MEMBER's type (defining ModelKeyTraits<M>), and A is recorded as an action that carries it (defining ActionKeyTraits<A>).
Executing such an action on a shareable handler attaches — or re-points — that handler to the instance holding the named key, constructing one only if no instance holds it yet. Every keyless action on that handler afterwards lands on the same instance, which is what makes the common case free of ceremony:
MEMBER is a pointer-to-data-member of A (e.g. &LoadAccount::id) whose type satisfies morph::model::ModelKey. Must appear at global scope; a header included by several translation units is fine, like the other BRIDGE_REGISTER_* macros — this macro emits only explicit specialisations, which [basic.def.odr] permits in multiple translation units when the definitions are token-identical. See docs/spec/core/registry.md, "Header placement is legal".
Definition at line 292 of file model_key.hpp.
| #define BRIDGE_KEY_FROM | ( | A, | |
| MEMBER ) |
Declares that action A also carries its model's primary key in MEMBER.
The companion to BRIDGE_MODEL_KEY, for the other actions that name the same entity — CloseAccount{.id = ...} alongside GetAccount{.id = ...}. It records only that A carries the key; the key's type has already been established by the model's one BRIDGE_MODEL_KEY line, and an explicit specialisation cannot be repeated.
Must appear at global scope; a header included by several translation units is fine (only explicit specialisations are emitted — see docs/spec/core/registry.md, "Header placement is legal").
Definition at line 317 of file model_key.hpp.
| #define BRIDGE_MODEL_KEY_FROM_RESULT | ( | M, | |
| A, | |||
| MEMBER ) |
Declares that action A's result establishes its model's primary key.
For actions that create the entity rather than name it: the key is not in the request, it is generated and returned, exactly as a database insert returns its generated primary key. MEMBER is a pointer-to-data-member of A's result type (e.g. &AccountInfo::id).
Must appear at global scope; a header included by several translation units is fine (only explicit specialisations are emitted — see docs/spec/core/registry.md, "Header placement is legal").
Definition at line 337 of file model_key.hpp.
| #define BRIDGE_KEY_FROM_RESULT | ( | A, | |
| MEMBER ) |
Declares that action A's result also establishes its model's key.
The companion to BRIDGE_MODEL_KEY_FROM_RESULT, for a second creating action on a model whose key type is already established.
Must appear at global scope; a header included by several translation units is fine (only explicit specialisations are emitted — see docs/spec/core/registry.md, "Header placement is legal").
Definition at line 362 of file model_key.hpp.
| using morph::model::PrimaryKeyOf = detail::KeyTypeOf<M>::type |
The primary key type of a keyed model.
| M | Keyed model type. |
Definition at line 142 of file model_key.hpp.
|
nodiscard |
Encodes a primary key as its canonical wire string.
Integral keys are decimal; std::string keys pass through unchanged; a strong id encodes as whatever it wraps, so it shares a directory entry with the raw key of the same value. The encoding is total for every engaged key — each has exactly one representation — so two clients naming the same key always land on the same directory entry.
| K | Key type satisfying ModelKey. |
| key | Key value to encode. |
key. | std::runtime_error | if key is a strong id with no value. Such an id names no instance, and encoding it as "" or "0" would route every caller holding an unset id to a single shared instance. |
Definition at line 158 of file model_key.hpp.
|
nodiscard |
Decodes a primary key from its canonical wire string.
A strong id is reconstructed by decoding what it wraps and rewrapping it, so keyFromString<PasteId>(keyToString(id)) == id for any engaged id.
| K | Key type satisfying ModelKey. |
| text | Canonical string form, as produced by keyToString. |
| std::runtime_error | if text is not a valid encoding of a K (non-numeric text, trailing garbage, or a value out of range). A key that cannot be decoded is a protocol error, not a value to clamp: silently yielding 0 would route the caller to the wrong instance. |
Definition at line 190 of file model_key.hpp.