cxxmcp 1.1.6
C++ MCP SDK
Loading...
Searching...
No Matches
prompt.hpp
Go to the documentation of this file.
1// Copyright (c) 2025 [caomengxuan666]
2
3#pragma once
4
11
12#include <optional>
13#include <string>
14#include <string_view>
15#include <utility>
16#include <vector>
17
22
23namespace mcp::protocol {
24
28 User,
31};
32
34inline std::string_view prompt_message_role_to_string(PromptMessageRole role) {
35 switch (role) {
36 case PromptMessageRole::User:
37 return "user";
38 case PromptMessageRole::Assistant:
39 return "assistant";
40 }
41 return "user";
42}
43
46inline std::optional<PromptMessageRole> prompt_message_role_from_string(
47 std::string_view value) {
48 if (value == "user") {
49 return PromptMessageRole::User;
50 }
51 if (value == "assistant") {
52 return PromptMessageRole::Assistant;
53 }
54 return std::nullopt;
55}
56
58inline bool is_valid_prompt_message_role(std::string_view value) {
59 return prompt_message_role_from_string(value).has_value();
60}
61
65 std::string title;
67 std::string name;
69 std::string description;
71 bool required = false;
73 bool required_present = false;
75 Json annotations = Json::object();
77 std::optional<Json> meta;
79 Json extensions = Json::object();
80};
81
83struct Prompt {
85 std::string title;
87 std::string name;
89 std::string description;
91 std::vector<PromptArgument> arguments;
93 std::vector<Icon> icons;
95 Json annotations = Json::object();
97 std::optional<Json> meta;
99 Json extensions = Json::object();
100};
101
104 public:
105 explicit PromptBuilder(std::string name) { prompt_.name = std::move(name); }
106
107 PromptBuilder& title(std::string value) {
108 prompt_.title = std::move(value);
109 return *this;
110 }
111
112 PromptBuilder& description(std::string value) {
113 prompt_.description = std::move(value);
114 return *this;
115 }
116
117 PromptBuilder& argument(std::string name, bool required = false,
118 std::string description = {}) {
119 PromptArgument argument;
120 argument.name = std::move(name);
121 argument.description = std::move(description);
122 argument.required = required;
123 argument.required_present = true;
124 prompt_.arguments.push_back(std::move(argument));
125 return *this;
126 }
127
128 PromptBuilder& argument(PromptArgument argument) {
129 prompt_.arguments.push_back(std::move(argument));
130 return *this;
131 }
132
133 PromptBuilder& icon(Icon value) {
134 prompt_.icons.push_back(std::move(value));
135 return *this;
136 }
137
138 PromptBuilder& annotations(Json value) {
139 prompt_.annotations = std::move(value);
140 return *this;
141 }
142
143 PromptBuilder& meta(Json value) {
144 prompt_.meta = std::move(value);
145 return *this;
146 }
147
148 PromptBuilder& extension(std::string name, Json value) {
149 prompt_.extensions[std::move(name)] = std::move(value);
150 return *this;
151 }
152
153 Prompt build() { return std::move(prompt_); }
154
155 private:
156 Prompt prompt_;
157};
158
160inline PromptBuilder prompt_definition(std::string name) {
161 return PromptBuilder(std::move(name));
162}
163
167 std::vector<Prompt> prompts;
169 std::optional<std::string> next_cursor;
171 std::optional<Json> meta;
173 Json extensions = Json::object();
175 std::optional<std::int64_t> ttl_ms;
177 std::optional<std::string> cache_scope;
178};
179
183 std::string name;
185 Json arguments = Json::object();
187 std::optional<Json> meta;
189 Json extensions = Json::object();
190};
191
195 std::string role;
199 std::optional<Json> meta;
201 Json extensions = Json::object();
202
204 static PromptMessage text(std::string role, std::string value) {
205 PromptMessage message;
206 message.role = std::move(role);
207 message.content = ContentBlock::text_content(std::move(value));
208 return message;
209 }
210};
211
215 std::string description;
217 std::vector<PromptMessage> messages;
219 std::optional<Json> meta;
222 std::optional<std::string> result_type;
224 std::optional<Json> input_requests;
226 std::optional<std::string> request_state;
228 Json extensions = Json::object();
229};
230
232inline core::Error prompt_json_error(std::string message) {
233 return core::Error{
234 static_cast<int>(ErrorCode::InvalidRequest), std::move(message), {}};
235}
236
239 Json json = Json::object();
240 if (!argument.title.empty()) {
241 json["title"] = argument.title;
242 }
243 json["name"] = argument.name;
244 if (!argument.description.empty()) {
245 json["description"] = argument.description;
246 }
247 if (argument.required_present || argument.required) {
248 json["required"] = argument.required;
249 }
250 if (!argument.annotations.empty()) {
251 json["annotations"] = argument.annotations;
252 }
253 if (argument.meta.has_value()) {
254 json["_meta"] = *argument.meta;
255 }
256 append_json_extensions(json, argument.extensions);
257 return json;
258}
259
263 const Json& json) {
264 if (!json.is_object()) {
265 return mcp::core::unexpected(
266 prompt_json_error("prompt argument must be an object"));
267 }
268 if (json.contains("title")) {
269 if (!json.at("title").is_string()) {
270 return mcp::core::unexpected(
271 prompt_json_error("prompt argument title must be a string"));
272 }
273 }
274 if (!json.contains("name") || !json.at("name").is_string()) {
275 return mcp::core::unexpected(
276 prompt_json_error("prompt argument requires a string name"));
277 }
278
279 PromptArgument argument;
280 if (json.contains("title")) {
281 argument.title = json.at("title").get<std::string>();
282 }
283 argument.name = json.at("name").get<std::string>();
284 if (json.contains("description")) {
285 if (!json.at("description").is_string()) {
286 return mcp::core::unexpected(
287 prompt_json_error("prompt argument description must be a string"));
288 }
289 argument.description = json.at("description").get<std::string>();
290 }
291 if (json.contains("required")) {
292 if (!json.at("required").is_boolean()) {
293 return mcp::core::unexpected(
294 prompt_json_error("prompt argument required must be a boolean"));
295 }
296 argument.required = json.at("required").get<bool>();
297 argument.required_present = true;
298 }
299 if (json.contains("annotations")) {
300 if (!json.at("annotations").is_object()) {
301 return mcp::core::unexpected(
302 prompt_json_error("prompt argument annotations must be an object"));
303 }
304 argument.annotations = json.at("annotations");
305 }
306 if (json.contains("_meta")) {
307 if (!json.at("_meta").is_object()) {
308 return mcp::core::unexpected(
309 prompt_json_error("prompt argument _meta must be an object"));
310 }
311 argument.meta = json.at("_meta");
312 }
314 json,
315 {"title", "name", "description", "required", "annotations", "_meta"});
316 return argument;
317}
318
320inline Json prompt_to_json(const Prompt& prompt) {
321 Json json = Json::object();
322 if (!prompt.title.empty()) {
323 json["title"] = prompt.title;
324 }
325 json["name"] = prompt.name;
326 if (!prompt.description.empty()) {
327 json["description"] = prompt.description;
328 }
329 if (!prompt.arguments.empty()) {
330 json["arguments"] = Json::array();
331 for (const auto& argument : prompt.arguments) {
332 json["arguments"].push_back(prompt_argument_to_json(argument));
333 }
334 }
335 if (!prompt.icons.empty()) {
336 json["icons"] = Json::array();
337 for (const auto& icon : prompt.icons) {
338 json["icons"].push_back(icon_to_json(icon));
339 }
340 }
341 if (!prompt.annotations.empty()) {
342 json["annotations"] = prompt.annotations;
343 }
344 if (prompt.meta.has_value()) {
345 json["_meta"] = *prompt.meta;
346 }
347 append_json_extensions(json, prompt.extensions);
348 return json;
349}
350
354 if (!json.is_object()) {
355 return mcp::core::unexpected(prompt_json_error("prompt must be an object"));
356 }
357 if (json.contains("title")) {
358 if (!json.at("title").is_string()) {
359 return mcp::core::unexpected(
360 prompt_json_error("prompt title must be a string"));
361 }
362 }
363 if (!json.contains("name") || !json.at("name").is_string()) {
364 return mcp::core::unexpected(
365 prompt_json_error("prompt requires a string name"));
366 }
367
368 Prompt prompt;
369 if (json.contains("title")) {
370 prompt.title = json.at("title").get<std::string>();
371 }
372 prompt.name = json.at("name").get<std::string>();
373 if (json.contains("description")) {
374 if (!json.at("description").is_string()) {
375 return mcp::core::unexpected(
376 prompt_json_error("prompt description must be a string"));
377 }
378 prompt.description = json.at("description").get<std::string>();
379 }
380 if (json.contains("arguments")) {
381 if (!json.at("arguments").is_array()) {
382 return mcp::core::unexpected(
383 prompt_json_error("prompt arguments must be an array"));
384 }
385 for (const auto& item : json.at("arguments")) {
386 const auto argument = prompt_argument_from_json(item);
387 if (!argument) {
388 return mcp::core::unexpected(argument.error());
389 }
390 prompt.arguments.push_back(*argument);
391 }
392 }
393 if (json.contains("icons")) {
394 if (!json.at("icons").is_array()) {
395 return mcp::core::unexpected(
396 prompt_json_error("prompt icons must be an array"));
397 }
398 for (const auto& item : json.at("icons")) {
399 const auto icon = icon_from_json(item);
400 if (!icon.has_value()) {
401 return mcp::core::unexpected(
402 prompt_json_error("prompt icon is invalid"));
403 }
404 prompt.icons.push_back(*icon);
405 }
406 }
407 if (json.contains("annotations")) {
408 if (!json.at("annotations").is_object()) {
409 return mcp::core::unexpected(
410 prompt_json_error("prompt annotations must be an object"));
411 }
412 prompt.annotations = json.at("annotations");
413 }
414 if (json.contains("_meta")) {
415 if (!json.at("_meta").is_object()) {
416 return mcp::core::unexpected(
417 prompt_json_error("prompt _meta must be an object"));
418 }
419 prompt.meta = json.at("_meta");
420 }
421 prompt.extensions = collect_json_extensions(
422 json, {"title", "name", "description", "arguments", "icons",
423 "annotations", "_meta"});
424 return prompt;
425}
426
429 Json json = Json::object();
430 json["prompts"] = Json::array();
431 for (const auto& prompt : result.prompts) {
432 json["prompts"].push_back(prompt_to_json(prompt));
433 }
434 if (result.next_cursor.has_value()) {
435 json["nextCursor"] = *result.next_cursor;
436 }
437 if (result.meta.has_value()) {
438 json["_meta"] = *result.meta;
439 }
440 if (result.ttl_ms.has_value()) {
441 json["ttlMs"] = *result.ttl_ms;
442 }
443 if (result.cache_scope.has_value()) {
444 json["cacheScope"] = *result.cache_scope;
445 }
447 return json;
448}
449
453 const Json& json) {
454 if (!json.is_object()) {
455 return mcp::core::unexpected(
456 prompt_json_error("prompts/list result must be an object"));
457 }
458 if (!json.contains("prompts") || !json.at("prompts").is_array()) {
459 return mcp::core::unexpected(
460 prompt_json_error("prompts/list result requires a prompts array"));
461 }
462
463 PromptsListResult result;
464 for (const auto& item : json.at("prompts")) {
465 const auto prompt = prompt_from_json(item);
466 if (!prompt) {
467 return mcp::core::unexpected(prompt.error());
468 }
469 result.prompts.push_back(*prompt);
470 }
471 if (json.contains("nextCursor")) {
472 if (!json.at("nextCursor").is_string()) {
473 return mcp::core::unexpected(
474 prompt_json_error("prompts/list nextCursor must be a string"));
475 }
476 result.next_cursor = json.at("nextCursor").get<std::string>();
477 }
478 if (json.contains("_meta")) {
479 if (!json.at("_meta").is_object()) {
480 return mcp::core::unexpected(
481 prompt_json_error("prompts/list result _meta must be an object"));
482 }
483 result.meta = json.at("_meta");
484 }
485 result.extensions =
486 collect_json_extensions(json, {"prompts", "nextCursor", "_meta"});
487 return result;
488}
489
492 Json json = Json::object();
493 json["name"] = params.name;
494 if (!params.arguments.empty()) {
495 json["arguments"] = params.arguments;
496 }
497 if (params.meta.has_value()) {
498 json["_meta"] = *params.meta;
499 }
501 return json;
502}
503
507 const Json& json) {
508 if (!json.is_object()) {
509 return mcp::core::unexpected(
510 prompt_json_error("prompts/get params must be an object"));
511 }
512 if (!json.contains("name") || !json.at("name").is_string()) {
513 return mcp::core::unexpected(
514 prompt_json_error("prompts/get params require a string name"));
515 }
516
517 PromptsGetParams params;
518 params.name = json.at("name").get<std::string>();
519 if (json.contains("arguments")) {
520 if (!json.at("arguments").is_object()) {
521 return mcp::core::unexpected(
522 prompt_json_error("prompts/get arguments must be an object"));
523 }
524 params.arguments = json.at("arguments");
525 }
526 if (json.contains("_meta")) {
527 if (!json.at("_meta").is_object()) {
528 return mcp::core::unexpected(
529 prompt_json_error("prompts/get _meta must be an object"));
530 }
531 params.meta = json.at("_meta");
532 }
533 params.extensions =
534 collect_json_extensions(json, {"name", "arguments", "_meta"});
535 return params;
536}
537
540 Json json = Json::object();
541 json["role"] = message.role;
542 json["content"] = content_block_to_json(message.content);
543 if (message.meta.has_value()) {
544 json["_meta"] = *message.meta;
545 }
546 append_json_extensions(json, message.extensions);
547 return json;
548}
549
553 if (!json.is_object()) {
554 return mcp::core::unexpected(
555 prompt_json_error("prompt message must be an object"));
556 }
557 if (!json.contains("role") || !json.at("role").is_string()) {
558 return mcp::core::unexpected(
559 prompt_json_error("prompt message requires a string role"));
560 }
561 if (!json.contains("content")) {
562 return mcp::core::unexpected(
563 prompt_json_error("prompt message requires content"));
564 }
565
566 const auto content = content_block_from_json(json.at("content"));
567 if (!content) {
568 return mcp::core::unexpected(content.error());
569 }
570
571 PromptMessage message;
572 message.role = json.at("role").get<std::string>();
573 message.content = *content;
574 if (json.contains("_meta")) {
575 if (!json.at("_meta").is_object()) {
576 return mcp::core::unexpected(
577 prompt_json_error("prompt message _meta must be an object"));
578 }
579 message.meta = json.at("_meta");
580 }
581 message.extensions =
582 collect_json_extensions(json, {"role", "content", "_meta"});
583 return message;
584}
585
588 Json json = Json::object();
589 if (result.result_type.has_value()) {
590 json["resultType"] = *result.result_type;
591 }
592 if (!result.description.empty()) {
593 json["description"] = result.description;
594 }
595 if (!result.messages.empty()) {
596 json["messages"] = Json::array();
597 for (const auto& message : result.messages) {
598 json["messages"].push_back(prompt_message_to_json(message));
599 }
600 }
601 if (result.meta.has_value()) {
602 json["_meta"] = *result.meta;
603 }
604 if (result.input_requests.has_value()) {
605 json["inputRequests"] = *result.input_requests;
606 }
607 if (result.request_state.has_value()) {
608 json["requestState"] = *result.request_state;
609 }
611 return json;
612}
613
617 const Json& json) {
618 if (!json.is_object()) {
619 return mcp::core::unexpected(
620 prompt_json_error("prompts/get result must be an object"));
621 }
622 if (!json.contains("messages") && !json.contains("resultType") &&
623 !json.contains("inputRequests")) {
624 return mcp::core::unexpected(prompt_json_error(
625 "prompts/get result requires messages, resultType, or inputRequests"));
626 }
627
628 PromptsGetResult result;
629 if (json.contains("resultType")) {
630 result.result_type = json.at("resultType").get<std::string>();
631 }
632 if (json.contains("description")) {
633 if (!json.at("description").is_string()) {
634 return mcp::core::unexpected(
635 prompt_json_error("prompts/get description must be a string"));
636 }
637 result.description = json.at("description").get<std::string>();
638 }
639 if (json.contains("messages")) {
640 if (!json.at("messages").is_array()) {
641 return mcp::core::unexpected(
642 prompt_json_error("prompts/get messages must be an array"));
643 }
644 for (const auto& item : json.at("messages")) {
645 const auto message = prompt_message_from_json(item);
646 if (!message) {
647 return mcp::core::unexpected(message.error());
648 }
649 result.messages.push_back(*message);
650 }
651 }
652 if (json.contains("_meta")) {
653 if (!json.at("_meta").is_object()) {
654 return mcp::core::unexpected(
655 prompt_json_error("prompts/get result _meta must be an object"));
656 }
657 result.meta = json.at("_meta");
658 }
659 if (json.contains("inputRequests")) {
660 result.input_requests = json.at("inputRequests");
661 }
662 if (json.contains("requestState")) {
663 result.request_state = json.at("requestState").get<std::string>();
664 }
666 json, {"description", "messages", "_meta", "resultType", "inputRequests",
667 "requestState"});
668 return result;
669}
670
671} // namespace mcp::protocol
Fluent builder for prompt descriptors.
Definition prompt.hpp:103
core::Result< PromptArgument > prompt_argument_from_json(const Json &json)
Parses a prompt argument descriptor.
Definition prompt.hpp:262
core::Result< PromptsGetResult > prompts_get_result_from_json(const Json &json)
Parses a prompts/get result.
Definition prompt.hpp:616
core::Result< PromptsListResult > prompts_list_result_from_json(const Json &json)
Parses a prompts/list result.
Definition prompt.hpp:452
Json prompts_get_params_to_json(const PromptsGetParams &params)
Serializes prompts/get params.
Definition prompt.hpp:491
std::optional< PromptMessageRole > prompt_message_role_from_string(std::string_view value)
Parses a prompt message role string.
Definition prompt.hpp:46
std::string_view prompt_message_role_to_string(PromptMessageRole role)
Converts a prompt message role to its MCP wire string.
Definition prompt.hpp:34
bool is_valid_prompt_message_role(std::string_view value)
Checks whether a string is a valid prompt message role.
Definition prompt.hpp:58
PromptMessageRole
Roles allowed on a prompt message.
Definition prompt.hpp:26
@ User
Message from the user.
@ Assistant
Message from the assistant (model).
Json prompt_argument_to_json(const PromptArgument &argument)
Serializes a prompt argument descriptor.
Definition prompt.hpp:238
core::Result< PromptMessage > prompt_message_from_json(const Json &json)
Parses one rendered prompt message.
Definition prompt.hpp:552
Json prompts_get_result_to_json(const PromptsGetResult &result)
Serializes a prompts/get result.
Definition prompt.hpp:587
PromptBuilder prompt_definition(std::string name)
Creates a fluent builder for advertised MCP prompt metadata.
Definition prompt.hpp:160
Json prompts_list_result_to_json(const PromptsListResult &result)
Serializes a prompts/list result.
Definition prompt.hpp:428
Json prompt_to_json(const Prompt &prompt)
Serializes a prompt descriptor.
Definition prompt.hpp:320
core::Result< Prompt > prompt_from_json(const Json &json)
Parses a prompt descriptor.
Definition prompt.hpp:353
core::Result< PromptsGetParams > prompts_get_params_from_json(const Json &json)
Parses prompts/get params.
Definition prompt.hpp:506
core::Error prompt_json_error(std::string message)
Builds an InvalidRequest error for prompt JSON validation failures.
Definition prompt.hpp:232
Json prompt_message_to_json(const PromptMessage &message)
Serializes one rendered prompt message.
Definition prompt.hpp:539
Shared JSON, JSON-RPC, error, cancellation, and progress model types.
void append_json_extensions(Json &json, const Json &extensions)
Flattens extension members into a JSON object without overwriting typed fields.
Definition types.hpp:358
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
Shared result and error primitives used by the public cxxmcp SDK.
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
A single content item returned by a tool or embedded in prompts.
Definition tool.hpp:93
static ContentBlock text_content(std::string value)
Creates a text content block.
Definition tool.hpp:115
Icon descriptor used by tools, resources, resource templates, and prompts.
Definition types.hpp:160
Argument accepted by a prompt template.
Definition prompt.hpp:63
std::string name
Stable argument name used as a key in prompts/get arguments.
Definition prompt.hpp:67
Json extensions
Unknown JSON members preserved for forward-compatible round trips.
Definition prompt.hpp:79
std::optional< Json > meta
Optional _meta extension object preserved on the wire.
Definition prompt.hpp:77
Json annotations
Optional annotations for model or client presentation.
Definition prompt.hpp:75
bool required
Whether the caller must provide this argument.
Definition prompt.hpp:71
bool required_present
Whether required was explicitly present on the wire or configured.
Definition prompt.hpp:73
std::string title
Optional human-readable display title.
Definition prompt.hpp:65
std::string description
Optional human-readable description.
Definition prompt.hpp:69
One rendered prompt message.
Definition prompt.hpp:193
Json extensions
Unknown JSON members preserved for forward-compatible round trips.
Definition prompt.hpp:201
static PromptMessage text(std::string role, std::string value)
Creates a text-only prompt message for the given role.
Definition prompt.hpp:204
std::optional< Json > meta
Optional _meta extension object preserved on the wire.
Definition prompt.hpp:199
ContentBlock content
Message content block.
Definition prompt.hpp:197
std::string role
Message role understood by the receiving model or peer.
Definition prompt.hpp:195
Prompt descriptor returned by prompts/list.
Definition prompt.hpp:83
std::optional< Json > meta
Optional _meta extension object preserved on the wire.
Definition prompt.hpp:97
std::string name
Stable prompt name used by prompts/get.
Definition prompt.hpp:87
std::string description
Optional human-readable description.
Definition prompt.hpp:89
std::vector< Icon > icons
Optional icon descriptors for client presentation.
Definition prompt.hpp:93
std::vector< PromptArgument > arguments
Prompt arguments accepted by this prompt.
Definition prompt.hpp:91
std::string title
Optional human-readable display title.
Definition prompt.hpp:85
Json extensions
Unknown JSON members preserved for forward-compatible round trips.
Definition prompt.hpp:99
Json annotations
Optional annotations for model or client presentation.
Definition prompt.hpp:95
Parameters for prompts/get.
Definition prompt.hpp:181
std::string name
Prompt name matching a Prompt descriptor.
Definition prompt.hpp:183
Json arguments
JSON object keyed by prompt argument name.
Definition prompt.hpp:185
Json extensions
Unknown JSON members preserved for forward-compatible round trips.
Definition prompt.hpp:189
std::optional< Json > meta
Optional _meta extension object preserved on the wire.
Definition prompt.hpp:187
Result object for prompts/get.
Definition prompt.hpp:213
std::optional< Json > input_requests
Server input requests for MRTR (SEP-2322).
Definition prompt.hpp:224
std::string description
Optional rendered prompt description.
Definition prompt.hpp:215
std::vector< PromptMessage > messages
Ordered messages produced by the prompt.
Definition prompt.hpp:217
std::optional< std::string > request_state
Opaque request state for MRTR retries (SEP-2322).
Definition prompt.hpp:226
Json extensions
Unknown JSON members preserved for forward-compatible round trips.
Definition prompt.hpp:228
std::optional< Json > meta
Optional _meta extension object preserved on the wire.
Definition prompt.hpp:219
std::optional< std::string > result_type
Result type discriminator.
Definition prompt.hpp:222
Result object for prompts/list.
Definition prompt.hpp:165
std::vector< Prompt > prompts
Prompts available to the caller.
Definition prompt.hpp:167
std::optional< std::string > next_cursor
Optional cursor for retrieving the next page.
Definition prompt.hpp:169
std::optional< std::string > cache_scope
Cache scope hint: "public" or "private" (SEP-2549).
Definition prompt.hpp:177
std::optional< std::int64_t > ttl_ms
Cache time-to-live hint in milliseconds (SEP-2549).
Definition prompt.hpp:175
Json extensions
Unknown JSON members preserved for forward-compatible round trips.
Definition prompt.hpp:173
std::optional< Json > meta
Optional _meta extension object preserved on the wire.
Definition prompt.hpp:171
Tool definition, call, and result payloads.
Json content_block_to_json(const ContentBlock &block)
Serializes a content block.
Definition tool.hpp:530
core::Result< ContentBlock > content_block_from_json(const Json &json)
Parses a content block from JSON.
Definition tool.hpp:573
Reflection specializations for DTOs defined in types.hpp.
Json icon_to_json(const Icon &icon)
Serializes a shared icon descriptor.
Definition types_reflect.hpp:109
std::optional< Icon > icon_from_json(const Json &json)
Parses a shared icon descriptor.
Definition types_reflect.hpp:114