5#include "qx/core/qx_core_export.h"
9#include <QJsonValueRef>
12#include <QJsonDocument>
26#define __QX_JSON_META_STRUCT_INSIDE(meta_tuple) \
27template <typename StructT> \
28 struct QxJsonMetaStructInside \
30 static inline constexpr auto memberMetadata() \
36#define __QX_JSON_META_STRUCT_OUTSIDE(self_type, meta_tuple) \
39 template <typename StructT> \
40 struct QxJsonMetaStructOutside<self_type, StructT> \
42 static inline constexpr auto memberMetadata() \
55#define QX_JSON_MEMBER(member) QxJsonPrivate::makeMemberMetadata<#member>(&StructT::member)
56#define QX_JSON_MEMBER_ALIASED(member, key) QxJsonPrivate::makeMemberMetadata<key>(&StructT::member)
58#define QX_JSON_STRUCT(...) __QX_JSON_META_STRUCT_INSIDE(std::make_tuple(QX_FOR_EACH_DELIM(QX_JSON_MEMBER, __VA_ARGS__)))
59#define QX_JSON_STRUCT_X(...) __QX_JSON_META_STRUCT_INSIDE(std::make_tuple(__VA_ARGS__))
61#define QX_JSON_STRUCT_OUTSIDE(Struct, ...) __QX_JSON_META_STRUCT_OUTSIDE(Struct, std::make_tuple(QX_FOR_EACH_DELIM(QX_JSON_MEMBER, __VA_ARGS__)))
62#define QX_JSON_STRUCT_OUTSIDE_X(Struct, ...) __QX_JSON_META_STRUCT_OUTSIDE(Struct, std::make_tuple(__VA_ARGS__))
72#define QX_JSON_MEMBER_OVERRIDE(Struct, member, ...) \
76 struct MemberOverrideCoverter<Struct, #member> \
92 File(
const QString& filename,
const QString& fileError = {});
93 File(
const QFile& docFile,
const QString& fileError = {});
94 File(
const QFileInfo& docFile,
const QString& fileError = {});
105 Data(
const QString& dataError = {});
159using ContextNode = std::variant<File, Data, Document, Object, ObjectKey, Array, ArrayElement>;
166class QX_CORE_EXPORT
JsonError final :
public AbstractError<"Qx::JsonError", 5>
186 static inline const QHash<Form, QString> ERR_STRINGS{
188 {MissingKey, u
"The key does not exist."_s},
189 {TypeMismatch, u
"Value type mismatch."_s},
190 {EmptyDoc, u
"The document is empty."_s},
191 {InvalidValue, u
"Invalid value for type."_s},
192 {InvalidData, u
"Data parse error."_s},
193 {MissingFile, u
"File does not exist."_s},
194 {InaccessibleFile, u
"Cannot open the file."_s},
195 {FileReadError, u
"File read error."_s},
196 {FileWriteError, u
"File write error."_s}
203 QList<QxJson::ContextNode> mContext;
208 JsonError(
const QString& a, Form f);
212 quint32 deriveValue()
const override;
213 QString derivePrimary()
const override;
214 QString deriveSecondary()
const override;
215 QString deriveDetails()
const override;
218 bool isValid()
const;
219 QString action()
const;
221 QList<QxJson::ContextNode> context()
const;
233template<
class Struct, Qx::CStringLiteral member>
234struct MemberOverrideCoverter;
236template<
typename SelfType,
typename DelayedSelfType>
237struct QxJsonMetaStructOutside;
246 T::template QxJsonMetaStructInside<T>::memberMetadata();
251 QxJsonMetaStructOutside<T, T>::memberMetadata();
264template<
class K,
typename T, Qx::CStringLiteral N>
266 { MemberOverrideCoverter<K, N>::fromJson(tValue, QJsonValue()) } -> std::same_as<Qx::JsonError>;
267 { MemberOverrideCoverter<K, N>::toJson(tValue) } ->
qjson_type;
270template<
typename Key,
class Value>
273template<
typename Key,
class Value>
298namespace QxJsonPrivate
301static inline const QString ERR_CONV_TYPE = u
"JSON Error: Converting value to %1"_s;
302static inline const QString ERR_NO_KEY = u
"JSON Error: Could not retrieve key '%1'."_s;
303static inline const QString ERR_PARSE_DOC = u
"JSON Error: Could not parse JSON document."_s;
304static inline const QString ERR_READ_FILE = u
"JSON Error: Could not read JSON file."_s;
305static inline const QString ERR_READ_DATA = u
"JSON Error: Could not read JSON data."_s;
306static inline const QString ERR_WRITE_FILE = u
"JSON Error: Could not write JSON file."_s;
309template<Qx::CStringLiteral MemberN,
typename MemberT,
class Struct>
313 typedef MemberT M_TYPE;
314 MemberT Struct::* mPtr;
318template <Qx::CStringLiteral N,
typename T,
class S>
319constexpr MemberMetadata<N, T, S> makeMemberMetadata(T S::*memberPtr)
324template<
typename T> [[maybe_unused]]
static inline QString typeString() =
delete;
325template<
typename T> [[maybe_unused]]
static inline bool isType(
const QJsonValue& v) =
delete;
326template<
typename T> [[maybe_unused]]
static inline T toType(
const QJsonValue& v) =
delete;
328template<>
inline QString typeString<bool>() {
return u
"bool"_s; };
329template<>
inline QString typeString<double>() {
return u
"double"_s; };
330template<>
inline QString typeString<QString>() {
return u
"string"_s; };
331template<>
inline QString typeString<QJsonArray>() {
return u
"array"_s; };
332template<>
inline QString typeString<QJsonObject>() {
return u
"object"_s; };
334template<>
inline bool isType<bool>(
const QJsonValue& v) {
return v.isBool(); };
335template<>
inline bool isType<double>(
const QJsonValue& v) {
return v.isDouble(); };
336template<>
inline bool isType<QString>(
const QJsonValue& v) {
return v.isString(); };
337template<>
inline bool isType<QJsonArray>(
const QJsonValue& v) {
return v.isArray(); };
338template<>
inline bool isType<QJsonObject>(
const QJsonValue& v) {
return v.isObject(); };
340template<>
inline bool toType<bool>(
const QJsonValue& v) {
return v.toBool(); };
341template<>
inline double toType<double>(
const QJsonValue& v) {
return v.toDouble(); };
342template<>
inline QString toType<QString>(
const QJsonValue& v) {
return v.toString(); };
343template<>
inline QJsonArray toType<QJsonArray>(
const QJsonValue& v) {
return v.toArray(); };
344template<>
inline QJsonObject toType<QJsonObject>(
const QJsonValue& v) {
return v.toObject(); };
367 requires QxJson::json_struct_inside<K>
368constexpr auto getMemberMeta()
370 return K::template QxJsonMetaStructInside<K>::memberMetadata();
374 requires QxJson::json_struct_outside<K>
375constexpr auto getMemberMeta()
377 return QxJson::QxJsonMetaStructOutside<K, K>::memberMetadata();
380template<
class K,
typename T, Qx::CStringLiteral N>
381 requires QxJson::json_override_convertible<K, T, N>
382Qx::JsonError overrideParse(T& value,
const QJsonValue& jv)
384 return QxJson::MemberOverrideCoverter<K, N>::fromJson(value, jv);
387template<
class K,
typename T, Qx::CStringLiteral N>
388 requires QxJson::json_override_convertible<K, T, N>
389auto overrideSerialize(
const T& value)
391 return QxJson::MemberOverrideCoverter<K, N>::toJson(value);
395 requires QxJson::json_convertible<T>
396Qx::JsonError standardParse(T& value,
const QJsonValue& jv)
398 return QxJson::Converter<T>::fromJson(value, jv);
402 requires QxJson::json_convertible<T>
403auto standardSerialize(
const T& value)
405 return QxJson::Converter<T>::toJson(value);
420 static Qx::JsonError fromJson(T& value,
const QJsonValue& jValue)
422 if(!QxJsonPrivate::isType<T>(jValue))
425 value = QxJsonPrivate::toType<T>(jValue);
426 return Qx::JsonError();
429 static T toJson(
const T& value)
444 static Qx::JsonError fromJson(T& value,
const QJsonValue& jValue)
446 if(!jValue.isObject())
448 .withContext(QxJson::Object());
451 QJsonObject jObject = jValue.toObject();
454 Qx::JsonError cnvError;
457 constexpr auto memberMetas = QxJsonPrivate::getMemberMeta<T>();
463 std::apply([&](
auto&&... memberMeta)
constexpr {
467 static constexpr auto mName = std::remove_reference<
decltype(memberMeta)>::type::M_NAME;
468 constexpr QLatin1StringView mKey(mName);
469 using mType =
typename std::remove_reference<
decltype(memberMeta)>::type::M_TYPE;
470 auto& mRef = value.*(memberMeta.mPtr);
473 if(!jObject.contains(mKey))
475 if constexpr(json_optional<mType>)
487 QJsonValue mValue = jObject.value(mKey);
490 if constexpr(json_override_convertible<T, mType, mName>)
491 cnvError = QxJsonPrivate::overrideParse<T, mType, mName>(mRef, mValue);
493 cnvError = QxJsonPrivate::standardParse<mType>(mRef, mValue);
503 static QJsonObject toJson(
const T& value)
509 constexpr auto memberMetas = QxJsonPrivate::getMemberMeta<T>();
512 std::apply([&](
auto&&... memberMeta)
constexpr {
516 static constexpr auto mName = std::remove_reference<
decltype(memberMeta)>::type::M_NAME;
517 constexpr QLatin1StringView mKey(mName);
518 using mType =
typename std::remove_reference<
decltype(memberMeta)>::type::M_TYPE;
519 auto& mRef = value.*(memberMeta.mPtr);
522 if constexpr(json_optional<mType>)
529 if constexpr(json_override_convertible<T, mType, mName>)
530 jObject.insert(mKey, QxJsonPrivate::overrideSerialize<T, mType, mName>(mRef));
532 jObject.insert(mKey, QxJsonPrivate::standardSerialize<mType>(mRef));
544 using E =
typename T::value_type;
546 static Qx::JsonError fromJson(T& value,
const QJsonValue& jValue)
551 if(!jValue.isArray())
554 .withContext(QxJson::Array());
558 QJsonArray jArray = jValue.toArray();
561 Qx::JsonError cnvError;
564 for(
auto i = 0; i < jArray.count(); ++i)
567 if(cnvError = Converter<E>::fromJson(converted, jArray[i]); cnvError.
isValid())
576 return Qx::JsonError();
579 static QJsonArray toJson(
const T& value)
585 for(
const E& e : value)
588 if constexpr(json_optional<E>)
594 jArray.append(Converter<E>::toJson(e));
605 using K =
typename T::key_type;
606 using V =
typename T::mapped_type;
608 static Qx::JsonError fromJson(T& value,
const QJsonValue& jValue)
613 if(!jValue.isArray())
616 .withContext(QxJson::Array());
619 QJsonArray jArray = jValue.toArray();
622 Qx::JsonError cnvError;
625 for(
auto i = 0; i < jArray.count(); ++i)
628 if(cnvError = Converter<V>::fromJson(converted, jArray[i]); cnvError.
isValid())
637 return Qx::JsonError();
640 static QJsonArray toJson(
const T& value)
646 for(
const V& v : value)
649 if constexpr(json_optional<V>)
655 jArray.append(Converter<V>::toJson(v));
666 using O =
typename T::value_type;
668 static Qx::JsonError fromJson(T& value,
const QJsonValue& jValue)
671 Qx::JsonError je = Converter<O>::fromJson(opt, jValue);
674 value = std::move(opt);
679 static auto toJson(
const T& value)
682 return Converter<O>::toJson(*value);
687 requires std::integral<T> && (!std::same_as<T, bool>)
690 static Qx::JsonError fromJson(T& value,
const QJsonValue& jValue)
692 if(!jValue.isDouble())
695 value =
static_cast<T
>(jValue.toDouble());
696 return Qx::JsonError();
699 static double toJson(
const T& value)
701 return static_cast<double>(value);
721 static inline const QString OFFSET_STR = u
"Position: %1."_s;
725 const QJsonParseError& mErrorRef;
735 quint32 deriveValue()
const override;
736 QString derivePrimary()
const override;
737 QString deriveSecondary()
const override;
746 QJsonValue objAsValue(obj);
763 QJsonValue arrayAsValue(array);
776 requires json_root<T>
799 requires json_root<T>
806 requires json_root<T>
815 QJsonDocument jd = QJsonDocument::fromJson(data, &jpe);
817 if(jpe.error != jpe.NoError)
825 requires json_root<T>
826void serializeJson(QByteArray& serialized,
const T& root, QJsonDocument::JsonFormat fmt = QJsonDocument::Indented)
836 serialized = jd.toJson(fmt);
840 requires json_root<T>
851 if(!file.open(QIODevice::ReadOnly))
855 QScopeGuard fileGuard([&file]{ file.close(); });
858 QByteArray jsonData = file.readAll();
859 if(jsonData.isEmpty())
861 if(file.error() != QFileDevice::NoError)
869 QJsonDocument jd = QJsonDocument::fromJson(jsonData, &jpe);
871 if(jpe.error != jpe.NoError)
879 requires json_root<T>
883 if(serialized.isOpen())
886 if(!serialized.open(QIODevice::Truncate | QIODevice::WriteOnly))
890 QScopeGuard fileGuard([&serialized]{ serialized.close(); });
895 if(serialized.write(jsonData) != jsonData.size())
902 requires json_root<T>
905 QFile file(filePath);
911 requires json_root<T>
912JsonError serializeJson(
const QString& serializedPath,
const T& root, QJsonDocument::JsonFormat fmt = QJsonDocument::Indented)
914 QFile file(serializedPath);
919QX_CORE_EXPORT QList<QJsonValue>
findAllValues(
const QJsonValue& rootValue, QStringView key);
920QX_CORE_EXPORT QString
asString(
const QJsonValue& value);
QString string() const
Definition qx-json.cpp:629
ArrayElement(uint element)
Definition qx-json.cpp:624
Array()
Definition qx-json.cpp:604
QString string() const
Definition qx-json.cpp:609
The document class represents a JSON data node for use in error contexts.
Definition qx-json.h:100
QString string() const
Definition qx-json.cpp:522
Data(const QString &dataError={})
Definition qx-json.cpp:515
The document class represents a JSON document node for use in error contexts.
Definition qx-json.h:111
QString string() const
Definition qx-json.cpp:549
Document(const QString &name={})
Definition qx-json.cpp:544
The file class represents a JSON file node for use in error contexts.
Definition qx-json.h:86
File(const QString &filename, const QString &fileError={})
Definition qx-json.cpp:466
QString string() const
Definition qx-json.cpp:492
ObjectKey(const QString &name)
Definition qx-json.cpp:584
QString string() const
Definition qx-json.cpp:589
QString string() const
Definition qx-json.cpp:569
Object()
Definition qx-json.cpp:564
The AbstractError template class completes the Error interface and acts as the base class from which ...
Definition qx-abstracterror.h:88
The JsonError class is used to report errors related to JSON manipulation.
Definition qx-json.h:167
Form
Definition qx-json.h:171
@ MissingFile
Definition qx-json.h:178
@ NoError
Definition qx-json.h:172
@ EmptyDoc
Definition qx-json.h:175
@ InaccessibleFile
Definition qx-json.h:179
@ FileWriteError
Definition qx-json.h:181
@ FileReadError
Definition qx-json.h:180
@ InvalidValue
Definition qx-json.h:176
@ TypeMismatch
Definition qx-json.h:174
@ MissingKey
Definition qx-json.h:173
JsonError & withContext(const QxJson::ContextNode &node)
Definition qx-json.cpp:220
JsonError()
Definition qx-json.cpp:156
bool isValid() const
Definition qx-json.cpp:189
Allows QJsonParseError to be used via the Qx::Error interface.
Definition qx-json.h:718
QJsonParseErrorAdapter(const QJsonParseError &e)
Definition qx-json.cpp:249
Specifies that a type is an associative container, the value type of which is convertible,...
Definition qx-json.h:283
Specifies that a type is a non-associative container, the value type of which is convertible to/from ...
Definition qx-json.h:279
Specifies that a type is a container, and abides by the other corresponding restrictions for that kin...
Definition qx-json.h:288
Specifies that a type is generally convertible to/from JSON.
Definition qx-json.h:259
Specifies that a type has a known method for creating a corresponding key.
Definition qx-json.h:274
Specifies that a type is a specialization of std::optional that manages values of a JSON convertible ...
Definition qx-json.h:292
Specifies that a type has override conversions for changing to/from JSON.
Definition qx-json.h:265
Specifies that a type is a JSON-tied struct registered with QX_JSON_STRUCT().
Definition qx-json.h:245
Specifies that a type is a JSON-tied struct registered with QX_JSON_STRUCT_OUTSIDE().
Definition qx-json.h:250
Specifies that a type is a JSON-tied struct.
Definition qx-json.h:255
Specifies that a type is one of the fundamental JSON types within Qt's JSON system.
Definition qx-json.h:242
Specifies that a type is one of several types.
Definition qx-concepts.h:509
Specifies that a type is a valid analogue for a JSON document root element.
Definition qx-json.h:713
Specifies that a type is a Qt-based associative container type.
Definition qx-concepts.h:520
Specifies that a type is a Qt-based collection type.
Definition qx-concepts.h:524
Specifies that a type is a specialization of a template.
Definition qx-concepts.h:513
The QxJson namespace encapsulates the user-extensible implementation of Qx's JSON parsing facilities.
Definition qx-json.cpp:440
std::variant< File, Data, Document, Object, ObjectKey, Array, ArrayElement > ContextNode
Definition qx-json.h:159
Key keygen(const Value &value)=delete
The keygen template function acts as an interface through which the derivation of a key for a given t...
The Qx namespace is the main namespace through which all non-global functionality of the Qx library i...
Definition qx-abstracterror.cpp:13
void serializeJson(QJsonObject &serialized, const T &struc)
Definition qx-json.h:753
QString asString(const QJsonValue &value)
Definition qx-json.cpp:414
JsonError parseJson(T &parsed, const QJsonObject &obj)
Definition qx-json.h:743
QList< QJsonValue > findAllValues(const QJsonValue &rootValue, QStringView key)
Definition qx-json.cpp:402
The qx-abstracterror.h header file provides access to the base class from which custom error types sh...
The qx-concepts header file provides a library of general purpose concepts as an extension of the sta...
The qx-error.h header file provides access to the Error interface.
#define QX_DECLARE_ERROR_ADAPTATION(Adaptable, Adapter)
Definition qx-error.h:164
The qx-concepts header file provides a set of various object-like and function-like macros that are d...
The Converter template struct acts as an interface that carries details on how to parse/serialize JSO...
Definition qx-json.h:231
CStringLiteral acts like a typedef/alias for a StringLiteral that uses char as its storage type.
Definition qx-stringliteral.h:194