cheatah
Source

stdlib/parsers/json/schema.hpp

1// Copyright (c) 2026 BigBrain LLC. MIT-licensed (see LICENSE).
2// Original work; see ACKNOWLEDGMENTS.md for the open-source ideas we build upon.
3#pragma once
5// cheatah::parsers::json — compile-time SCHEMA for reading JSON straight into user structs.
6//
7// A struct opts in NON-INTRUSIVELY by specializing the `schema<T>` variable template with an
8// `object(field(...), ...)` description — no base class, no macro, no member function, so it works
9// for third-party / aggregate types you cannot edit:
10//
11// struct Ohlc { std::string date; double open; double close; };
12// template<> inline constexpr auto schema<Ohlc> = object(
13// field("date", &Ohlc::date),
14// field("open", &Ohlc::open),
15// field("close", &Ohlc::close));
16//
17// read.hpp consumes this at compile time to parse directly into the fields (no Node/variant DOM).
18// Fully static; no runtime polymorphism.
20#include <string_view>
21#include <tuple>
22#include <type_traits>
24namespace cheatah::parsers::json {
26/**
27 * @brief One mapping from a JSON object key to a struct data member (a key name plus a
28 * pointer-to-member).
29 * @tparam Class the struct type owning the member.
30 * @tparam Member the member's value type.
31 */
32template <class Class, class Member>
33struct Field {
34 std::string_view name; ///< the JSON object key this field maps to.
35 Member Class::*ptr; ///< pointer to the target data member of @p Class.
36 using class_type = Class; ///< the struct type owning the member.
37 using member_type = Member; ///< the member's value type.
38};
40/**
41 * Build one key->member mapping.
42 * @tparam Class the struct type owning the member.
43 * @tparam Member the member's value type.
44 * @param name the JSON object key.
45 * @param ptr pointer to the target data member.
46 * @return the Field mapping.
47 * @complexity O(1) — constexpr aggregate construction.
48 * @alloc none.
49 * @test CheatahParsers.SchemaFactoriesAtRuntime
50 */
51template <class Class, class Member>
52constexpr Field<Class, Member> field(std::string_view name, Member Class::*ptr) noexcept {
53 return Field<Class, Member>{name, ptr};
56/**
57 * @brief A struct's schema: an ordered list of Fields. Declaration order is cosmetic — at parse
58 * time each JSON key is matched to a field BY NAME, so the JSON's key order does not matter.
59 * @tparam Fields the Field types making up the schema.
60 */
61template <class... Fields>
62struct ObjectSchema {
63 std::tuple<Fields...> fields; ///< the field mappings, held as a tuple.
64};
66/**
67 * Bundle fields into a schema.
68 * @tparam Fields the Field types making up the schema.
69 * @param fs the field mappings, in declaration order (cosmetic — matching is by name).
70 * @return the ObjectSchema.
71 * @complexity O(1) — constexpr tuple construction.
72 * @alloc none.
73 * @test CheatahParsers.SchemaFactoriesAtRuntime
74 */
75template <class... Fields>
76constexpr ObjectSchema<Fields...> object(Fields... fs) noexcept {
77 return ObjectSchema<Fields...>{std::tuple<Fields...>{fs...}};
80// Sentinel type for "this T has no schema". The primary template yields it; a user gives T a schema
81// by specializing: `template<> inline constexpr auto schema<Foo> = object(...);`.
82struct no_schema {};
83template <class T>
84inline constexpr no_schema schema{};
86// True iff T has a user-declared schema specialization (so read<>() treats it as a JSON object).
87template <class T>
88concept HasSchema = !std::is_same_v<std::remove_cvref_t<decltype(schema<T>)>, no_schema>;
90} // namespace cheatah::parsers::json