#ifndef UTILS_JSON_H
#define UTILS_JSON_H
#include <QJsonObject>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonValue>
#include <QFile>
#include <QVariant>
#include <QString>
#include <functional>
#include <cstddef>
#include <QSaveFile>
#include <type_traits>
#include <algorithm> // for std::min if needed, though qMin is Qt
namespace Utils {
namespace JsonSerialize {
// --- 数组转换 ---
template< typename T, std::size_t N >
inline QJsonArray ToJsonArray(const T(&arr)[N]) {
QJsonArray result;
for (std::size_t i = 0; i < N; ++i) {
result.append(QJsonValue(arr[i]));
}
return result;
}
template<typename T, std::size_t N>
inline void FromJsonArray(const QJsonArray& jarr, T(&arr)[N]) {
const int len = std::min(static_cast<int>(jarr.size()), static_cast<int>(N));
for (int i = 0; i < len; ++i) {
arr[i] = static_cast<T>(jarr[i].toDouble());
}
}
template <std::size_t N>
inline void FromJsonArray(const QJsonArray& jarr, int(&arr)[N]) {
const int len = std::min(static_cast<int>(N), jarr.size());
for (int i = 0; i < len; ++i)
arr[i] = jarr[i].toInt();
}
// --- 基础类型 jsonField (Write) ---
inline void jsonField(QJsonObject& obj, const char* key, int val) {
obj[key] = val;
}
inline void jsonField(QJsonObject& obj, const char* key, float val) {
obj[key] = static_cast<double>(val);
}
inline void jsonField(QJsonObject& obj, const char* key, bool val) {
obj[key] = val;
}
inline void jsonField(QJsonObject& obj, const char* key, unsigned char val) {
obj[key] = static_cast<int>(val);
}
template <typename T, std::size_t N>
inline void jsonField(QJsonObject& obj, const char* key, const T(&arr)[N]) {
obj[key] = ToJsonArray(arr);
}
// --- 基础类型 jsonField (Read) ---
inline void jsonField(const QJsonObject& obj, const char* key, int& val) {
if (obj.contains(key)) val = obj[key].toInt();
}
inline void jsonField(const QJsonObject& obj, const char* key, float& val) {
if (obj.contains(key)) val = static_cast<float>(obj[key].toDouble());
}
inline void jsonField(const QJsonObject& obj, const char* key, bool& val) {
if (obj.contains(key)) val = obj[key].toBool();
}
inline void jsonField(const QJsonObject& obj, const char* key, unsigned char& val) {
if (obj.contains(key)) val = static_cast<unsigned char>(obj[key].toInt());
}
template <typename T, std::size_t N>
inline void jsonField(const QJsonObject& obj, const char* key, T(&arr)[N]) {
if (obj.contains(key)) FromJsonArray(obj[key].toArray(), arr);
}
// --- 辅助宏 ---
/**
* @brief 安全地去除 m_ 前缀
*/
inline const char* StripM_(const char* s) {
if (!s) return s;
// 检查 "m_" 前缀
if (s[0] == 'm' && s[1] == '_') {
return s + 2;
}
return s;
}
/**
* @brief 字段宏:依赖上下文中的 obj (QJsonObject) 和 p (Struct&)
*/
#define JF(member) jsonField(obj, StripM_(#member), p.member);
/**
* @brief 嵌套对象支持宏
*/
#define JSON_NESTED(Type) \
inline void jsonField(QJsonObject &obj, const char *key, const Type &val) { \
obj[key] = ToJson(val); \
} \
inline void jsonField(const QJsonObject &obj, const char *key, Type &val) { \
if (obj.contains(key)) \
FromJson(obj[key].toObject(), val); \
}
/**
* @brief 定义序列化/反序列化函数
*/
#define DEFINE_JSON(Type, ...) \
inline QJsonObject ToJson(const Type &p) { \
QJsonObject obj; \
__VA_ARGS__ \
return obj; \
} \
inline void FromJson(const QJsonObject &obj, Type &p) { \
__VA_ARGS__ \
} \
JSON_NESTED(Type)
// --- SFINAE 检测 ---
template <typename T, typename = void>
struct has_to_json : std::false_type {};
template<typename T>
struct has_to_json<T, std::void_t< decltype(ToJson(std::declval<const T&>())) >> : std::true_type {};
template<typename T>
constexpr bool has_to_json_v = has_to_json<T>::value;
template <typename T, typename = void>
struct has_from_json : std::false_type {};
template<typename T>
struct has_from_json<T, std::void_t< decltype(FromJson(std::declval<const QJsonObject&>(), std::declval<T&>())) >> : std::true_type {};
template<typename T>
constexpr bool has_from_json_v = has_from_json<T>::value;
// --- 文件 IO ---
template <typename T, std::enable_if_t<has_to_json_v<T>, int> = 0>
bool SaveToFile(const T& obj, const QString& filepath) {
QSaveFile file(filepath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
return false;
}
QJsonDocument doc(ToJson(obj));
qint64 written = file.write(doc.toJson(QJsonDocument::Indented));
if (!file.commit()) {
return false;
}
return written > 0;
}
template <typename T, std::enable_if_t<has_from_json_v<T>, int> = 0>
bool LoadFromFile(T& param, const QString& filePath) {
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return false;
QByteArray raw = file.readAll();
file.close();
if (raw.isEmpty()) {
return false;
}
QJsonParseError err;
QJsonDocument doc = QJsonDocument::fromJson(raw, &err);
if (err.error != QJsonParseError::NoError || !doc.isObject())
return false;
FromJson(doc.object(), param);
return true;
}
} // namespace JsonSerialize
} // namespace Utils
#endif // UTILS_JSON_H