cxxmcp 1.1.6
C++ MCP SDK
Loading...
Searching...
No Matches
reflect.hpp File Reference

C++17 tuple-reflection infrastructure for zero-boilerplate DTO serialization. More...

#include <cstdint>
#include <map>
#include <optional>
#include <string>
#include <string_view>
#include <tuple>
#include <type_traits>
#include <variant>
#include <vector>
#include "cxxmcp/core/result.hpp"
#include "cxxmcp/protocol/types.hpp"

Go to the source code of this file.

Classes

struct  mcp::protocol::FieldDescriptor< Struct, Field >
 Describes a single DTO field: its JSON wire name, pointer-to-member, and optional post-deserialization validator. More...
 
struct  mcp::protocol::ExtensionsField< Struct >
 Tag-only field descriptor for the extensions member. More...
 
struct  mcp::protocol::DeserializeOnlyField< Struct, Field >
 Tag-only field descriptor for fields that are populated during deserialization only (e.g. More...
 
struct  mcp::protocol::is_optional< T >
 Detects std::optional<T>. More...
 
struct  mcp::protocol::is_optional< std::optional< T > >
 
struct  mcp::protocol::is_nullable_variant< T >
 Detects std::variant containing std::monostate (nullable on wire). More...
 
struct  mcp::protocol::is_nullable_variant< std::variant< Ts... > >
 
struct  mcp::protocol::has_extensions_member< T, typename >
 Detects whether a type has an extensions member of type Json. More...
 
struct  mcp::protocol::has_extensions_member< T, std::void_t< decltype(std::declval< T >().extensions)> >
 
struct  mcp::protocol::detail::has_known_keys< T, typename >
 
struct  mcp::protocol::detail::has_known_keys< T, std::void_t< decltype(T::known_keys())> >
 
struct  mcp::protocol::Reflect< T >
 Primary template. More...
 
struct  mcp::protocol::has_reflect< T, typename >
 Detects whether Reflect<T> is specialized for a given type. More...
 
struct  mcp::protocol::has_reflect< T, std::void_t< decltype(Reflect< T >::defined)> >
 
struct  mcp::protocol::JsonFieldTraits< T, Enable >
 Type-specific serialization and deserialization logic. More...
 
struct  mcp::protocol::JsonFieldTraits< T, std::enable_if_t< has_reflect_v< T > > >
 Generic support for nested DTOs that opt into Reflect<T>. More...
 
struct  mcp::protocol::JsonFieldTraits< std::string >
 
struct  mcp::protocol::JsonFieldTraits< Json >
 
struct  mcp::protocol::JsonFieldTraits< IconTheme >
 
struct  mcp::protocol::JsonFieldTraits< std::optional< T > >
 
struct  mcp::protocol::JsonFieldTraits< std::optional< Json > >
 
struct  mcp::protocol::JsonFieldTraits< std::vector< T > >
 
struct  mcp::protocol::JsonFieldTraits< std::vector< std::string > >
 
struct  mcp::protocol::JsonFieldTraits< std::map< std::string, std::string > >
 
struct  mcp::protocol::JsonFieldTraits< std::variant< std::monostate, std::int64_t > >
 
struct  mcp::protocol::JsonFieldTraits< std::variant< std::int64_t, std::string > >
 

Namespaces

namespace  mcp::protocol::detail
 Auto-generates JSON Schema from a Reflect<T> specialization.
 

Macros

#define CXXMCP_REFL_IMPL_1(T, f1)
 
#define CXXMCP_REFL_IMPL_2(T, f1, f2)
 
#define CXXMCP_REFL_IMPL_3(T, f1, f2, f3)
 
#define CXXMCP_REFL_IMPL_4(T, f1, f2, f3, f4)
 
#define CXXMCP_REFL_IMPL_5(T, f1, f2, f3, f4, f5)
 
#define CXXMCP_REFL_IMPL_6(T, f1, f2, f3, f4, f5, f6)
 
#define CXXMCP_REFL_IMPL_7(T, f1, f2, f3, f4, f5, f6, f7)
 
#define CXXMCP_REFL_IMPL_8(T, f1, f2, f3, f4, f5, f6, f7, f8)
 
#define CXXMCP_REFL_IMPL_9(T, f1, f2, f3, f4, f5, f6, f7, f8, f9)
 
#define CXXMCP_REFL_IMPL_10(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10)
 
#define CXXMCP_REFL_IMPL_11(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11)
 
#define CXXMCP_REFL_IMPL_12(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12)
 
#define CXXMCP_REFL_IMPL_13(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13)
 
#define CXXMCP_REFL_IMPL_14(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14)
 
#define CXXMCP_REFL_IMPL_15(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15)
 
#define CXXMCP_REFL_IMPL_16(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, f12, f13, f14, f15, f16)
 
#define CXXMCP_REFLECT_CHOOSER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, _12, _13, _14, _15, _16, NAME, ...)    NAME
 
#define CXXMCP_REFLECT_EXPAND(expr)   expr
 
#define CXXMCP_REFLECT(Type, ...)
 One-line Reflect<T> specialization.
 
#define CXXMCP_REFLECT_CHECK(Struct, expected_count)
 Validates that a Reflect<> specialization covers the expected number of fields.
 

Functions

template<typename Struct , typename Field >
constexpr FieldDescriptor< Struct, Field > mcp::protocol::field (const char *wire_name, Field Struct::*pointer)
 Creates a FieldDescriptor with wire name and pointer-to-member.
 
template<typename Struct , typename Field >
constexpr FieldDescriptor< Struct, Field > mcp::protocol::validated_field (const char *wire_name, Field Struct::*pointer, core::Result< core::Unit >(*validator)(const Field &))
 Creates a FieldDescriptor with a post-deserialization validator.
 
template<typename Struct >
ExtensionsField< Struct > mcp::protocol::extensions_field (Json Struct::*pointer, std::vector< std::string > own_keys)
 Creates an ExtensionsField descriptor.
 
template<typename Struct , typename Field >
constexpr DeserializeOnlyField< Struct, Field > mcp::protocol::deserialize_only (const char *wire_name, Field Struct::*pointer)
 Creates a DeserializeOnlyField descriptor.
 
template<typename Struct , typename Field >
constexpr FieldDescriptor< Struct, Field > mcp::protocol::nullable_field (const char *wire_name, Field Struct::*pointer)
 Creates a FieldDescriptor whose missing wire value maps to std::monostate.
 
template<typename Struct , typename Field >
constexpr FieldDescriptor< Struct, Field > mcp::protocol::defaulted_field (const char *wire_name, Field Struct::*pointer)
 Creates a FieldDescriptor whose missing wire value keeps the C++ default value.
 
template<typename S , typename F >
void mcp::protocol::detail::push_wire_name (std::vector< std::string > &keys, const FieldDescriptor< S, F > &fd)
 Overloads that extract wire_name from field descriptors.
 
template<typename S , typename F >
void mcp::protocol::detail::push_wire_name (std::vector< std::string > &keys, const DeserializeOnlyField< S, F > &fd)
 
template<typename S >
void mcp::protocol::detail::push_wire_name (std::vector< std::string > &, const ExtensionsField< S > &)
 
template<typename T >
std::vector< std::string > mcp::protocol::extract_known_keys ()
 Extracts known wire names from the fields() tuple at runtime.
 
template<typename T >
Json mcp::protocol::reflect_to_json (const T &obj)
 Serializes a DTO to JSON using its Reflect<T> trait.
 
template<typename T >
core::Result< T > mcp::protocol::reflect_from_json (const Json &json)
 Deserializes a DTO from JSON using its Reflect<T> trait.
 
template<typename Struct , typename Field >
void mcp::protocol::serialize_one (Json &json, const Struct &obj, const FieldDescriptor< Struct, Field > &fd)
 Serializes a single field into the JSON object.
 
template<typename Struct , typename Field >
void mcp::protocol::serialize_one (Json &, const Struct &, const DeserializeOnlyField< Struct, Field > &)
 No-op for deserialize-only fields during serialization.
 
template<typename Struct >
void mcp::protocol::serialize_one (Json &json, const Struct &obj, const ExtensionsField< Struct > &fd)
 Merges extension members into the parent JSON object.
 
template<typename Struct , typename Field >
bool mcp::protocol::deserialize_one (const Json &json, Struct &obj, const FieldDescriptor< Struct, Field > &fd, core::Result< core::Unit > &status)
 Deserializes a single field from the JSON object.
 
template<typename Struct >
bool mcp::protocol::deserialize_one (const Json &, Struct &, const ExtensionsField< Struct > &, core::Result< core::Unit > &)
 No-op for extensions fields during deserialization.
 
template<typename Struct , typename Field >
bool mcp::protocol::deserialize_one (const Json &json, Struct &obj, const DeserializeOnlyField< Struct, Field > &fd, core::Result< core::Unit > &status)
 Deserializes a deserialize-only field.
 

Variables

template<typename T >
constexpr bool mcp::protocol::is_optional_v = is_optional<T>::value
 
template<typename T >
constexpr bool mcp::protocol::is_nullable_variant_v = is_nullable_variant<T>::value
 
template<typename T >
constexpr bool mcp::protocol::has_extensions_member_v = has_extensions_member<T>::value
 
template<typename T >
constexpr bool mcp::protocol::has_reflect_v = has_reflect<T>::value
 

Detailed Description

C++17 tuple-reflection infrastructure for zero-boilerplate DTO serialization.

Each DTO that opts into reflection provides a Reflect<T> specialization with fields() returning a tuple of FieldDescriptor. The generic reflect_to_json() and reflect_from_json<T>() functions then handle serialization automatically. known_keys() is optional; when absent, wire names are extracted from the fields() tuple at runtime.

Type-specific logic is dispatched through JsonFieldTraits<T> partial specializations for optional, vector, string, enum, variant, and nested-DTO types.

Macro Definition Documentation

◆ CXXMCP_REFL_IMPL_1

#define CXXMCP_REFL_IMPL_1 (   T,
  f1 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { return std::make_tuple(field(#f1, &T::f1)); } \
};
Primary template.
Definition reflect.hpp:199

◆ CXXMCP_REFL_IMPL_10

#define CXXMCP_REFL_IMPL_10 (   T,
  f1,
  f2,
  f3,
  f4,
  f5,
  f6,
  f7,
  f8,
  f9,
  f10 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
field(#f3, &T::f3), field(#f4, &T::f4), \
field(#f5, &T::f5), field(#f6, &T::f6), \
field(#f7, &T::f7), field(#f8, &T::f8), \
field(#f9, &T::f9), field(#f10, &T::f10)); \
} \
};

◆ CXXMCP_REFL_IMPL_11

#define CXXMCP_REFL_IMPL_11 (   T,
  f1,
  f2,
  f3,
  f4,
  f5,
  f6,
  f7,
  f8,
  f9,
  f10,
  f11 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple( \
field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
field(#f10, &T::f10), field(#f11, &T::f11)); \
} \
};

◆ CXXMCP_REFL_IMPL_12

#define CXXMCP_REFL_IMPL_12 (   T,
  f1,
  f2,
  f3,
  f4,
  f5,
  f6,
  f7,
  f8,
  f9,
  f10,
  f11,
  f12 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple( \
field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12)); \
} \
};

◆ CXXMCP_REFL_IMPL_13

#define CXXMCP_REFL_IMPL_13 (   T,
  f1,
  f2,
  f3,
  f4,
  f5,
  f6,
  f7,
  f8,
  f9,
  f10,
  f11,
  f12,
  f13 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple( \
field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12), \
field(#f13, &T::f13)); \
} \
};

◆ CXXMCP_REFL_IMPL_14

#define CXXMCP_REFL_IMPL_14 (   T,
  f1,
  f2,
  f3,
  f4,
  f5,
  f6,
  f7,
  f8,
  f9,
  f10,
  f11,
  f12,
  f13,
  f14 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple( \
field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12), \
field(#f13, &T::f13), field(#f14, &T::f14)); \
} \
};

