6#include <glaze/glaze.hpp>
18#include "registry.hpp"
29namespace morph::record {
41template <
typename... S>
70 static constexpr bool value =
false;
75 static constexpr bool value =
true;
77 static constexpr auto member = Member;
84template <
typename... S>
91template <
typename Class,
typename Member>
101 using Plain = std::remove_cvref_t<K>;
103 return std::is_same_v<model::detail::UnwrappedKeyOf<Plain>, std::string>;
105 return std::is_same_v<Plain, std::string>;
114template <
typename Class,
typename Member>
117 void const*
const target = std::addressof(probe.*member);
119 [&]<std::size_t... Index>(std::index_sequence<Index...>) {
120 auto visit = [&]<std::size_t I>() {
122 if constexpr (std::is_reference_v<
decltype(value)>) {
123 if (
static_cast<void const*
>(std::addressof(value)) == target) {
124 found = std::string{glz::reflect<Class>::keys[I]};
128 (visit.template operator()<Index>(), ...);
129 }(std::make_index_sequence<glz::reflect<Class>::size>{});
138 constexpr auto keys = glz::reflect<T>::keys;
139 for (std::size_t i = 0; i < keys.size(); ++i) {
140 if (keys[i] ==
"id") {
151template <
typename T,
typename... Opts>
153 constexpr bool keyless_ = (std::is_same_v<Opts, keyless> || ...);
155 static_assert(explicitKeys <= 1,
"BRIDGE_REGISTER_RECORD: at most one key<> option");
156 static_assert(!(keyless_ && explicitKeys > 0),
"BRIDGE_REGISTER_RECORD: keyless and key<> contradict");
157 if constexpr (keyless_) {
159 }
else if constexpr (explicitKeys == 1) {
160 auto const apply = []<
typename O>(
RecordInfo& target) {
164 "BRIDGE_REGISTER_RECORD: a key member must be a ModelKey");
166 assert(!name.empty() &&
"BRIDGE_REGISTER_RECORD: key<> names a member glaze does not reflect");
168 target.keyField = std::move(name);
173 (apply.template operator()<Opts>(info), ...);
174 }
else if constexpr (
constexpr std::size_t index =
idIndex<T>(); index < glz::reflect<T>::size) {
175 using Raw = std::remove_cvref_t<decltype(morph::detail::reflectedMember<index>(std::declval<T&>()))>;
176 static_assert(
model::ModelKey<Raw>,
"BRIDGE_REGISTER_RECORD: the `id` member must be a ModelKey");
177 info.keyField =
"id";
185 static std::vector<RecordInfo> entries;
198template <
typename T,
typename... Opts>
201 assert(!::morph::model::registrationPhaseClosed() &&
202 "registerRecordOnce: registration after the registration phase closed. The process-level "
203 "registries are unsynchronised and are read-only once dispatch begins -- registering now "
204 "races their internals against concurrent lookups. Load and register plugin modules before "
205 "the first dispatch.");
206 RecordInfo info{.name = std::string{name}, .type = std::type_index{
typeid(T)}, .keyField = {}, .derivedFrom = {}};
208 info.privateKeys = (std::is_same_v<Opts, privateKeys> || ... ||
false);
210 [[maybe_unused]]
auto const addSources = []<
typename O>(
RecordInfo& target) {
212 []<
typename... S>(
RecordInfo& out,
derivedFrom<S...>) { (out.derivedFrom.emplace_back(
typeid(S)), ...); }(
216 (addSources.template operator()<Opts>(info), ...);
236#ifdef MORPH_CLIENT_ONLY
237#define BRIDGE_REGISTER_RECORD(T, NAME, ...)
239#define BRIDGE_REGISTER_RECORD(T, NAME, ...) \
241 [[maybe_unused]] const bool BRIDGE_DETAIL_CAT(bridge_record_reg_, __COUNTER__) = \
242 morph::record::detail::registerRecordOnce<T __VA_OPT__(, ) __VA_ARGS__>(NAME); \
Key types a model may declare as its PrimaryKey.
Key types that wrap a RawModelKey — the ladder's strong ids.
std::string memberKeyName(Member Class::*member)
The reflected name of a data member, found by its address in a value-initialised object.
std::vector< RecordInfo > const & recordRegistry()
The records declared so far, raw and unvalidated.
void applyKey(RecordInfo &info)
Fills the key fields of info from the options.
constexpr std::size_t idIndex()
The index of the reflected member named id, or size when there is none.
bool registerRecordOnce(std::string_view name) noexcept
Static-init helper for BRIDGE_REGISTER_RECORD.
std::vector< RecordInfo > & mutableRecordRegistry()
The process-level record list, appended to by static registrars.
constexpr bool keyTypeIsString()
Whether a key member's raw type is std::string, looking through a wrapped strong id.
The value glaze reads and writes under a reflected key.
constexpr decltype(auto) reflectedMember(T &object)
The value glaze reads and writes under glz::reflect<T>::keys[I].
What one BRIDGE_REGISTER_RECORD declared.
std::vector< std::type_index > derivedFrom
The source types this record is derived from.
std::type_index type
The record's C++ type; records and effects are matched by this identity.
bool keyIsString
True when the key's raw type is std::string; false when it is integral or there is no key.
std::string name
The wire name of the record type.
bool privateKeys
True when the record's keys must not reach other principals.
std::optional< std::string > keyField
The glaze JSON name of the key member; empty for a keyless record or one without an id member.
Option for BRIDGE_REGISTER_RECORD: a change to any of S is a change to this record type.
Detects a derivedFrom<> option.
Detects a key<> option and exposes its member pointer.
static constexpr bool value
True for a key<> option.
The type of the data member a member pointer names.
Option for BRIDGE_REGISTER_RECORD: the record's key is the named member instead of id.
Option for BRIDGE_REGISTER_RECORD: the record has no key.
Option for BRIDGE_REGISTER_RECORD: the record's keys must not reach other principals.