cxxmcp 1.1.6
C++ MCP SDK
Loading...
Searching...
No Matches
reflect.hpp
Go to the documentation of this file.
1// Copyright (c) 2025 [caomengxuan666]
2
3#pragma once
4
18
19#include <cstdint>
20#include <map>
21#include <optional>
22#include <string>
23#include <string_view>
24#include <tuple>
25#include <type_traits>
26#include <variant>
27#include <vector>
28
31
32namespace mcp::protocol {
33
34// ---------------------------------------------------------------------------
35// Field descriptor
36// ---------------------------------------------------------------------------
37
40template <typename Struct, typename Field>
42 const char* wire_name;
43 Field Struct::* pointer;
44 using field_type = Field;
45 using struct_type = Struct;
46 core::Result<core::Unit> (*post_validate)(const Field&) = nullptr;
47 bool absent_as_monostate = false;
48 bool absent_as_default = false;
49};
50
55template <typename Struct>
57 Json Struct::* pointer;
58 std::vector<std::string> own_keys;
59 using field_type = Json;
60 using struct_type = Struct;
61};
62
65template <typename Struct, typename Field>
67 const char* wire_name;
68 Field Struct::* pointer;
69 using field_type = Field;
70 using struct_type = Struct;
71};
72
74template <typename Struct, typename Field>
75constexpr FieldDescriptor<Struct, Field> field(const char* wire_name,
76 Field Struct::* pointer) {
77 return {wire_name, pointer, nullptr};
78}
79
81template <typename Struct, typename Field>
83 const char* wire_name, Field Struct::* pointer,
84 core::Result<core::Unit> (*validator)(const Field&)) {
85 return {wire_name, pointer, validator};
86}
87
89template <typename Struct>
91 std::vector<std::string> own_keys) {
92 return {pointer, std::move(own_keys)};
93}
94
96template <typename Struct, typename Field>
98 const char* wire_name, Field Struct::* pointer) {
99 return {wire_name, pointer};
100}
101
102// ---------------------------------------------------------------------------
103// Utility type traits
104// ---------------------------------------------------------------------------
105
107template <typename T>
108struct is_optional : std::false_type {};
109
110template <typename T>
111struct is_optional<std::optional<T>> : std::true_type {};
112
113template <typename T>
114inline constexpr bool is_optional_v = is_optional<T>::value;
115
117template <typename T>
118struct is_nullable_variant : std::false_type {};
119
120template <typename... Ts>
121struct is_nullable_variant<std::variant<Ts...>>
122 : std::disjunction<std::is_same<Ts, std::monostate>...> {};
123
124template <typename T>
125inline constexpr bool is_nullable_variant_v = is_nullable_variant<T>::value;
126
133template <typename Struct, typename Field>
135 const char* wire_name, Field Struct::* pointer) {
136 static_assert(is_nullable_variant_v<Field>,
137 "nullable_field requires a std::variant containing "
138 "std::monostate");
139 return {wire_name, pointer, nullptr, true};
140}
141
144template <typename Struct, typename Field>
146 const char* wire_name, Field Struct::* pointer) {
147 return {wire_name, pointer, nullptr, false, true};
148}
149
151template <typename T, typename = void>
152struct has_extensions_member : std::false_type {};
153
154template <typename T>
156 T, std::void_t<decltype(std::declval<T>().extensions)>>
157 : std::bool_constant<
158 std::is_same_v<decltype(std::declval<T>().extensions), Json>> {};
159
160template <typename T>
161inline constexpr bool has_extensions_member_v = has_extensions_member<T>::value;
162
163// ---------------------------------------------------------------------------
164// SFINAE: detect optional known_keys() on Reflect<T>
165// ---------------------------------------------------------------------------
166
167namespace detail {
168template <typename T, typename = void>
169struct has_known_keys : std::false_type {};
170
171template <typename T>
172struct has_known_keys<T, std::void_t<decltype(T::known_keys())>>
173 : std::true_type {};
174
177template <typename S, typename F>
178void push_wire_name(std::vector<std::string>& keys,
179 const FieldDescriptor<S, F>& fd) {
180 keys.push_back(fd.wire_name);
181}
182template <typename S, typename F>
183void push_wire_name(std::vector<std::string>& keys,
184 const DeserializeOnlyField<S, F>& fd) {
185 keys.push_back(fd.wire_name);
186}
187template <typename S>
188void push_wire_name(std::vector<std::string>&, const ExtensionsField<S>&) {}
189} // namespace detail
190
191// ---------------------------------------------------------------------------
192// Primary Reflect template (unspecialized types are not reflectable)
193// ---------------------------------------------------------------------------
194
198template <typename T>
199struct Reflect {
200 static constexpr bool defined = false;
201};
202
206template <typename T>
207std::vector<std::string> extract_known_keys() {
208 std::vector<std::string> keys;
209 std::apply(
210 [&keys](const auto&... fds) { (detail::push_wire_name(keys, fds), ...); },
212 return keys;
213}
214
215// ---------------------------------------------------------------------------
216// Type trait: detect whether a type has a Reflect specialization
217// ---------------------------------------------------------------------------
218
220template <typename T, typename = void>
221struct has_reflect : std::false_type {};
222
223template <typename T>
224struct has_reflect<T, std::void_t<decltype(Reflect<T>::defined)>>
225 : std::bool_constant<Reflect<T>::defined> {};
226
227template <typename T>
228inline constexpr bool has_reflect_v = has_reflect<T>::value;
229
230// Forward declarations for reflect_to_json / reflect_from_json.
231template <typename T>
232Json reflect_to_json(const T& obj);
233template <typename T>
235
236// ---------------------------------------------------------------------------
237// JsonFieldTraits: primary template for scalars (int64, double, bool)
238// ---------------------------------------------------------------------------
239
245template <typename T, typename Enable = void>
247 static void serialize(Json& json, const char* key, const T& value) {
248 json[key] = value;
249 }
250
251 static bool deserialize(const Json& json, const char* key, T& target) {
252 if (!json.contains(key)) {
253 return false;
254 }
255 const auto& val = json.at(key);
256 if constexpr (std::is_same_v<T, bool>) {
257 if (!val.is_boolean()) {
258 return false;
259 }
260 } else if constexpr (std::is_floating_point_v<T>) {
261 if (!val.is_number()) {
262 return false;
263 }
264 } else if constexpr (std::is_integral_v<T>) {
265 if (!val.is_number_integer()) {
266 return false;
267 }
268 }
269 target = val.get<T>();
270 return true;
271 }
272};
273
275template <typename T>
276struct JsonFieldTraits<T, std::enable_if_t<has_reflect_v<T>>> {
277 static void serialize(Json& json, const char* key, const T& value) {
278 json[key] = reflect_to_json(value);
279 }
280
281 static bool deserialize(const Json& json, const char* key, T& target) {
282 if (!json.contains(key)) {
283 return false;
284 }
285 auto value = reflect_from_json<T>(json.at(key));
286 if (!value) {
287 return false;
288 }
289 target = std::move(*value);
290 return true;
291 }
292};
293
294// ---------------------------------------------------------------------------
295// Traits for std::string (omit empty on serialize, no default on deserialize)
296// ---------------------------------------------------------------------------
297
298template <>
299struct JsonFieldTraits<std::string> {
300 static void serialize(Json& json, const char* key, const std::string& value) {
301 json[key] = value;
302 }
303
304 static bool deserialize(const Json& json, const char* key,
305 std::string& target) {
306 if (!json.contains(key)) {
307 return false;
308 }
309 if (!json.at(key).is_string()) {
310 return false;
311 }
312 target = json.at(key).get<std::string>();
313 return true;
314 }
315};
316
317// ---------------------------------------------------------------------------
318// Traits for Json (raw JSON passthrough)
319// ---------------------------------------------------------------------------
320
321template <>
323 static void serialize(Json& json, const char* key, const Json& value) {
324 if (!value.is_null() && !value.empty()) {
325 json[key] = value;
326 }
327 }
328
329 static bool deserialize(const Json& json, const char* key, Json& target) {
330 if (!json.contains(key)) {
331 return false;
332 }
333 target = json.at(key);
334 return true;
335 }
336};
337
338template <>
340 static void serialize(Json& json, const char* key, IconTheme value) {
341 json[key] = std::string(icon_theme_to_string(value));
342 }
343
344 static bool deserialize(const Json& json, const char* key,
345 IconTheme& target) {
346 if (!json.contains(key) || !json.at(key).is_string()) {
347 return false;
348 }
349 auto value = icon_theme_from_string(json.at(key).get<std::string>());
350 if (!value.has_value()) {
351 return false;
352 }
353 target = *value;
354 return true;
355 }
356};
357
358// ---------------------------------------------------------------------------
359// Note: JsonFieldTraits<Icon> and JsonFieldTraits<std::vector<Icon>> are no
360// longer needed. Icon uses Reflect<Icon> (in types_reflect.hpp) via the
361// generic vector<T> trait and reflect_to_json/reflect_from_json.
362// ---------------------------------------------------------------------------
363
364// ---------------------------------------------------------------------------
365// Traits for std::optional<T>
366// ---------------------------------------------------------------------------
367
368template <typename T>
369struct JsonFieldTraits<std::optional<T>> {
370 static void serialize(Json& json, const char* key,
371 const std::optional<T>& value) {
372 if (value.has_value()) {
373 JsonFieldTraits<T>::serialize(json, key, *value);
374 }
375 }
376
377 static bool deserialize(const Json& json, const char* key,
378 std::optional<T>& target) {
379 if (!json.contains(key)) {
380 return true; // optional: missing is OK
381 }
382 T inner{};
383 if (!JsonFieldTraits<T>::deserialize(json, key, inner)) {
384 return false;
385 }
386 target = std::move(inner);
387 return true;
388 }
389};
390
391// ---------------------------------------------------------------------------
392// Traits for std::optional<Json> (e.g. `_meta`)
393// ---------------------------------------------------------------------------
394
395template <>
396struct JsonFieldTraits<std::optional<Json>> {
397 static void serialize(Json& json, const char* key,
398 const std::optional<Json>& value) {
399 if (value.has_value() && !value->is_null()) {
400 json[key] = *value;
401 }
402 }
403
404 static bool deserialize(const Json& json, const char* key,
405 std::optional<Json>& target) {
406 if (!json.contains(key)) {
407 return true;
408 }
409 target = json.at(key);
410 return true;
411 }
412};
413
414// ---------------------------------------------------------------------------
415// Traits for std::vector<T> (omit empty, recurse elements)
416// ---------------------------------------------------------------------------
417
418template <typename T>
419struct JsonFieldTraits<std::vector<T>> {
420 static void serialize(Json& json, const char* key,
421 const std::vector<T>& value) {
422 if (value.empty()) {
423 return;
424 }
425 json[key] = Json::array();
426 for (const auto& item : value) {
427 Json element = Json::object();
428 JsonFieldTraits<T>::serialize(element, "_item", item);
429 json[key].push_back(std::move(element["_item"]));
430 }
431 }
432
433 static bool deserialize(const Json& json, const char* key,
434 std::vector<T>& target) {
435 if (!json.contains(key)) {
436 return true; // missing vector = empty
437 }
438 if (!json.at(key).is_array()) {
439 return false;
440 }
441 target.clear();
442 target.reserve(json.at(key).size());
443 for (const auto& item : json.at(key)) {
444 T element{};
445 // For nested DTOs, pass the item directly
446 if constexpr (has_reflect_v<T>) {
447 auto result = reflect_from_json<T>(item);
448 if (!result) {
449 return false;
450 }
451 target.push_back(std::move(*result));
452 } else {
453 // For scalars, extract directly
454 element = item.get<T>();
455 target.push_back(std::move(element));
456 }
457 }
458 return true;
459 }
460};
461
462// ---------------------------------------------------------------------------
463// Traits for std::vector<std::string>
464// ---------------------------------------------------------------------------
465
466template <>
467struct JsonFieldTraits<std::vector<std::string>> {
468 static void serialize(Json& json, const char* key,
469 const std::vector<std::string>& value) {
470 if (value.empty()) {
471 return;
472 }
473 json[key] = value;
474 }
475
476 static bool deserialize(const Json& json, const char* key,
477 std::vector<std::string>& target) {
478 if (!json.contains(key)) {
479 return true;
480 }
481 if (!json.at(key).is_array()) {
482 return false;
483 }
484 target.reserve(json.at(key).size());
485 for (const auto& item : json.at(key)) {
486 if (!item.is_string()) {
487 return false;
488 }
489 target.push_back(item.get<std::string>());
490 }
491 return true;
492 }
493};
494
495// ---------------------------------------------------------------------------
496// Traits for std::map<std::string, std::string> (string-to-string maps)
497// ---------------------------------------------------------------------------
498
499template <>
500struct JsonFieldTraits<std::map<std::string, std::string>> {
501 static void serialize(Json& json, const char* key,
502 const std::map<std::string, std::string>& value) {
503 if (value.empty()) {
504 return;
505 }
506 json[key] = Json::object();
507 for (const auto& [k, v] : value) {
508 json[key][k] = v;
509 }
510 }
511
512 static bool deserialize(const Json& json, const char* key,
513 std::map<std::string, std::string>& target) {
514 if (!json.contains(key)) {
515 return true; // missing map = empty
516 }
517 if (!json.at(key).is_object()) {
518 return false;
519 }
520 target.clear();
521 for (const auto& [k, v] : json.at(key).items()) {
522 if (!v.is_string()) {
523 return false;
524 }
525 target[k] = v.get<std::string>();
526 }
527 return true;
528 }
529};
530
531// ---------------------------------------------------------------------------
532// Traits for std::variant<std::monostate, std::int64_t> (nullable int)
533// ---------------------------------------------------------------------------
534
535template <>
536struct JsonFieldTraits<std::variant<std::monostate, std::int64_t>> {
537 static void serialize(Json& json, const char* key,
538 const std::variant<std::monostate, std::int64_t>& val) {
539 if (std::holds_alternative<std::int64_t>(val)) {
540 json[key] = std::get<std::int64_t>(val);
541 } else {
542 json[key] = nullptr;
543 }
544 }
545
546 static bool deserialize(const Json& json, const char* key,
547 std::variant<std::monostate, std::int64_t>& target) {
548 if (!json.contains(key)) {
549 target = std::monostate{};
550 return true;
551 }
552 if (json.at(key).is_null()) {
553 target = std::monostate{};
554 return true;
555 }
556 if (json.at(key).is_number_integer()) {
557 target = json.at(key).get<std::int64_t>();
558 return true;
559 }
560 return false;
561 }
562};
563
564// ---------------------------------------------------------------------------
565// Traits for std::variant<int64_t, std::string> (RequestId / ProgressToken)
566// ---------------------------------------------------------------------------
567
568template <>
569struct JsonFieldTraits<std::variant<std::int64_t, std::string>> {
570 static void serialize(Json& json, const char* key,
571 const std::variant<std::int64_t, std::string>& val) {
572 json[key] = std::visit([](const auto& v) { return Json(v); }, val);
573 }
574
575 static bool deserialize(const Json& json, const char* key,
576 std::variant<std::int64_t, std::string>& target) {
577 if (!json.contains(key)) {
578 return false;
579 }
580 const auto& val = json.at(key);
581 if (val.is_number_integer()) {
582 target = val.get<std::int64_t>();
583 return true;
584 }
585 if (val.is_string()) {
586 target = val.get<std::string>();
587 return true;
588 }
589 return false;
590 }
591};
592
593// ---------------------------------------------------------------------------
594// Generic fold-expression helpers for serialize/deserialize one field
595// ---------------------------------------------------------------------------
596
598template <typename Struct, typename Field>
599void serialize_one(Json& json, const Struct& obj,
601 JsonFieldTraits<Field>::serialize(json, fd.wire_name, obj.*(fd.pointer));
602}
603
605template <typename Struct, typename Field>
606void serialize_one(Json&, const Struct&,
608
610template <typename Struct>
611void serialize_one(Json& json, const Struct& obj,
612 const ExtensionsField<Struct>& fd) {
613 append_json_extensions(json, obj.*(fd.pointer));
614}
615
620template <typename Struct, typename Field>
621bool deserialize_one(const Json& json, Struct& obj,
623 core::Result<core::Unit>& status) {
624 const bool present = json.contains(fd.wire_name);
625 if (!present) {
626 if (fd.absent_as_default) {
627 obj.*(fd.pointer) = Field{};
628 status = core::Unit{};
629 return true;
630 }
631 // For optional types, absent is fine. Nullable variants must opt in
632 // explicitly with nullable_field(); otherwise they are required fields.
633 if constexpr (is_optional_v<Field>) {
634 return true;
635 }
636 if constexpr (is_nullable_variant_v<Field>) {
637 if (fd.absent_as_monostate) {
638 obj.*(fd.pointer) = Field{std::monostate{}};
639 status = core::Unit{};
640 return true;
641 }
642 }
643 status = mcp::core::unexpected(core::Error{
644 static_cast<int>(ErrorCode::InvalidRequest),
645 "missing required field '" + std::string(fd.wire_name) + "'",
646 {}});
647 return false;
648 }
649 Field temp{};
650 if (!JsonFieldTraits<Field>::deserialize(json, fd.wire_name, temp)) {
651 status = mcp::core::unexpected(
652 core::Error{static_cast<int>(ErrorCode::InvalidRequest),
653 "invalid field '" + std::string(fd.wire_name) + "'",
654 {}});
655 return false;
656 }
657 if (fd.post_validate) {
658 auto validation = fd.post_validate(temp);
659 if (!validation) {
660 status = mcp::core::unexpected(validation.error());
661 return false;
662 }
663 }
664 obj.*(fd.pointer) = std::move(temp);
665 status = core::Unit{};
666 return true;
667}
668
670template <typename Struct>
671bool deserialize_one(const Json&, Struct&, const ExtensionsField<Struct>&,
673 return true;
674}
675
677template <typename Struct, typename Field>
678bool deserialize_one(const Json& json, Struct& obj,
680 core::Result<core::Unit>& status) {
681 if constexpr (is_optional_v<Field>) {
682 JsonFieldTraits<Field>::deserialize(json, fd.wire_name, obj.*(fd.pointer));
683 status = core::Unit{};
684 return true;
685 } else {
686 return deserialize_one(
687 json, obj,
688 FieldDescriptor<Struct, Field>{fd.wire_name, fd.pointer, nullptr},
689 status);
690 }
691}
692
693// ---------------------------------------------------------------------------
694// reflect_to_json / reflect_from_json
695// ---------------------------------------------------------------------------
696
700template <typename T>
701Json reflect_to_json(const T& obj) {
702 static_assert(has_reflect_v<T>,
703 "Reflect<T> must be specialized for this type");
704 Json json = Json::object();
705
706 // Serialize each field.
707 std::apply([&](const auto&... fds) { (serialize_one(json, obj, fds), ...); },
709
710 // Merge extension members last (they fill gaps left by typed fields).
711 if constexpr (has_extensions_member_v<T>) {
712 append_json_extensions(json, obj.extensions);
713 }
714 return json;
715}
716
721template <typename T>
723 static_assert(has_reflect_v<T>,
724 "Reflect<T> must be specialized for this type");
725 if (!json.is_object()) {
726 return mcp::core::unexpected(
727 core::Error{static_cast<int>(ErrorCode::InvalidRequest),
728 "expected a JSON object",
729 {}});
730 }
731
732 T obj{};
734
735 // Early-exit fold: on first error, skip remaining fields.
736 std::apply(
737 [&](const auto&... fds) {
738 auto one = [&](const auto& fd) {
739 if (status) {
740 deserialize_one(json, obj, fd, status);
741 }
742 };
743 (one(fds), ...);
744 },
746
747 if (!status) {
748 return mcp::core::unexpected(status.error());
749 }
750
751 // Collect unknown keys into extensions.
752 if constexpr (has_extensions_member_v<T>) {
753 auto known = [] {
754 if constexpr (detail::has_known_keys<Reflect<T>>::value) {
755 return Reflect<T>::known_keys();
756 } else {
757 return extract_known_keys<T>();
758 }
759 }();
760 obj.extensions = collect_json_extensions(json, known);
761 }
762
763 return obj;
764}
765
766// ---------------------------------------------------------------------------
767// CXXMCP_REFLECT: one-line Reflect<T> specialization
768// ---------------------------------------------------------------------------
769
770#define CXXMCP_REFL_IMPL_1(T, f1) \
771 template <> \
772 struct mcp::protocol::Reflect<T> { \
773 static constexpr bool defined = true; \
774 static auto fields() { return std::make_tuple(field(#f1, &T::f1)); } \
775 };
776
777#define CXXMCP_REFL_IMPL_2(T, f1, f2) \
778 template <> \
779 struct mcp::protocol::Reflect<T> { \
780 static constexpr bool defined = true; \
781 static auto fields() { \
782 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2)); \
783 } \
784 };
785
786#define CXXMCP_REFL_IMPL_3(T, f1, f2, f3) \
787 template <> \
788 struct mcp::protocol::Reflect<T> { \
789 static constexpr bool defined = true; \
790 static auto fields() { \
791 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
792 field(#f3, &T::f3)); \
793 } \
794 };
795
796#define CXXMCP_REFL_IMPL_4(T, f1, f2, f3, f4) \
797 template <> \
798 struct mcp::protocol::Reflect<T> { \
799 static constexpr bool defined = true; \
800 static auto fields() { \
801 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
802 field(#f3, &T::f3), field(#f4, &T::f4)); \
803 } \
804 };
805
806#define CXXMCP_REFL_IMPL_5(T, f1, f2, f3, f4, f5) \
807 template <> \
808 struct mcp::protocol::Reflect<T> { \
809 static constexpr bool defined = true; \
810 static auto fields() { \
811 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
812 field(#f3, &T::f3), field(#f4, &T::f4), \
813 field(#f5, &T::f5)); \
814 } \
815 };
816
817#define CXXMCP_REFL_IMPL_6(T, f1, f2, f3, f4, f5, f6) \
818 template <> \
819 struct mcp::protocol::Reflect<T> { \
820 static constexpr bool defined = true; \
821 static auto fields() { \
822 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
823 field(#f3, &T::f3), field(#f4, &T::f4), \
824 field(#f5, &T::f5), field(#f6, &T::f6)); \
825 } \
826 };
827
828#define CXXMCP_REFL_IMPL_7(T, f1, f2, f3, f4, f5, f6, f7) \
829 template <> \
830 struct mcp::protocol::Reflect<T> { \
831 static constexpr bool defined = true; \
832 static auto fields() { \
833 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
834 field(#f3, &T::f3), field(#f4, &T::f4), \
835 field(#f5, &T::f5), field(#f6, &T::f6), \
836 field(#f7, &T::f7)); \
837 } \
838 };
839
840#define CXXMCP_REFL_IMPL_8(T, f1, f2, f3, f4, f5, f6, f7, f8) \
841 template <> \
842 struct mcp::protocol::Reflect<T> { \
843 static constexpr bool defined = true; \
844 static auto fields() { \
845 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
846 field(#f3, &T::f3), field(#f4, &T::f4), \
847 field(#f5, &T::f5), field(#f6, &T::f6), \
848 field(#f7, &T::f7), field(#f8, &T::f8)); \
849 } \
850 };
851
852#define CXXMCP_REFL_IMPL_9(T, f1, f2, f3, f4, f5, f6, f7, f8, f9) \
853 template <> \
854 struct mcp::protocol::Reflect<T> { \
855 static constexpr bool defined = true; \
856 static auto fields() { \
857 return std::make_tuple( \
858 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
859 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
860 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9)); \
861 } \
862 };
863
864#define CXXMCP_REFL_IMPL_10(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10) \
865 template <> \
866 struct mcp::protocol::Reflect<T> { \
867 static constexpr bool defined = true; \
868 static auto fields() { \
869 return std::make_tuple(field(#f1, &T::f1), field(#f2, &T::f2), \
870 field(#f3, &T::f3), field(#f4, &T::f4), \
871 field(#f5, &T::f5), field(#f6, &T::f6), \
872 field(#f7, &T::f7), field(#f8, &T::f8), \
873 field(#f9, &T::f9), field(#f10, &T::f10)); \
874 } \
875 };
876
877#define CXXMCP_REFL_IMPL_11(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11) \
878 template <> \
879 struct mcp::protocol::Reflect<T> { \
880 static constexpr bool defined = true; \
881 static auto fields() { \
882 return std::make_tuple( \
883 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
884 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
885 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
886 field(#f10, &T::f10), field(#f11, &T::f11)); \
887 } \
888 };
889
890#define CXXMCP_REFL_IMPL_12(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, \
891 f12) \
892 template <> \
893 struct mcp::protocol::Reflect<T> { \
894 static constexpr bool defined = true; \
895 static auto fields() { \
896 return std::make_tuple( \
897 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
898 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
899 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
900 field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12)); \
901 } \
902 };
903
904#define CXXMCP_REFL_IMPL_13(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, \
905 f12, f13) \
906 template <> \
907 struct mcp::protocol::Reflect<T> { \
908 static constexpr bool defined = true; \
909 static auto fields() { \
910 return std::make_tuple( \
911 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
912 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
913 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
914 field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12), \
915 field(#f13, &T::f13)); \
916 } \
917 };
918
919#define CXXMCP_REFL_IMPL_14(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, \
920 f12, f13, f14) \
921 template <> \
922 struct mcp::protocol::Reflect<T> { \
923 static constexpr bool defined = true; \
924 static auto fields() { \
925 return std::make_tuple( \
926 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
927 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
928 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
929 field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12), \
930 field(#f13, &T::f13), field(#f14, &T::f14)); \
931 } \
932 };
933
934#define CXXMCP_REFL_IMPL_15(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, \
935 f12, f13, f14, f15) \
936 template <> \
937 struct mcp::protocol::Reflect<T> { \
938 static constexpr bool defined = true; \
939 static auto fields() { \
940 return std::make_tuple( \
941 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
942 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
943 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
944 field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12), \
945 field(#f13, &T::f13), field(#f14, &T::f14), field(#f15, &T::f15)); \
946 } \
947 };
948
949#define CXXMCP_REFL_IMPL_16(T, f1, f2, f3, f4, f5, f6, f7, f8, f9, f10, f11, \
950 f12, f13, f14, f15, f16) \
951 template <> \
952 struct mcp::protocol::Reflect<T> { \
953 static constexpr bool defined = true; \
954 static auto fields() { \
955 return std::make_tuple( \
956 field(#f1, &T::f1), field(#f2, &T::f2), field(#f3, &T::f3), \
957 field(#f4, &T::f4), field(#f5, &T::f5), field(#f6, &T::f6), \
958 field(#f7, &T::f7), field(#f8, &T::f8), field(#f9, &T::f9), \
959 field(#f10, &T::f10), field(#f11, &T::f11), field(#f12, &T::f12), \
960 field(#f13, &T::f13), field(#f14, &T::f14), field(#f15, &T::f15), \
961 field(#f16, &T::f16)); \
962 } \
963 };
964
965// Internal dispatch by selecting the implementation from the argument list.
966#define CXXMCP_REFLECT_CHOOSER(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10, _11, \
967 _12, _13, _14, _15, _16, NAME, ...) \
968 NAME
969#define CXXMCP_REFLECT_EXPAND(expr) expr
970
979#define CXXMCP_REFLECT(Type, ...) \
980 using ::mcp::protocol::Reflect; \
981 using ::mcp::protocol::field; \
982 CXXMCP_REFLECT_EXPAND(CXXMCP_REFLECT_CHOOSER( \
983 __VA_ARGS__, CXXMCP_REFL_IMPL_16, CXXMCP_REFL_IMPL_15, \
984 CXXMCP_REFL_IMPL_14, CXXMCP_REFL_IMPL_13, CXXMCP_REFL_IMPL_12, \
985 CXXMCP_REFL_IMPL_11, CXXMCP_REFL_IMPL_10, CXXMCP_REFL_IMPL_9, \
986 CXXMCP_REFL_IMPL_8, CXXMCP_REFL_IMPL_7, CXXMCP_REFL_IMPL_6, \
987 CXXMCP_REFL_IMPL_5, CXXMCP_REFL_IMPL_4, CXXMCP_REFL_IMPL_3, \
988 CXXMCP_REFL_IMPL_2, CXXMCP_REFL_IMPL_1)(Type, __VA_ARGS__))
989
990// ---------------------------------------------------------------------------
991// Compile-time reflection completeness check
992// ---------------------------------------------------------------------------
993
1008#define CXXMCP_REFLECT_CHECK(Struct, expected_count) \
1009 static_assert( \
1010 std::tuple_size_v< \
1011 decltype(::mcp::protocol::Reflect<Struct>::fields())> == \
1012 (expected_count), \
1013 "Reflect<" #Struct \
1014 ">::fields() has " \
1015 "a different number of descriptors than expected (" #expected_count \
1016 "). Update the count or add/remove field descriptors.")
1017
1018} // namespace mcp::protocol
void push_wire_name(std::vector< std::string > &keys, const FieldDescriptor< S, F > &fd)
Overloads that extract wire_name from field descriptors.
Definition reflect.hpp:178
Shared JSON, JSON-RPC, error, cancellation, and progress model types.
std::string_view icon_theme_to_string(IconTheme theme) noexcept
Converts an icon theme enum to the lowercase wire value.
Definition types.hpp:259
void append_json_extensions(Json &json, const Json &extensions)
Flattens extension members into a JSON object without overwriting typed fields.
Definition types.hpp:358
IconTheme
Preferred icon variant for clients with light or dark surfaces.
Definition types.hpp:151
std::optional< IconTheme > icon_theme_from_string(std::string_view value) noexcept
Parses a lowercase icon theme wire value.
Definition types.hpp:270
nlohmann::json Json
JSON value type used by all protocol DTOs.
Definition types.hpp:28
Json collect_json_extensions(const Json &json, std::initializer_list< std::string_view > known_keys)
Collects unknown object members so typed DTOs can preserve future protocol fields and vendor extensio...
Definition types.hpp:320
constexpr FieldDescriptor< Struct, Field > field(const char *wire_name, Field Struct::*pointer)
Creates a FieldDescriptor with wire name and pointer-to-member.
Definition reflect.hpp:75
std::vector< std::string > extract_known_keys()
Extracts known wire names from the fields() tuple at runtime.
Definition reflect.hpp:207
constexpr FieldDescriptor< Struct, Field > defaulted_field(const char *wire_name, Field Struct::*pointer)
Creates a FieldDescriptor whose missing wire value keeps the C++ default value.
Definition reflect.hpp:145
constexpr FieldDescriptor< Struct, Field > nullable_field(const char *wire_name, Field Struct::*pointer)
Creates a FieldDescriptor whose missing wire value maps to std::monostate.
Definition reflect.hpp:134
ExtensionsField< Struct > extensions_field(Json Struct::*pointer, std::vector< std::string > own_keys)
Creates an ExtensionsField descriptor.
Definition reflect.hpp:90
void serialize_one(Json &json, const Struct &obj, const FieldDescriptor< Struct, Field > &fd)
Serializes a single field into the JSON object.
Definition reflect.hpp:599
constexpr DeserializeOnlyField< Struct, Field > deserialize_only(const char *wire_name, Field Struct::*pointer)
Creates a DeserializeOnlyField descriptor.
Definition reflect.hpp:97
Json reflect_to_json(const T &obj)
Serializes a DTO to JSON using its Reflect<T> trait.
Definition reflect.hpp:701
constexpr FieldDescriptor< Struct, Field > validated_field(const char *wire_name, Field Struct::*pointer, core::Result< core::Unit >(*validator)(const Field &))
Creates a FieldDescriptor with a post-deserialization validator.
Definition reflect.hpp:82
bool 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.
Definition reflect.hpp:621
core::Result< T > reflect_from_json(const Json &json)
Deserializes a DTO from JSON using its Reflect<T> trait.
Definition reflect.hpp:722
Shared result and error primitives used by the public cxxmcp SDK.
std::monostate Unit
Success value for operations that only need to report failure.
Definition result.hpp:55
tl::expected< T, Error > Result
Alias for the SDK result type.
Definition result.hpp:64
Structured error returned by fallible SDK operations.
Definition result.hpp:35
Tag-only field descriptor for fields that are populated during deserialization only (e....
Definition reflect.hpp:66
Tag-only field descriptor for the extensions member.
Definition reflect.hpp:56
Describes a single DTO field: its JSON wire name, pointer-to-member, and optional post-deserializatio...
Definition reflect.hpp:41
Type-specific serialization and deserialization logic.
Definition reflect.hpp:246
Primary template.
Definition reflect.hpp:199
Definition reflect.hpp:169
Detects whether a type has an extensions member of type Json.
Definition reflect.hpp:152
Detects whether Reflect<T> is specialized for a given type.
Definition reflect.hpp:221
Detects std::variant containing std::monostate (nullable on wire).
Definition reflect.hpp:118
Detects std::optional<T>.
Definition reflect.hpp:108