◆ CXXMCP_REFL_IMPL_15

#define CXXMCP_REFL_IMPL_15 (   T,
  f1,
  f2,
  f3,
  f4,
  f5,
  f6,
  f7,
  f8,
  f9,
  f10,
  f11,
  f12,
  f13,
  f14,
  f15 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple( \
field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12), \
field(#f13, &T::f13), field(#f14, &T::f14), field(#f15, &T::f15)); \
} \
};

◆ CXXMCP_REFL_IMPL_16

#define CXXMCP_REFL_IMPL_16 (   T,
  f1,
  f2,
  f3,
  f4,
  f5,
  f6,
  f7,
  f8,
  f9,
  f10,
  f11,
  f12,
  f13,
  f14,
  f15,
  f16 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple( \
field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12), \
field(#f13, &T::f13), field(#f14, &T::f14), field(#f15, &T::f15), \
field(#f16, &T::f16)); \
} \
};

◆ CXXMCP_REFL_IMPL_2

#define CXXMCP_REFL_IMPL_2 (   T,
  f1,
  f2 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2)); \
} \
};

◆ CXXMCP_REFL_IMPL_3

#define CXXMCP_REFL_IMPL_3 (   T,
  f1,
  f2,
  f3 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
field(#f3, &T::f3)); \
} \
};

