使用boost pfr 遍历结构体

This commit is contained in:
2026-06-26 09:36:15 +08:00
parent acc1b7003d
commit fd6097564c
142 changed files with 13775 additions and 410 deletions
+9
View File
@@ -309,6 +309,15 @@ JSON &JSON::operator=(JSON &&other) noexcept {
}
return *this;
}
JSON& JSON::operator+=(const JSON& child) {
append_list(child.children);
return *this;
}
JSON& JSON::operator+=(JSON&& child) {
append_list(child.children);
return *this;
}
// 解析的分割线----------------------------
// 如果未找到非空白字符,将 i 更新为 std::string::npos
+451 -408
View File
@@ -1,5 +1,4 @@
#pragma once
#include "../Base/global_include.h"
#include "../system/export.h"
#include <atomic>
@@ -9,13 +8,9 @@
#include <optional>
#include <string>
#include <vector>
#define PSC_JSON_KEY_PARAMS(M, SEP) M(const std::string &, key)
#define PSC_JSON_PARSE_PARAMS(M, SEP) M(const std::string &, text)
#define PSC_JSON_FILE_PARAMS(M, SEP) M(const std::string &, file_name)
#undef max
#undef min
#define Json_GET(type, name) \
@@ -28,453 +23,473 @@
} \
return that->name##_val(); \
}
#pragma once
#include "../Base/global_include.h"
#include <stdexcept>
#include <string>
#include <system_error>
#include <utility>
namespace Psc {
class json_assign_error final : public std::system_error {
public:
using std::system_error::system_error;
using std::system_error::system_error;
};
enum JsonType : uint8_t { String, Object, Array, Null, Number, Bool };
template <typename T> void assign_json(JsonType &rt, std::string &rv, T &&val);
template <typename T>
void assign_json(JsonType& rt, std::string& rv, T&& val);
template <typename T_Number>
bool to_number_ec(const std::string &val, T_Number &out,
std::error_code &ec) noexcept;
template <typename T_Number> T_Number to_number(const std::string &val) {
return detail::triple_api_throwing<T_Number>(
[&val](T_Number &out, std::error_code &ec) {
return to_number_ec(val, out, ec);
},
"to_number failed");
bool to_number_ec(const std::string& val, T_Number& out,
std::error_code& ec) noexcept;
template <typename T_Number>
T_Number to_number(const std::string& val) {
return detail::triple_api_throwing<T_Number>(
[&val](T_Number& out, std::error_code& ec) {
return to_number_ec(val, out, ec);
},
"to_number failed");
}
template <typename T_Number>
expected<T_Number, std::error_code>
try_to_number(const std::string &val) noexcept {
return detail::triple_api_expected<T_Number>(
[&val](T_Number &out, std::error_code &ec) {
return to_number_ec(val, out, ec);
});
try_to_number(const std::string& val) noexcept {
return detail::triple_api_expected<T_Number>(
[&val](T_Number& out, std::error_code& ec) {
return to_number_ec(val, out, ec);
});
}
template <typename T_Number>
bool to_number_ec(const std::string &val, T_Number &out,
std::error_code &ec) noexcept {
ec.clear();
// 限定只支持整数/浮点,其他类型编译期报错(比运行时返回默认值更安全)
static_assert(std::is_integral_v<T_Number> ||
std::is_floating_point_v<T_Number>,
"to_number<T_Number>: T_Number must be an integral or "
"floating-point type");
try {
if constexpr (std::is_integral_v<T_Number>) {
if constexpr (std::is_unsigned_v<T_Number>) {
// stoull: 负号、非数字等会抛 invalid_argument;超范围抛 out_of_range
unsigned long long x = std::stoull(val);
// 额外范围检查,避免静默截断
if (x > static_cast<unsigned long long>(
bool to_number_ec(const std::string& val, T_Number& out,
std::error_code& ec) noexcept {
ec.clear();
// 限定只支持整数/浮点,其他类型编译期报错(比运行时返回默认值更安全)
static_assert(std::is_integral_v<T_Number> ||
std::is_floating_point_v<T_Number>,
"to_number<T_Number>: T_Number must be an integral or "
"floating-point type");
try {
if constexpr (std::is_integral_v<T_Number>) {
if constexpr (std::is_unsigned_v<T_Number>) {
// stoull: 负号、非数字等会抛 invalid_argument;超范围抛 out_of_range
unsigned long long x = std::stoull(val);
// 额外范围检查,避免静默截断
if (x > static_cast<unsigned long long>(
std::numeric_limits<T_Number>::max())) {
ec = std::make_error_code(std::errc::result_out_of_range);
return false;
ec = std::make_error_code(std::errc::result_out_of_range);
return false;
}
out = static_cast<T_Number>(x);
return true;
}
else {
long long x = std::stoll(val);
// 额外范围检查,避免静默截断
if (x < static_cast<long long>(std::numeric_limits<T_Number>::min()) ||
x > static_cast<long long>(std::numeric_limits<T_Number>::max())) {
ec = std::make_error_code(std::errc::result_out_of_range);
return false;
}
out = static_cast<T_Number>(x);
return true;
}
}
out = static_cast<T_Number>(x);
return true;
} else {
long long x = std::stoll(val);
// 额外范围检查,避免静默截断
if (x < static_cast<long long>(std::numeric_limits<T_Number>::min()) ||
x > static_cast<long long>(std::numeric_limits<T_Number>::max())) {
ec = std::make_error_code(std::errc::result_out_of_range);
return false;
else {
// floating point
long double x = std::stold(val);
// 可选:检查是否超出目标浮点类型范围
if (x < -static_cast<long double>(std::numeric_limits<T_Number>::max()) ||
x > static_cast<long double>(std::numeric_limits<T_Number>::max())) {
ec = std::make_error_code(std::errc::result_out_of_range);
return false;
}
out = static_cast<T_Number>(x);
return true;
}
out = static_cast<T_Number>(x);
return true;
}
} else { // floating point
long double x = std::stold(val);
// 可选:检查是否超出目标浮点类型范围
if (x < -static_cast<long double>(std::numeric_limits<T_Number>::max()) ||
x > static_cast<long double>(std::numeric_limits<T_Number>::max())) {
ec = std::make_error_code(std::errc::result_out_of_range);
return false;
}
out = static_cast<T_Number>(x);
return true;
}
} catch (const std::invalid_argument &) {
ec = std::make_error_code(std::errc::invalid_argument);
return false; // 不能解析为数字
} catch (const std::out_of_range &) {
ec = std::make_error_code(std::errc::result_out_of_range);
return false; // 数值超范围
}
catch (const std::invalid_argument&) {
ec = std::make_error_code(std::errc::invalid_argument);
return false; // 不能解析为数字
}
catch (const std::out_of_range&) {
ec = std::make_error_code(std::errc::result_out_of_range);
return false; // 数值超范围
}
}
class JSON {
public:
static std::function<void(const char *, const std::string &, const char *,
int)>
handle_error;
explicit operator std::string() const;
friend std::ostream &operator<<(std::ostream &os, const JSON &obj);
[[nodiscard]] bool has(const std::string &key) const;
[[nodiscard]] const JSON *get(const std::string &key) const;
PSC_DECLARE_TRIPLE_API_CONST_METHOD(std::string, get_string,
PSC_JSON_KEY_PARAMS);
PSC_DECLARE_TRIPLE_API_CONST_METHOD_0(bool, bool_val);
PSC_DECLARE_TRIPLE_API_CONST_METHOD(bool, get_bool, PSC_JSON_KEY_PARAMS);
template <typename T_Number>
T_Number get_number(const std::string &key) const {
return detail::triple_api_throwing<T_Number>(
[this, &key](T_Number &out, std::error_code &ec) {
return get_number_ec(key, out, ec);
},
"get_number failed");
}
template <typename T_Number>
expected<T_Number, std::error_code>
try_get_number(const std::string &key) const noexcept {
return detail::triple_api_expected<T_Number>(
[this, &key](T_Number &out, std::error_code &ec) {
return get_number_ec(key, out, ec);
});
}
template <typename T_Number>
bool get_number_ec(const std::string &key, T_Number &out,
std::error_code &ec) const noexcept {
const JSON *that = get(key);
if (!that) {
ec = std::make_error_code(std::errc::invalid_argument);
return false;
static std::function<void(const char*, const std::string&, const char*,
int)>
handle_error;
explicit operator std::string() const;
friend std::ostream& operator<<(std::ostream& os, const JSON& obj);
[[nodiscard]] bool has(const std::string& key) const;
[[nodiscard]] const JSON* get(const std::string& key) const;
PSC_DECLARE_TRIPLE_API_CONST_METHOD(std::string, get_string,
PSC_JSON_KEY_PARAMS);
PSC_DECLARE_TRIPLE_API_CONST_METHOD_0(bool, bool_val);
PSC_DECLARE_TRIPLE_API_CONST_METHOD(bool, get_bool, PSC_JSON_KEY_PARAMS);
template <typename T_Number>
T_Number get_number(const std::string& key) const {
return detail::triple_api_throwing<T_Number>(
[this, &key](T_Number& out, std::error_code& ec) {
return get_number_ec(key, out, ec);
},
"get_number failed");
}
return that->number_val_ec(out, ec);
}
template <typename T_Number> T_Number number_val() const {
return detail::triple_api_throwing<T_Number>(
[this](T_Number &out, std::error_code &ec) {
return number_val_ec(out, ec);
},
"number_val failed");
}
template <typename T_Number>
expected<T_Number, std::error_code> try_number_val() const noexcept {
return detail::triple_api_expected<T_Number>(
[this](T_Number &out, std::error_code &ec) {
return number_val_ec(out, ec);
});
}
template <typename T_Number>
bool number_val_ec(T_Number &out, std::error_code &ec) const noexcept {
if (valueType != Number) {
ec = std::make_error_code(std::errc::invalid_argument);
return false;
template <typename T_Number>
expected<T_Number, std::error_code>
try_get_number(const std::string& key) const noexcept {
return detail::triple_api_expected<T_Number>(
[this, &key](T_Number& out, std::error_code& ec) {
return get_number_ec(key, out, ec);
});
}
return to_number_ec(val, out, ec);
}
JSON(std::string key, const JSON &body);
template <typename T,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, JSON>>>
JSON(std::string k, T &&v) {
key = std::move(k);
assign_json(valueType, val, std::forward<T>(v));
}
template <typename T,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, JSON>>>
JSON(T &&v) {
assign_json(valueType, val, std::forward<T>(v));
}
JSON();
JSON(const JSON &other);
JSON(JSON &&other) noexcept;
JSON &operator=(const JSON &other);
JSON &operator=(JSON &&other) noexcept;
void append_list(const std::vector<JSON> &arr);
void append(const JSON &json);
void prepend(const JSON &json);
static JSON array(std::string key, const std::vector<JSON> &arr);
static JSON object(std::string key, const std::vector<JSON> &children);
static JSON array(const std::vector<JSON> &arr = {});
static JSON object(const std::vector<JSON> &children = {});
JsonType valueType = Null;
std::string key, val;
std::vector<JSON> children;
[[nodiscard]] std::string
to_json_string(const std::string &object_split = "\n",
const std::string &array_split = "\n",
const std::string &indentStr = " ",
const int &indent = 0) const;
template <typename T_Number>
bool get_number_ec(const std::string& key, T_Number& out,
std::error_code& ec) const noexcept {
const JSON* that = get(key);
if (!that) {
ec = std::make_error_code(std::errc::invalid_argument);
return false;
}
return that->number_val_ec(out, ec);
}
template <typename T_Number>
T_Number number_val() const {
return detail::triple_api_throwing<T_Number>(
[this](T_Number& out, std::error_code& ec) {
return number_val_ec(out, ec);
},
"number_val failed");
}
template <typename T_Number>
expected<T_Number, std::error_code> try_number_val() const noexcept {
return detail::triple_api_expected<T_Number>(
[this](T_Number& out, std::error_code& ec) {
return number_val_ec(out, ec);
});
}
template <typename T_Number>
bool number_val_ec(T_Number& out, std::error_code& ec) const noexcept {
if (valueType != Number) {
ec = std::make_error_code(std::errc::invalid_argument);
return false;
}
return to_number_ec(val, out, ec);
}
JSON(std::string key, const JSON& body);
template <typename T,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, JSON>>>
JSON(std::string k, T&& v) {
key = std::move(k);
assign_json(valueType, val, std::forward<T>(v));
}
template <typename T,
typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, JSON>>>
JSON(T&& v) {
assign_json(valueType, val, std::forward<T>(v));
}
JSON();
JSON(const JSON& other);
JSON(JSON&& other) noexcept;
JSON& operator=(const JSON& other);
JSON& operator=(JSON&& other) noexcept;
JSON& operator+=(const JSON& child);
JSON& operator+=(JSON&& child);
void append_list(const std::vector<JSON>& arr);
void append(const JSON& json);
void prepend(const JSON& json);
static JSON array(std::string key, const std::vector<JSON>& arr);
static JSON object(std::string key, const std::vector<JSON>& children);
static JSON array(const std::vector<JSON>& arr = {});
static JSON object(const std::vector<JSON>& children = {});
JsonType valueType = Null;
std::string key, val;
std::vector<JSON> children;
[[nodiscard]] std::string
to_json_string(const std::string& object_split = "\n",
const std::string& array_split = "\n",
const std::string& indentStr = " ",
const int& indent = 0) const;
private:
static std::string get_indent(const int &indent,
const std::string &indentStr);
void append_value_string(std::string &ret, const int &indent, bool isEnd,
const std::string &object_split,
const std::string &array_split,
const std::string &indentStr,
JsonType fatherType) const;
static std::string get_indent(const int& indent,
const std::string& indentStr);
void append_value_string(std::string& ret, const int& indent, bool isEnd,
const std::string& object_split,
const std::string& array_split,
const std::string& indentStr,
JsonType fatherType) const;
};
PSC_DECLARE_TRIPLE_API(JSON, parse_json, PSC_JSON_PARSE_PARAMS);
PSC_DECLARE_TRIPLE_API(JSON, parse_json_file, PSC_JSON_FILE_PARAMS);
template <typename T> void assign_json(JsonType &rt, std::string &rv, T &&v) {
using C = std::decay_t<T>;
if constexpr (std::is_same_v<C, std::string>) {
rt = String;
rv = std::forward<T>(v);
} else if constexpr (std::is_same_v<C, void *>) {
std::stringstream ss;
ss << "0x" << std::setw(sizeof(void *) * 2) << std::setfill('0') << std::hex
<< reinterpret_cast<std::uintptr_t>(v);
rt = String;
rv = ss.str();
}
// 处理 char* 类型
else if constexpr (std::is_same_v<C, char *>) {
rt = String;
rv = std::string(v);
} else if constexpr (std::is_same_v<C, const char *>) {
rt = String;
rv = std::string(v); // 或 val = v;
}
// 处理 wchar_t* 类型
else if constexpr (std::is_same_v<C, wchar_t *>) {
std::wstring ws(v);
rt = String;
rv = std::string(ws.begin(), ws.end());
}
// 处理 std::wstring 类型
else if constexpr (std::is_same_v<C, std::wstring>) {
rt = String;
rv = std::string(v.begin(), v.end());
}
// 处理枚举类型
else if constexpr (std::is_enum_v<C>) {
rt = String;
rv = std::string(magic_enum::enum_name(v));
}
// 处理 bool 类型
else if constexpr (std::is_same_v<C, bool>) {
rt = Bool;
rv = v ? "true" : "false"; // 对 bool 类型进行自定义转换
}
// 处理 std::nullptr_t 类型
else if constexpr (std::is_same_v<C, std::nullptr_t>) {
rt = Null;
rv = "null";
} else if constexpr (std::is_arithmetic_v<C>) {
rt = Number;
rv = std::to_string(v);
} else if constexpr (is_atomic_v<C>) {
assign_json(rt, rv, v.load());
} else if constexpr (is_optional_v<C>) {
if (v.has_value()) {
assign_json(rt, rv, v.value());
} else {
rt = Null;
rv = "null";
}
} else {
rt = String;
rv = v.to_string();
}
}
template <typename T>
bool assign_field_ec(T &field, const Psc::JSON *that_json, const char *name,
std::error_code &ec) noexcept;
void assign_json(JsonType& rt, std::string& rv, T&& v) {
using C = std::decay_t<T>;
if constexpr (std::is_same_v<C, std::string>) {
rt = String;
rv = std::forward<T>(v);
}
else if constexpr (std::is_same_v<C, void*>) {
std::stringstream ss;
ss << "0x" << std::setw(sizeof(void*) * 2) << std::setfill('0') << std::hex
<< reinterpret_cast<std::uintptr_t>(v);
rt = String;
rv = ss.str();
}
// 处理 char* 类型
else if constexpr (std::is_same_v<C, char*>) {
rt = String;
rv = std::string(v);
}
else if constexpr (std::is_same_v<C, const char*>) {
rt = String;
rv = std::string(v); // 或 val = v;
}
// 处理 wchar_t* 类型
else if constexpr (std::is_same_v<C, wchar_t*>) {
std::wstring ws(v);
rt = String;
rv = std::string(ws.begin(), ws.end());
}
// 处理 std::wstring 类型
else if constexpr (std::is_same_v<C, std::wstring>) {
rt = String;
rv = std::string(v.begin(), v.end());
}
// 处理枚举类型
else if constexpr (std::is_enum_v<C>) {
rt = String;
rv = std::string(magic_enum::enum_name(v));
}
// 处理 bool 类型
else if constexpr (std::is_same_v<C, bool>) {
rt = Bool;
rv = v ? "true" : "false"; // 对 bool 类型进行自定义转换
}
// 处理 std::nullptr_t 类型
else if constexpr (std::is_same_v<C, std::nullptr_t>) {
rt = Null;
rv = "null";
}
else if constexpr (std::is_arithmetic_v<C>) {
rt = Number;
rv = std::to_string(v);
}
else if constexpr (is_atomic_v<C>) {
assign_json(rt, rv, v.load());
}
else if constexpr (is_optional_v<C>) {
if (v.has_value()) {
assign_json(rt, rv, v.value());
}
else {
rt = Null;
rv = "null";
}
}
else {
rt = String;
rv = v.to_string();
}
}
void check_json_assign_field(bool ok, const std::error_code& ec,
const Psc::JSON* that_json, const char* name);
template <typename T>
void assign_field(T &field, const Psc::JSON *that_json, const char *name) {
detail::triple_api_throwing_void(
[&field, that_json, name](std::error_code &ec) {
return assign_field_ec(field, that_json, name, ec);
},
"assign_field failed");
}
bool assign_field_ec(T& field, const Psc::JSON* that_json, const char* name, std::error_code& ec) noexcept;
template <typename T>
expected<void, std::error_code> try_assign_field(T &field,
const Psc::JSON *that_json,
const char *name) noexcept {
return detail::triple_api_expected_void(
[&field, that_json, name](std::error_code &ec) {
return assign_field_ec(field, that_json, name, ec);
});
void assign_field(T& field, const Psc::JSON* that_json, const char* name) {
detail::triple_api_throwing_void(
[&field, that_json, name](std::error_code& ec) {
return assign_field_ec(field, that_json, name, ec);
},
"assign_field failed");
}
template <typename T>
bool assign_field_ec(T &field, const Psc::JSON *that_json, const char *name,
std::error_code &ec) noexcept {
using C = clean_t<T>;
if (that_json == nullptr) {
ec = std::make_error_code(std::errc::invalid_argument);
return false;
}
auto j = that_json->get(name);
if (j == nullptr) {
ec = std::make_error_code(std::errc::invalid_argument);
return false;
}
if constexpr (std::is_same_v<C, bool>) {
return j->bool_val_ec(field, ec);
} else if constexpr (std::is_arithmetic_v<C> && !std::is_same_v<C, bool>) {
return that_json->get_number_ec(name, field, ec);
} else if constexpr (std::is_same_v<C, std::string>) {
return that_json->get_string_ec(name, field, ec);
} else if constexpr (std::is_enum_v<C>) {
std::string value;
if (!that_json->get_string_ec(name, value, ec))
return false;
field = Psc::to_enum<C>(value);
} else if constexpr (is_atomic_v<T>) {
using V = atomic_value_t<T>;
V value{};
if constexpr (std::is_same_v<V, bool>) {
if (!that_json->get_bool_ec(name, value, ec))
return false;
} else if constexpr (std::is_arithmetic_v<V>) {
if (!that_json->get_number_ec(name, value, ec))
return false;
}
field = value;
} else if constexpr (is_optional_v<T>) {
using V = optional_value_t<T>;
V value{};
if constexpr (std::is_same_v<V, bool>) {
if (!that_json->get_bool_ec(name, value, ec))
return false;
} else if constexpr (std::is_arithmetic_v<V> && !std::is_same_v<V, bool>) {
if (!that_json->get_number_ec(name, value, ec))
return false;
} else if constexpr (std::is_same_v<V, std::string>) {
if (!that_json->get_string_ec(name, value, ec))
return false;
} else if constexpr (std::is_enum_v<V>) {
std::string text;
if (!that_json->get_string_ec(name, text, ec))
return false;
value = Psc::to_enum<V>(text);
} else {
static_assert(!sizeof(T),
"assign_field does not support this optional type");
}
field = std::move(value);
} else {
static_assert(!sizeof(T), "assign_field does not support this type");
}
return true;
expected<void, std::error_code> try_assign_field(T& field,
const Psc::JSON* that_json,
const char* name) noexcept {
return detail::triple_api_expected_void(
[&field, that_json, name](std::error_code& ec) {
return assign_field_ec(field, that_json, name, ec);
});
}
template <typename T>
void output_field(const T &field, Psc::JSON &ret, const char *name) {
using C = clean_t<T>;
// bool
if constexpr (std::is_same_v<C, bool>) {
ret.append(Psc::JSON(name, field));
}
// 数字(排除 bool
else if constexpr (std::is_arithmetic_v<C> && !std::is_same_v<C, bool>) {
ret.append(Psc::JSON(name, field));
}
// string
else if constexpr (std::is_same_v<C, std::string>) {
ret.append(Psc::JSON(name, field));
}
// enum
else if constexpr (std::is_enum_v<C>) {
ret.append(Psc::JSON(name, Psc::to_string(field)));
}
// atomic<T>
else if constexpr (is_atomic_v<T>) {
ret.append(Psc::JSON(name, field.load()));
}
// optional<T>
else if constexpr (is_optional_v<T>) {
using V = optional_value_t<T>;
if (field.has_value()) {
// --- optional<bool>
if constexpr (std::is_same_v<V, bool>) {
ret.append(Psc::JSON(name, field.value()));
}
// --- optional<number>
else if constexpr (std::is_arithmetic_v<V> && !std::is_same_v<V, bool>) {
ret.append(Psc::JSON(name, field.value()));
}
// --- optional<string>
else if constexpr (std::is_same_v<V, std::string>) {
ret.append(Psc::JSON(name, field.value()));
}
// --- optional<enum>
else if constexpr (std::is_enum_v<V>) {
ret.append(Psc::JSON(name, to_string(field.value())));
}
// --- optional<atomic>
else if constexpr (is_atomic_v<T>) {
ret.append(Psc::JSON(name, field.value().load()));
}
// --- optional<未知类型>(调试输出)
else {
ret.append(Psc::JSON(name, field.value().to_string()));
}
} else {
// optional 没值 → JSON null
ret.append(Psc::JSON(name, nullptr));
bool assign_field_ec(T& field, const Psc::JSON* that_json, const char* name,
std::error_code& ec) noexcept {
using C = clean_t<T>;
if (that_json == nullptr) {
ec = std::make_error_code(std::errc::invalid_argument);
return false;
}
} else if constexpr (is_shared_ptr_v<C>) {
if (field) {
ret.append(Psc::JSON(name, field->to_string()));
} else {
ret.append(Psc::JSON(name, nullptr));
auto j = that_json->get(name);
if (j == nullptr) {
ec = std::make_error_code(std::errc::invalid_argument);
return false;
}
if constexpr (std::is_same_v<C, bool>) {
return j->bool_val_ec(field, ec);
}
else if constexpr (std::is_arithmetic_v<C> && !std::is_same_v<C, bool>) {
return that_json->get_number_ec(name, field, ec);
}
else if constexpr (std::is_same_v<C, std::string>) {
return that_json->get_string_ec(name, field, ec);
}
else if constexpr (std::is_enum_v<C>) {
std::string value;
if (!that_json->get_string_ec(name, value, ec))
return false;
field = Psc::to_enum<C>(value);
}
else if constexpr (is_atomic_v<T>) {
using V = atomic_value_t<T>;
V value{};
if constexpr (std::is_same_v<V, bool>) {
if (!that_json->get_bool_ec(name, value, ec))
return false;
}
else if constexpr (std::is_arithmetic_v<V>) {
if (!that_json->get_number_ec(name, value, ec))
return false;
}
field = value;
}
else if constexpr (is_copyable_atomic_v<T>) {
using V = copyable_atomic_value_t<T>;
V value{};
if constexpr (std::is_same_v<V, bool>) {
if (!that_json->get_bool_ec(name, value, ec)) {
return false;
}
}
else if constexpr (std::is_arithmetic_v<V>) {
if (!that_json->get_number_ec(name, value, ec)) {
return false;
}
}
field = value;
}
else if constexpr (is_optional_v<T>) {
using V = optional_value_t<T>;
V value{};
if constexpr (std::is_same_v<V, bool>) {
if (!that_json->get_bool_ec(name, value, ec))
return false;
}
else if constexpr (std::is_arithmetic_v<V> && !std::is_same_v<V, bool>) {
if (!that_json->get_number_ec(name, value, ec))
return false;
}
else if constexpr (std::is_same_v<V, std::string>) {
if (!that_json->get_string_ec(name, value, ec))
return false;
}
else if constexpr (std::is_enum_v<V>) {
std::string text;
if (!that_json->get_string_ec(name, text, ec))
return false;
value = Psc::to_enum<V>(text);
}
else {
static_assert(!sizeof(T),
"assign_field does not support this optional type");
}
field = std::move(value);
}
else {
static_assert(!sizeof(T), "assign_field does not support this type");
}
return true;
}
template <typename T>
void output_field(const T& field, Psc::JSON& ret, const char* name) {
using C = clean_t<T>;
// bool
if constexpr (std::is_same_v<C, bool>) {
ret.append(Psc::JSON(name, field));
}
// 数字(排除 bool
else if constexpr (std::is_arithmetic_v<C> && !std::is_same_v<C, bool>) {
ret.append(Psc::JSON(name, field));
}
// string
else if constexpr (std::is_same_v<C, std::string>) {
ret.append(Psc::JSON(name, field));
}
// enum
else if constexpr (std::is_enum_v<C>) {
ret.append(Psc::JSON(name, Psc::to_string(field)));
}
// atomic<T>
else if constexpr (is_atomic_v<T>) {
ret.append(Psc::JSON(name, field.load()));
}
else if constexpr (is_copyable_atomic_v<T>) {
ret.append(Psc::JSON(name, field.load()));
}
// optional<T>
else if constexpr (is_optional_v<T>) {
using V = optional_value_t<T>;
if (field.has_value()) {
// --- optional<bool>
if constexpr (std::is_same_v<V, bool>) {
ret.append(Psc::JSON(name, field.value()));
}
// --- optional<number>
else if constexpr (std::is_arithmetic_v<V> && !std::is_same_v<V, bool>) {
ret.append(Psc::JSON(name, field.value()));
}
// --- optional<string>
else if constexpr (std::is_same_v<V, std::string>) {
ret.append(Psc::JSON(name, field.value()));
}
// --- optional<enum>
else if constexpr (std::is_enum_v<V>) {
ret.append(Psc::JSON(name, to_string(field.value())));
}
// --- optional<atomic>
else if constexpr (is_atomic_v<T>) {
ret.append(Psc::JSON(name, field.value().load()));
}
// --- optional<未知类型>(调试输出)
else {
ret.append(Psc::JSON(name, field.value().to_string()));
}
}
else {
// optional 没值 → JSON null
ret.append(Psc::JSON(name, nullptr));
}
}
else if constexpr (is_shared_ptr_v<C>) {
if (field) {
ret.append(Psc::JSON(name, field->to_string()));
}
else {
ret.append(Psc::JSON(name, nullptr));
}
}
// 最终兜底
else {
ret.append(Psc::JSON(name, field.to_string()));
}
}
// 最终兜底
else {
ret.append(Psc::JSON(name, field.to_string()));
}
}
void check_json_assign_field(bool ok, const std::error_code &ec,
const Psc::JSON *that_json, const char *name);
} // namespace Psc
#undef Json_GET
#define Get_J(FIELD) \
{ \
#define Get_J_ex(NAME, FIELD) \
{ \
std::error_code ec_##FIELD; \
const bool ok_##FIELD = \
Psc::assign_field_ec(FIELD, that_json, #FIELD, ec_##FIELD); \
Psc::check_json_assign_field(ok_##FIELD, ec_##FIELD, that_json, #FIELD); \
}
#define Ret_J(FIELD) \
{ \
Psc::output_field(FIELD, ret, #FIELD); \
}
Psc::assign_field_ec(FIELD, that_json, NAME, ec_##FIELD); \
Psc::check_json_assign_field(ok_##FIELD, ec_##FIELD, that_json, NAME); \
}
#define Ret_J_ex(NAME, FIELD) \
{ \
Psc::output_field(FIELD, ret, NAME); \
}
#define Get_J(FIELD) Get_J_ex(#FIELD, FIELD)
#define Ret_J(FIELD) Ret_J_ex(#FIELD, FIELD)
#define JSON_KV(P) {#P, (P)}
#define JSON_KV_1(P1) JSON_KV(P1)
#define JSON_KV_2(P1, P2) JSON_KV_1(P1), JSON_KV(P2)
@@ -491,7 +506,6 @@ void check_json_assign_field(bool ok, const std::error_code &ec,
JSON_KV_8(P1, P2, P3, P4, P5, P6, P7, P8), JSON_KV(P9)
#define JSON_KV_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \
JSON_KV_9(P1, P2, P3, P4, P5, P6, P7, P8, P9), JSON_KV(P10)
#define VAR_JSON_1(P1) Psc::JSON::object({JSON_KV_1(P1)})
#define VAR_JSON_2(P1, P2) Psc::JSON::object({JSON_KV_2(P1, P2)})
#define VAR_JSON_3(P1, P2, P3) Psc::JSON::object({JSON_KV_3(P1, P2, P3)})
@@ -508,4 +522,33 @@ void check_json_assign_field(bool ok, const std::error_code &ec,
#define VAR_JSON_9(P1, P2, P3, P4, P5, P6, P7, P8, P9) \
Psc::JSON::object({JSON_KV_9(P1, P2, P3, P4, P5, P6, P7, P8, P9)})
#define VAR_JSON_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10) \
Psc::JSON::object({JSON_KV_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)})
Psc::JSON::object({JSON_KV_10(P1, P2, P3, P4, P5, P6, P7, P8, P9, P10)})
#include "boost/pfr/core.hpp"
#include <boost/pfr/core_name.hpp>
#include <string_view>
#define PSC_TO_JSON \
[[nodiscard]] Psc::JSON to_base_json() const { \
Psc::JSON ret = Psc::JSON::object(); \
using T = std::remove_cv_t<std::remove_pointer_t<decltype(this)>>; \
boost::pfr::for_each_field(*this, [&, names = boost::pfr::names_as_array<T>(), i = std::size_t{}](const auto& field) mutable { \
Psc::output_field(field, ret, names[i++].data()); \
}); \
return ret; \
}
#define PSC_FROM_JSON \
void from_base_json(const Psc::JSON *that_json) { \
using T = std::remove_cv_t<std::remove_pointer_t<decltype(this)>>; \
boost::pfr::for_each_field(*this, [&, names = boost::pfr::names_as_array<T>(), i = std::size_t{}](auto& field) mutable { \
auto name = names[i++].data(); \
std::error_code ec; \
auto t = Psc::assign_field_ec(field, that_json, name, ec); \
Psc::check_json_assign_field(t, ec, that_json, name); \
}); \
}
#define PSC_USE_JSON \
PSC_TO_JSON \
PSC_FROM_JSON