morph 0.1.0
Asynchronous bridge between GUI thread and business models
Loading...
Searching...
No Matches
tagged.hpp File Reference

Tagged<T, "Name"> — an opaque, type-safe newtype for protocol scalars that serializes transparently as its underlying T. More...

#include <compare>
#include <cstddef>
#include <glaze/glaze.hpp>
#include <morph/core/payload_shape_tag.hpp>
#include <string>
#include <string_view>
#include <type_traits>
#include <utility>
#include "../attributes.hpp"
#include "../detail/fixed_string.hpp"

Go to the source code of this file.

Classes

struct  morph::util::Tagged< T, Tag >
 An opaque, type-safe newtype wrapping a protocol scalar T, distinguished at compile time by the string tag Tag. More...
struct  morph::util::detail::IsTagged< T >
 Trait: is T some Tagged<...>? More...
struct  morph::model::PayloadShapeTag< morph::util::Tagged< T, Tag > >
 Stable shape tag for Tagged<T, Tag>, carrying both the tag text and the wrapped type's own shape. More...

Variables

template<typename T>
constexpr bool morph::util::isTagged = detail::IsTagged<std::remove_cvref_t<T>>::value
 true when T (cvref-stripped) is a morph::util::Tagged.

Detailed Description

Tagged<T, "Name"> — an opaque, type-safe newtype for protocol scalars that serializes transparently as its underlying T.

A protocol scalar (a pagination cursor, an event id, a job id, a bearer token) is a T (usually std::string or an integer) that must not be interchangeable with a different scalar of the same underlying type — Tagged<std::string, "UserId"> and Tagged<std::string, "AccountId"> carry the same wire representation but are distinct C++ types, so passing one where the other is expected is a compile error rather than a silent mix-up caught (or not) at runtime.

Tag is a morph::detail::FixedString non-type template parameter (the same structural string type morph::forms::Choice and morph::units::NamedQuantity use), so the identity lives in the type itself — two Tagged<T, "X"> written identically in different translation units are one and the same type, and no companion enum or registry is needed to keep tags distinct.

Wire. On the morph JSON wire a Tagged<T, Tag> is exactly its T payload — glz::meta maps the instance to value alone, so it reads and writes identically to a bare T, and to_json_schema delegates to T's own schema (the tag never appears on the wire or in the generated schema).

Forms palette. Tagged is a required scalar, not an optionally-empty field like Quantity/Choice/Timestamp: it always holds a T (default-constructed, never std::nullopt). Its hasValue() therefore always returns true, satisfying morph::forms::EmptyCapableField so it composes with the palette (rule vocabulary, allRequiredEngaged, etc.) the same way any other required field does — nothing in the palette special-cases it away like a plain, non-empty-capable scalar member would be.

Definition in file tagged.hpp.

Variable Documentation

◆ isTagged

template<typename T>
bool morph::util::isTagged = detail::IsTagged<std::remove_cvref_t<T>>::value
inlineconstexpr

true when T (cvref-stripped) is a morph::util::Tagged.

Definition at line 120 of file tagged.hpp.