◆ CXXMCP_REFL_IMPL_4

#define CXXMCP_REFL_IMPL_4 (   T,
  f1,
  f2,
  f3,
  f4 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
field(#f3, &T::f3), field(#f4, &T::f4)); \
} \
};

◆ CXXMCP_REFL_IMPL_5

#define CXXMCP_REFL_IMPL_5 (   T,
  f1,
  f2,
  f3,
  f4,
  f5 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
field(#f3, &T::f3), field(#f4, &T::f4), \
field(#f5, &T::f5)); \
} \
};

◆ CXXMCP_REFL_IMPL_6

#define CXXMCP_REFL_IMPL_6 (   T,
  f1,
  f2,
  f3,
  f4,
  f5,
  f6 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
field(#f3, &T::f3), field(#f4, &T::f4), \
field(#f5, &T::f5), field(#f6, &T::f6)); \
} \
};

◆ CXXMCP_REFL_IMPL_7

#define CXXMCP_REFL_IMPL_7 (   T,
  f1,
  f2,
  f3,
  f4,
  f5,
  f6,
  f7 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
field(#f3, &T::f3), field(#f4, &T::f4), \
field(#f5, &T::f5), field(#f6, &T::f6), \
field(#f7, &T::f7)); \
} \
};

◆ CXXMCP_REFL_IMPL_8

#define CXXMCP_REFL_IMPL_8 (   T,
  f1,
  f2,
  f3,
  f4,
  f5,
  f6,
  f7,
  f8 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
field(#f3, &T::f3), field(#f4, &T::f4), \
field(#f5, &T::f5), field(#f6, &T::f6), \
field(#f7, &T::f7), field(#f8, &T::f8)); \
} \
};

◆ CXXMCP_REFL_IMPL_9

#define CXXMCP_REFL_IMPL_9 (   T,
  f1,
  f2,
  f3,
  f4,
  f5,
  f6,
  f7,
  f8,
  f9 
)
Value:
template <> \
struct mcp::protocol::Reflect<T> { \
static constexpr bool defined = true; \
static auto fields() { \
return std::make_tuple( \
field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9)); \
} \
};

