C++ Essence Library 0.1.0
A Utility Library for Modern C++ Programming
Loading...
Searching...
No Matches
json_serializer.hpp
1/*
2 * Copyright (c) 2024 The RefValue Project
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to deal
6 * in the Software without restriction, including without limitation the rights
7 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8 * copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20 * THE SOFTWARE.
21 */
22
23#pragma once
24
25#include "../../char8_t_remediation.hpp"
26#include "../../json.hpp"
27#include "../../optional.hpp"
28#include "../detail/json.hpp"
29#include "../fingerprint.hpp"
30#include "../naming_convention.hpp"
31#include "enum.hpp"
32#include "struct.hpp"
33
34#include <concepts>
35#include <exception>
36#include <ranges>
37#include <type_traits>
38#include <utility>
39
40namespace essence::meta::runtime {
45 template <typename T, typename = void>
47 template <typename U, typename BasicJsonContext>
48 requires nlohmann::detail::is_basic_json_context<BasicJsonContext>::value
49 [[noreturn]] static void throw_exception(const U& member, std::string_view json_key, std::string_view message,
50 std::string_view internal, BasicJsonContext context) {
51
52 throw nlohmann::detail::parse_error::create(112, 0U,
53 nlohmann::detail::concat(U8("Accessing class data member '"), member.enclosing_type_name, U8("."),
54 member.name, U8("' required by JSON key '"), json_key, U8("' -- "), message,
55 U8("\nInternal error: "), internal),
56 context);
57 }
58
66 template <typename BasicJson, typename U = T>
67 requires(
68 nlohmann::detail::is_basic_json<BasicJson>::value
69 && (nlohmann::detail::is_compatible_type<nlohmann::json, U>::value || std::ranges::forward_range<U>)
70 && !std::is_enum_v<U>)
71 static void to_json(BasicJson& json, const U& value) {
72 nlohmann::to_json(json, value);
73 }
74
82 template <typename BasicJson, typename U = T>
83 requires(
84 nlohmann::detail::is_basic_json<BasicJson>::value
85 && (nlohmann::detail::is_compatible_type<nlohmann::json, U>::value || std::ranges::forward_range<U>)
86 && !std::is_enum_v<U>)
87 static void from_json(const BasicJson& json, U& value) {
88 nlohmann::from_json(json, value);
89 }
90
98 template <typename BasicJson, typename U = T>
99 requires(nlohmann::detail::is_basic_json<BasicJson>::value && std_optional<U>)
100 static void to_json(BasicJson& json, const U& value) {
101 if (value) {
102 to_json(json, *value);
103 } else {
104 json = nullptr;
105 }
106 }
107
115 template <typename BasicJson, typename U = T>
116 requires(nlohmann::detail::is_basic_json<BasicJson>::value && std_optional<U>)
117 static void from_json(const BasicJson& json, U& value) {
118 if (json.is_null()) {
119 value.reset();
120 } else {
121 typename U::value_type new_value{};
122
123 from_json(json, new_value);
124 value.emplace(std::move(new_value));
125 }
126 }
127
135 template <typename BasicJson, typename U = T>
136 requires(std::is_class_v<U> && nlohmann::detail::is_basic_json<BasicJson>::value
137 && !nlohmann::detail::is_compatible_type<nlohmann::json, U>::value
138 && !std::ranges::forward_range<U> && !std_optional<U>)
139 static void to_json(BasicJson& json, const U& value) {
140 auto handler = [&](const auto& item) {
141 try {
142 if (!detail::check_json_omitted<U>(item.raw_name)) {
143 BasicJson subjson;
144
145 to_json(subjson, item.reference);
146 json.emplace(item.name, std::move(subjson));
147 }
148 } catch (const std::exception& ex) {
149 throw_exception(
150 item, item.name, U8("Failed to serialize the data member to a JSON value."), ex.what(), &json);
151 }
152 };
153
154 enumerate_data_members<detail::get_json_naming_convention<U>()>(
155 value, [&](const auto&... members) { (handler(members), ...); });
156 }
157
165 template <typename BasicJson, typename U = T>
166 requires(std::is_class_v<U> && nlohmann::detail::is_basic_json<BasicJson>::value
167 && !nlohmann::detail::is_compatible_type<nlohmann::json, U>::value
168 && !std::ranges::forward_range<U> && !std_optional<U>)
169 static void from_json(const BasicJson& json, U& value) {
170 auto handler = [&](const auto& item) {
171 try {
172 if (!detail::check_json_omitted<U>(item.raw_name)) {
173 from_json(json.value(item.name, BasicJson{}), item.reference);
174 }
175 } catch (const std::exception& ex) {
176 throw_exception(item, item.name, U8("Failed to deserialize the JSON value to the data member."),
177 ex.what(), &json);
178 }
179 };
180
181 enumerate_data_members<detail::get_json_naming_convention<U>()>(
182 value, [&](const auto&... members) { (handler(members), ...); });
183 }
184
192 template <typename BasicJson, typename U = T>
193 requires(nlohmann::detail::is_basic_json<BasicJson>::value
194 && std::same_as<typename BasicJson::string_t::value_type, char> && std::is_enum_v<U>)
195 static void to_json(BasicJson& json, const U& value) {
197 nlohmann::to_json(
198 json, convert_naming_convention(to_string(value), detail::get_json_naming_convention<T>()));
199 } else {
200 nlohmann::to_json(json, value);
201 }
202 }
203
211 template <typename BasicJson, typename U = T>
212 requires(nlohmann::detail::is_basic_json<BasicJson>::value
213 && std::same_as<typename BasicJson::string_t::value_type, char> && std::is_enum_v<U>)
214 static void from_json(const BasicJson& json, U& value) {
215 if (json.is_string()) {
216 const auto name = json.template get_ptr<const typename BasicJson::string_t*>();
217
218 if (auto enum_value = from_string<U>(*name)) {
219 value = *enum_value;
220 } else {
221 throw nlohmann::detail::parse_error::create(112, 0U,
222 nlohmann::detail::concat(U8("invalid enumeration name '"), *name, U8("' of type '"),
223 fingerprint{std::type_identity<U>{}}.friendly_name(), U8("'.")),
224 &json);
225 }
226 } else {
227 nlohmann::from_json(json, value);
228 }
229 }
230 };
231} // namespace essence::meta::runtime
A unique identifier of a type, i.e. a fingerprint.
Definition fingerprint.hpp:34
constexpr const char * friendly_name() const noexcept
Gets the friendly name of the type.
Definition fingerprint.hpp:58
Definition optional.hpp:39
A JSON serializer by using the meta reflection implementation in this project.
Definition json_serializer.hpp:46
static void to_json(BasicJson &json, const U &value)
Serializes a std::optional<> value to a JSON value.
Definition json_serializer.hpp:100
static void from_json(const BasicJson &json, U &value)
Deserializes a JSON value to an enumeration value.
Definition json_serializer.hpp:214
static void to_json(BasicJson &json, const U &value)
Serializes an enumeration value to a JSON value.
Definition json_serializer.hpp:195
static void from_json(const BasicJson &json, U &value)
Deserializes a JSON value to a non-iterable class object.
Definition json_serializer.hpp:169
static void to_json(BasicJson &json, const U &value)
Serializes a primitive value to a JSON value.
Definition json_serializer.hpp:71
static void from_json(const BasicJson &json, U &value)
Deserializes a JSON value to a std::optional<> value.
Definition json_serializer.hpp:117
static void from_json(const BasicJson &json, U &value)
Deserializes a JSON value to a primitive value.
Definition json_serializer.hpp:87
static void to_json(BasicJson &json, const U &value)
Serializes a non-iterable class object to a JSON value.
Definition json_serializer.hpp:139