#pragma once #include "../system/export.h" #include "../Base/global_include.h" #include #include #include #include // std::numeric_limits #include #include #include #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) \ [[nodiscard]] type get_##name(const std::string &_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(const std::string& val, T_Number& out, std::error_code& ec) noexcept; template T_Number to_number(const std::string& 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(const std::string& 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(const std::string& 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 unsigned long long x = std::stoull(val); // 额外范围检查,避免静默截断 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 { long long x = std::stoll(val); // 额外范围检查,避免静默截断 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 long double x = std::stold(val); // 可选:检查是否超出目标浮点类型范围 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(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 T_Number get_number(const std::string& 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(const std::string& 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(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 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 key, const JSON &body); template , JSON>>> JSON(std::string k, T&& v) { key = std::move(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; void append_list(const std::vector &arr); void append(const JSON &json); void prepend(const JSON &json); static JSON array(std::string key, const std::vector &arr); static JSON object(std::string 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(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; }; 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) { 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) { 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(); } } 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_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) { 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) { 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())); } } 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) { \ 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); #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) })