◆ CXXMCP_REFLECT

#define CXXMCP_REFLECT (   Type,
  ... 
)
Value:
using ::mcp::protocol::Reflect; \
using ::mcp::protocol::field; \
CXXMCP_REFLECT_EXPAND(CXXMCP_REFLECT_CHOOSER( \
__VA_ARGS__, CXXMCP_REFL_IMPL_16, CXXMCP_REFL_IMPL_15, \
CXXMCP_REFL_IMPL_14, CXXMCP_REFL_IMPL_13, CXXMCP_REFL_IMPL_12, \
CXXMCP_REFL_IMPL_11, CXXMCP_REFL_IMPL_10, CXXMCP_REFL_IMPL_9, \
CXXMCP_REFL_IMPL_8, CXXMCP_REFL_IMPL_7, CXXMCP_REFL_IMPL_6, \
CXXMCP_REFL_IMPL_5, CXXMCP_REFL_IMPL_4, CXXMCP_REFL_IMPL_3, \
CXXMCP_REFL_IMPL_2, CXXMCP_REFL_IMPL_1)(Type, __VA_ARGS__))

One-line Reflect<T> specialization.

Usage (at namespace scope, usually in the global namespace):

CXXMCP_REFLECT(MyStruct, field1, field2, field3)
#define CXXMCP_REFLECT(Type,...)
One-line Reflect<T> specialization.
Definition reflect.hpp:979

