#pragma once #include "../Base/global_include.h" #include "../system/export.h" #include #include #include #include // std::numeric_limits #include #include #include #include #define PSC_JSON_KEY_PARAMS(M, SEP) M(std::string_view, key) #define PSC_JSON_PARSE_PARAMS(M, SEP) M(std::string_view, text) #define PSC_JSON_FILE_PARAMS(M, SEP) M(std::string_view, file_name) #undef max #undef min #define Json_GET(type, name) \ [[nodiscard]] type get_##name(std::string_view _key) const { \ const Psc::JSON *that = get(_key); \ if (!that) { \ std::cout << "get" #type " error json not found! key:" << _key \ << " json: " << to_json_string() << std::endl; \ return false; \ } \ return that->name##_val(); \ } #pragma once #include "../Base/global_include.h" #include #include #include #include namespace Psc { class json_assign_error final : public std::system_error { public: using std::system_error::system_error; }; enum JsonType : uint8_t { String, Object, Array, Null, Number, Bool }; template void assign_json(JsonType& rt, std::string& rv, T&& val); template bool to_number_ec(std::string_view val, T_Number& out, std::error_code& ec) noexcept; template T_Number to_number(std::string_view val) { return detail::triple_api_throwing( [&val](T_Number& out, std::error_code& ec) { return to_number_ec(val, out, ec); }, "to_number failed"); } template expected try_to_number(std::string_view val) noexcept { return detail::triple_api_expected( [&val](T_Number& out, std::error_code& ec) { return to_number_ec(val, out, ec); }); } template bool to_number_ec(std::string_view val, T_Number& out, std::error_code& ec) noexcept { ec.clear(); // 限定只支持整数/浮点,其他类型编译期报错(比运行时返回默认值更安全) static_assert(std::is_integral_v || std::is_floating_point_v, "to_number: T_Number must be an integral or " "floating-point type"); try { if constexpr (std::is_integral_v) { if constexpr (std::is_unsigned_v) { // stoull: 负号、非数字等会抛 invalid_argument;超范围抛 out_of_range auto text = std::string(val); unsigned long long x = std::stoull(text); // 额外范围检查,避免静默截断 if (x > static_cast( std::numeric_limits::max())) { ec = std::make_error_code(std::errc::result_out_of_range); return false; } out = static_cast(x); return true; } else { auto text = std::string(val); long long x = std::stoll(text); // 额外范围检查,避免静默截断 if (x < static_cast(std::numeric_limits::min()) || x > static_cast(std::numeric_limits::max())) { ec = std::make_error_code(std::errc::result_out_of_range); return false; } out = static_cast(x); return true; } } else { // floating point auto text = std::string(val); long double x = std::stold(text); // 可选:检查是否超出目标浮点类型范围 if (x < -static_cast(std::numeric_limits::max()) || x > static_cast(std::numeric_limits::max())) { ec = std::make_error_code(std::errc::result_out_of_range); return false; } out = static_cast(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; // 数值超范围 } } class JSON { public: static std::function handle_error; explicit operator std::string() const; friend std::ostream& operator<<(std::ostream& os, const JSON& obj); [[nodiscard]] bool has(std::string_view key) const; [[nodiscard]] const JSON* get(std::string_view 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 T_Number get_number(std::string_view key) const { return detail::triple_api_throwing( [this, &key](T_Number& out, std::error_code& ec) { return get_number_ec(key, out, ec); }, "get_number failed"); } template expected try_get_number(std::string_view key) const noexcept { return detail::triple_api_expected( [this, &key](T_Number& out, std::error_code& ec) { return get_number_ec(key, out, ec); }); } template bool get_number_ec(std::string_view 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 T_Number number_val() const { return detail::triple_api_throwing( [this](T_Number& out, std::error_code& ec) { return number_val_ec(out, ec); }, "number_val failed"); } template expected try_number_val() const noexcept { return detail::triple_api_expected( [this](T_Number& out, std::error_code& ec) { return number_val_ec(out, ec); }); } template 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_view key, const JSON& body); template , JSON>>> JSON(std::string_view k, T&& v) { key = std::string(k); assign_json(valueType, val, std::forward(v)); } template , JSON>>> JSON(T&& v) { assign_json(valueType, val, std::forward(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& arr); void append(const JSON& json); void prepend(const JSON& json); static JSON array(std::string_view key, const std::vector& arr); static JSON object(std::string_view key, const std::vector& children); static JSON array(const std::vector& arr = {}); static JSON object(const std::vector& children = {}); JsonType valueType = Null; std::string key, val; std::vector children; [[nodiscard]] std::string to_json_string(std::string_view object_split = "\n", std::string_view array_split = "\n", std::string_view indentStr = " ", const int& indent = 0) const; private: static std::string get_indent(const int& indent, std::string_view indentStr); void append_value_string(std::string& ret, const int& indent, bool isEnd, std::string_view object_split, std::string_view array_split, std::string_view 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 void assign_json(JsonType& rt, std::string& rv, T&& v) { using C = std::decay_t; if constexpr (std::is_same_v) { rt = String; rv = std::forward(v); } else if constexpr (std::is_same_v) { rt = String; rv = std::string(v); } else if constexpr (std::is_same_v) { std::stringstream ss; ss << "0x" << std::setw(sizeof(void*) * 2) << std::setfill('0') << std::hex << reinterpret_cast(v); rt = String; rv = ss.str(); } // 处理 char* 类型 else if constexpr (std::is_same_v) { rt = String; rv = std::string(v); } else if constexpr (std::is_same_v) { rt = String; rv = std::string(v); // 或 val = v; } // 处理 wchar_t* 类型 else if constexpr (std::is_same_v) { std::wstring ws(v); rt = String; rv = std::string(ws.begin(), ws.end()); } // 处理 std::wstring 类型 else if constexpr (std::is_same_v) { rt = String; rv = std::string(v.begin(), v.end()); } // 处理枚举类型 else if constexpr (std::is_enum_v) { rt = String; rv = std::string(magic_enum::enum_name(v)); } // 处理 bool 类型 else if constexpr (std::is_same_v) { rt = Bool; rv = v ? "true" : "false"; // 对 bool 类型进行自定义转换 } // 处理 std::nullptr_t 类型 else if constexpr (std::is_same_v) { rt = Null; rv = "null"; } else if constexpr (std::is_arithmetic_v) { rt = Number; rv = std::to_string(v); } else if constexpr (is_atomic_v || is_copyable_atomic_v) { assign_json(rt, rv, v.load()); } else if constexpr (is_optional_v) { 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 bool assign_field_ec(T& field, const Psc::JSON *that_json, const char *name, std::error_code& ec) noexcept; template 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 expected 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 bool assign_field_ec(T& field, const Psc::JSON *that_json, const char *name, std::error_code& ec) noexcept { using C = clean_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) { return j->bool_val_ec(field, ec); } else if constexpr (std::is_arithmetic_v && !std::is_same_v) { return that_json->get_number_ec(name, field, ec); } else if constexpr (std::is_same_v) { return that_json->get_string_ec(name, field, ec); } else if constexpr (std::is_enum_v) { std::string value; if (!that_json->get_string_ec(name, value, ec)) return false; field = Psc::to_enum(value); } else if constexpr (is_atomic_v) { using V = atomic_value_t; V value{}; if constexpr (std::is_same_v) { if (!that_json->get_bool_ec(name, value, ec)) return false; } else if constexpr (std::is_arithmetic_v) { if (!that_json->get_number_ec(name, value, ec)) return false; } field = value; } else if constexpr (is_copyable_atomic_v) { using V = copyable_atomic_value_t; V value{}; if constexpr (std::is_same_v) { if (!that_json->get_bool_ec(name, value, ec)) { return false; } } else if constexpr (std::is_arithmetic_v) { if (!that_json->get_number_ec(name, value, ec)) { return false; } } field = value; } else if constexpr (is_optional_v) { using V = optional_value_t; V value{}; if constexpr (std::is_same_v) { if (!that_json->get_bool_ec(name, value, ec)) return false; } else if constexpr (std::is_arithmetic_v && !std::is_same_v) { if (!that_json->get_number_ec(name, value, ec)) return false; } else if constexpr (std::is_same_v) { if (!that_json->get_string_ec(name, value, ec)) return false; } else if constexpr (std::is_enum_v) { std::string text; if (!that_json->get_string_ec(name, text, ec)) return false; value = Psc::to_enum(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 void output_field(const T& field, Psc::JSON& ret, const char *name) { using C = clean_t; // bool if constexpr (std::is_same_v) { ret.append(Psc::JSON(name, field)); } // 数字(排除 bool) else if constexpr (std::is_arithmetic_v && !std::is_same_v) { ret.append(Psc::JSON(name, field)); } // string else if constexpr (std::is_same_v) { ret.append(Psc::JSON(name, field)); } // enum else if constexpr (std::is_enum_v) { ret.append(Psc::JSON(name, Psc::to_string(field))); } // atomic else if constexpr (is_atomic_v || is_copyable_atomic_v) { ret.append(Psc::JSON(name, field.load())); } // optional else if constexpr (is_optional_v) { using V = optional_value_t; if (field.has_value()) { // --- optional if constexpr (std::is_same_v) { ret.append(Psc::JSON(name, field.value())); } // --- optional else if constexpr (std::is_arithmetic_v && !std::is_same_v) { ret.append(Psc::JSON(name, field.value())); } // --- optional else if constexpr (std::is_same_v) { ret.append(Psc::JSON(name, field.value())); } // --- optional else if constexpr (std::is_enum_v) { ret.append(Psc::JSON(name, to_string(field.value()))); } // --- optional else if constexpr (is_atomic_v || is_copyable_atomic_v) { 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) { 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())); } } } // namespace Psc #undef Json_GET #define Get_J_ex(NAME, FIELD) \ { \ std::error_code ec_##FIELD; \ const bool ok_##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) #define JSON_KV_3(P1, P2, P3) JSON_KV_2(P1, P2), JSON_KV(P3) #define JSON_KV_4(P1, P2, P3, P4) JSON_KV_3(P1, P2, P3), JSON_KV(P4) #define JSON_KV_5(P1, P2, P3, P4, P5) JSON_KV_4(P1, P2, P3, P4), JSON_KV(P5) #define JSON_KV_6(P1, P2, P3, P4, P5, P6) \ JSON_KV_5(P1, P2, P3, P4, P5), JSON_KV(P6) #define JSON_KV_7(P1, P2, P3, P4, P5, P6, P7) \ JSON_KV_6(P1, P2, P3, P4, P5, P6), JSON_KV(P7) #define JSON_KV_8(P1, P2, P3, P4, P5, P6, P7, P8) \ JSON_KV_7(P1, P2, P3, P4, P5, P6, P7), JSON_KV(P8) #define JSON_KV_9(P1, P2, P3, P4, P5, P6, P7, P8, P9) \ 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)}) #define VAR_JSON_4(P1, P2, P3, P4) \ Psc::JSON::object({JSON_KV_4(P1, P2, P3, P4)}) #define VAR_JSON_5(P1, P2, P3, P4, P5) \ Psc::JSON::object({JSON_KV_5(P1, P2, P3, P4, P5)}) #define VAR_JSON_6(P1, P2, P3, P4, P5, P6) \ Psc::JSON::object({JSON_KV_6(P1, P2, P3, P4, P5, P6)}) #define VAR_JSON_7(P1, P2, P3, P4, P5, P6, P7) \ Psc::JSON::object({JSON_KV_7(P1, P2, P3, P4, P5, P6, P7)}) #define VAR_JSON_8(P1, P2, P3, P4, P5, P6, P7, P8) \ Psc::JSON::object({JSON_KV_8(P1, P2, P3, P4, P5, P6, P7, P8)}) #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)}) #include "boost/pfr/core.hpp" #include #include #define PSC_TO_JSON \ [[nodiscard]] Psc::JSON to_base_json() const { \ Psc::JSON ret = Psc::JSON::object(); \ using T = std::remove_cv_t>; \ boost::pfr::for_each_field(*this, [&, names = boost::pfr::names_as_array(), 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>; \ boost::pfr::for_each_field(*this, [&, names = boost::pfr::names_as_array(), 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