226 Model(detail::RecordOps* ops,
const T* instance)
239 template <ultralight::detail::FixedString Name>
242 using Tok = std::tuple_element_t<idx, std::remove_cvref_t<
decltype(
Base::schema())>>;
243 static_assert(detail::EntryInfo<Tok>::kClass != detail::EntryClass::kAction,
244 "actions have no value to sync");
245 static_assert(detail::EntryInfo<Tok>::kHasAccessor,
246 "accessorless fields are written with Set, not synced");
263 template <ultralight::detail::FixedString... Names>
266 SyncRangeExcept<Names...>(std::make_index_sequence<
Base::schema().kCount> {});
277 template <ultralight::detail::FixedString Name,
typename Arg>
278 void Set(
const Arg& value) {
280 using Tok = std::tuple_element_t<idx, std::remove_cvref_t<
decltype(
Base::schema())>>;
281 using Info = detail::EntryInfo<Tok>;
282 static_assert(Info::kClass == detail::EntryClass::kLeaf
283 || Info::kClass == detail::EntryClass::kVar,
284 "Set writes leaf values; objects, lists, and actions have no slot value");
285 using Value =
typename Tok::value_type;
286 static_assert(std::is_convertible_v<const Arg&, Value>,
287 "value is not convertible to the field's declared value type");
288 WriteSlot<Info::kKind>(
static_cast<uint32_t
>(idx),
295 template <
size_t... Is>
296 void SyncRange(std::index_sequence<Is...>) {
297 (SyncEntryIfSyncable<Is>(), ...);
300 template <ultralight::detail::FixedString... Names,
size_t... Is>
301 void SyncRangeExcept(std::index_sequence<Is...>) {
302 (SyncEntryIfIncluded<Is, Names...>(), ...);
305 template <
size_t I, ultralight::detail::FixedString... Names>
306 void SyncEntryIfIncluded() {
307 constexpr bool excluded = ((
Base::schema().IndexOf(Names.view()) == I) || ...);
308 if constexpr (!excluded)
309 SyncEntryIfSyncable<I>();
313 void SyncEntryIfSyncable() {
314 using SchemaT = std::remove_cvref_t<
decltype(
Base::schema())>;
315 using Info = detail::EntryInfo<std::tuple_element_t<I, SchemaT>>;
316 if constexpr (Info::kClass != detail::EntryClass::kAction && Info::kHasAccessor)
323 using Tok = std::remove_cvref_t<
decltype(token)>;
324 using Info = detail::EntryInfo<Tok>;
325 static_assert(
requires(
const T& t,
const Tok& tk) { detail::ReadAccessor(tk.accessor, t); },
326 "schema accessor does not read this described type (accessor owner "
327 "mismatch at the TypeTraits pairing)");
330 constexpr uint32_t slot =
static_cast<uint32_t
>(I);
331 detail::RecordOps* ops = this->
ops_;
332 if constexpr (Info::kClass == detail::EntryClass::kLeaf
333 || Info::kClass == detail::EntryClass::kVar) {
334 using Value =
typename Tok::value_type;
335 WriteSlot<Info::kKind>(slot,
336 ValueTraits<Value>::ToSlot(
337 detail::ReadAccessor(token.accessor, *instance_)));
338 }
else if constexpr (Info::kClass == detail::EntryClass::kNullableObject) {
339 decltype(
auto) value = detail::ReadAccessor(token.accessor, *instance_);
340 const bool present =
static_cast<bool>(value);
341 if (ops && ops->set_present)
342 ops->set_present(ops->state, slot, present);
344 if (detail::RecordOps* child = (ops && ops->child) ? ops->child(ops->state, slot)
346 detail::SyncType(child, *value);
348 }
else if constexpr (Info::kClass == detail::EntryClass::kObject) {
349 decltype(
auto) value = detail::ReadAccessor(token.accessor, *instance_);
350 if (detail::RecordOps* child = (ops && ops->child) ? ops->child(ops->state, slot)
352 detail::SyncType(child, value);
353 }
else if constexpr (Info::kClass == detail::EntryClass::kList) {
358 template <
size_t I,
typename Tok>
359 void SyncList(
const Tok& token) {
360 detail::RecordOps* ops = this->
ops_;
363 constexpr uint32_t slot =
static_cast<uint32_t
>(I);
364 decltype(
auto) rows = detail::ReadAccessor(token.accessor, *instance_);
366 =
static_cast<uint64_t
>(std::distance(std::begin(rows), std::end(rows)));
368 ops->list_begin(ops->state, slot, count);
369 constexpr bool keyed = [] {
370 if constexpr (detail::IsListToken<Tok>::value)
375 uint64_t ordinal = 0;
376 for (
const auto&
row : rows) {
377 detail::RecordOps* row_ops =
nullptr;
378 if constexpr (keyed) {
379 using Key = detail::AccessorValue<typename Tok::key_pointer_type>;
380 constexpr ValueKind key_kind = ValueTraits<Key>::kind;
382 if (ops->list_row_key_int64)
383 row_ops = ops->list_row_key_int64(ops->state, slot, ordinal,
384 ValueTraits<Key>::ToSlot(
row.*token.key));
386 const String key = ValueTraits<Key>::ToSlot(
row.*token.key);
387 if (ops->list_row_key_string)
388 row_ops = ops->list_row_key_string(ops->state, slot, ordinal, &key);
392 row_ops = ops->list_row(ops->state, slot, ordinal);
395 detail::SyncType(row_ops,
row);
399 ops->list_end(ops->state, slot);
402 template <ValueKind K,
typename SlotV>
403 void WriteSlot(uint32_t slot,
const SlotV& value) {
404 detail::RecordOps* ops = this->
ops_;
409 ops->set_bool(ops->state, slot, value);
412 ops->set_int64(ops->state, slot, value);
415 ops->set_double(ops->state, slot, value);
417 const String& stored = value;
419 ops->set_string(ops->state, slot, &stored);
422 ops->set_style(ops->state, slot, value);
425 ops->set_color(ops->state, slot, value);
427 static_assert(detail::kAlwaysFalse<SlotV>,
"unsupported slot kind");