Supports 1 to 16 fields. For more, use a manual Reflect<> specialization.

◆ CXXMCP_REFLECT_CHECK

#define CXXMCP_REFLECT_CHECK (   Struct,
  expected_count 
)
Value:
static_assert( \
std::tuple_size_v< \
(expected_count), \
"Reflect<" #Struct \
">::fields() has " \
"a different number of descriptors than expected (" #expected_count \
"). Update the count or add/remove field descriptors.")

Validates that a Reflect<> specialization covers the expected number of fields.

Place this macro immediately after the Reflect<> specialization to catch field count mismatches at compile time. Example:

template <>
struct Reflect<MyStruct> { ... };
CXXMCP_REFLECT_CHECK(MyStruct, 5);
#define CXXMCP_REFLECT_CHECK(Struct, expected_count)
Validates that a Reflect<> specialization covers the expected number of fields.
Definition reflect.hpp:1008

The second argument must equal the number of field() + extensions_field() descriptors in the specialization. A mismatch produces a compile error.

Function Documentation

◆ deserialize_one()

template<typename Struct , typename Field >
bool mcp::protocol::deserialize_one ( const Json json,
Struct &  obj,
const FieldDescriptor< Struct, Field > &  fd,
core::Result< core::Unit > &  status 
)

Deserializes a single field from the JSON object.

Returns true on success (including "optional field absent"). Returns false only on a type mismatch or validation failure.

◆ extract_known_keys()

template<typename T >
std::vector< std::string > mcp::protocol::extract_known_keys ( )

Extracts known wire names from the fields() tuple at runtime.

This is the fallback used when Reflect<T> does not define known_keys().

◆ nullable_field()

template<typename Struct , typename Field >
constexpr FieldDescriptor< Struct, Field > mcp::protocol::nullable_field ( const char *  wire_name,
Field Struct::*  pointer 
)
constexpr

Creates a FieldDescriptor whose missing wire value maps to std::monostate.

Use this only for protocol fields where an absent member and an explicit JSON null have the same semantics. Normal variants remain required unless they use this descriptor.

◆ reflect_from_json()

template<typename T >
core::Result< T > mcp::protocol::reflect_from_json ( const Json json)

Deserializes a DTO from JSON using its Reflect<T> trait.

Validates required fields, parses types, runs post-validation hooks, and collects unknown JSON keys into the extensions member.

◆ reflect_to_json()

template<typename T >
Json mcp::protocol::reflect_to_json ( const T &  obj)

Serializes a DTO to JSON using its Reflect<T> trait.

Iterates all fields via fold expression, then merges extension members.