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> \
156using ContextNode = std::variant<File, Data, Document, Object, ObjectKey, Array, ArrayElement>;
185 {MissingKey, u
"The key does not exist."_s},
186 {TypeMismatch, u
"Value type mismatch."_s},
187 {EmptyDoc, u
"The document is empty."_s},
188 {InvalidValue, u
"Invalid value for type."_s},
189 {InvalidData, u
"Data parse error."_s},
190 {MissingFile, u
"File does not exist."_s},
191 {InaccessibleFile, u
"Cannot open the file."_s},
192 {FileReadError, u
"File read error."_s},
193 {FileWriteError, u
"File write error."_s}
205 JsonError(
const QString& a, Form f);
209 quint32 deriveValue()
const override;
210 QString derivePrimary()
const override;
211 QString deriveSecondary()
const override;
212 QString deriveDetails()
const override;
215 bool isValid()
const;
230template<
class Struct, Qx::StringLiteral member>
231struct MemberOverrideCoverter;
233template<
typename SelfType,
typename DelayedSelfType>
234struct QxJsonMetaStructOutside;
243 T::template QxJsonMetaStructInside<T>::memberMetadata();
248 QxJsonMetaStructOutside<T, T>::memberMetadata();
257 { Converter<T>::fromJson(tValue,
QJsonValue()) } -> std::same_as<Qx::JsonError>;
258 { Converter<T>::toJson(tValue) } ->
qjson_type;
261template<
class K,
typename T, Qx::StringLiteral N>
262concept json_override_convertible =
requires(T& tValue) {
263 { MemberOverrideCoverter<K, N>::fromJson(tValue,
QJsonValue()) } -> std::same_as<Qx::JsonError>;
264 { MemberOverrideCoverter<K, N>::toJson(tValue) } -> qjson_type;
267template<
typename Key,
class Value>
270template<
typename Key,
class Value>
272 { keygen<Key, Value>(v) } -> std::same_as<Key>;
295namespace QxJsonPrivate
298static inline const QString ERR_CONV_TYPE = u
"JSON Error: Converting value to %1"_s;
299static inline const QString ERR_NO_KEY = u
"JSON Error: Could not retrieve key '%1'."_s;
300static inline const QString ERR_PARSE_DOC = u
"JSON Error: Could not parse JSON document."_s;
301static inline const QString ERR_READ_FILE = u
"JSON Error: Could not read JSON file."_s;
302static inline const QString ERR_READ_DATA = u
"JSON Error: Could not read JSON data."_s;
303static inline const QString ERR_WRITE_FILE = u
"JSON Error: Could not write JSON file."_s;
306template<Qx::StringLiteral MemberN,
typename MemberT,
class Struct>
310 typedef MemberT M_TYPE;
311 MemberT Struct::* mPtr;
315template <Qx::StringLiteral N,
typename T,
class S>
316constexpr MemberMetadata<N, T, S> makeMemberMetadata(T S::*memberPtr)
321template<
typename T> [[maybe_unused]]
static inline QString typeString() =
delete;
322template<
typename T> [[maybe_unused]]
static inline bool isType(
const QJsonValue& v) =
delete;
323template<
typename T> [[maybe_unused]]
static inline T toType(
const QJsonValue& v) =
delete;
325template<>
inline QString typeString<bool>() {
return u
"bool"_s; };
326template<>
inline QString typeString<double>() {
return u
"double"_s; };
327template<>
inline QString typeString<QString>() {
return u
"string"_s; };
328template<>
inline QString typeString<QJsonArray>() {
return u
"array"_s; };
329template<>
inline QString typeString<QJsonObject>() {
return u
"object"_s; };
331template<>
inline bool isType<bool>(
const QJsonValue& v) {
return v.
isBool(); };
334template<>
inline bool isType<QJsonArray>(
const QJsonValue& v) {
return v.
isArray(); };
335template<>
inline bool isType<QJsonObject>(
const QJsonValue& v) {
return v.
isObject(); };
337template<>
inline bool toType<bool>(
const QJsonValue& v) {
return v.
toBool(); };
365constexpr auto getMemberMeta()
367 return K::template QxJsonMetaStructInside<K>::memberMetadata();
372constexpr auto getMemberMeta()
374 return QxJson::QxJsonMetaStructOutside<K, K>::memberMetadata();
377template<
class K,
typename T, Qx::StringLiteral N>
378 requires QxJson::json_override_convertible<K, T, N>
381 return QxJson::MemberOverrideCoverter<K, N>::fromJson(value, jv);
384template<
class K,
typename T, Qx::StringLiteral N>
385 requires QxJson::json_override_convertible<K, T, N>
386auto overrideSerialize(
const T& value)
388 return QxJson::MemberOverrideCoverter<K, N>::toJson(value);
400auto standardSerialize(
const T& value)
414 requires qjson_type<T>
419 if(!QxJsonPrivate::isType<T>(jValue))
422 value = QxJsonPrivate::toType<T>(jValue);
426 static T toJson(
const T& value)
438 requires json_struct<T>
454 constexpr auto memberMetas = QxJsonPrivate::getMemberMeta<T>();
460 std::apply([&](
auto&&... memberMeta)
constexpr {
464 static constexpr auto mName = std::remove_reference<
decltype(memberMeta)>::type::M_NAME;
466 using mType =
typename std::remove_reference<
decltype(memberMeta)>::type::M_TYPE;
467 auto& mRef = value.*(memberMeta.mPtr);
472 if constexpr(json_optional<mType>)
487 if constexpr(json_override_convertible<T, mType, mName>)
488 cnvError = QxJsonPrivate::overrideParse<T, mType, mName>(mRef, mValue);
490 cnvError = QxJsonPrivate::standardParse<mType>(mRef, mValue);
506 constexpr auto memberMetas = QxJsonPrivate::getMemberMeta<T>();
509 std::apply([&](
auto&&... memberMeta)
constexpr {
513 static constexpr auto mName = std::remove_reference<
decltype(memberMeta)>::type::M_NAME;
515 using mType =
typename std::remove_reference<
decltype(memberMeta)>::type::M_TYPE;
516 auto& mRef = value.*(memberMeta.mPtr);
519 if constexpr(json_optional<mType>)
526 if constexpr(json_override_convertible<T, mType, mName>)
527 jObject.
insert(mKey, QxJsonPrivate::overrideSerialize<T, mType, mName>(mRef));
529 jObject.
insert(mKey, QxJsonPrivate::standardSerialize<mType>(mRef));
538 requires json_collective<T>
541 using E =
typename T::value_type;
561 for(
auto i = 0; i < jArray.
count(); ++i)
564 if(cnvError = Converter<E>::fromJson(converted, jArray[i]); cnvError.
isValid())
582 for(
const E& e : value)
585 if constexpr(json_optional<E>)
591 jArray.
append(Converter<E>::toJson(e));
599 requires json_associative<T>
602 using K =
typename T::key_type;
603 using V =
typename T::mapped_type;
622 for(
auto i = 0; i < jArray.
count(); ++i)
625 if(cnvError = Converter<V>::fromJson(converted, jArray[i]); cnvError.
isValid())
631 value.insert(keygen<K, V>(converted), converted);
643 for(
const V& v : value)
646 if constexpr(json_optional<V>)
652 jArray.
append(Converter<V>::toJson(v));
660 requires json_optional<T>
663 using O =
typename T::value_type;
671 value = std::move(opt);
676 static auto toJson(
const T& value)
679 return Converter<O>::toJson(*value);
684 requires std::integral<T> && (!std::same_as<T, bool>)
692 value =
static_cast<T
>(jValue.
toDouble());
696 static double toJson(
const T& value)
698 return static_cast<double>(value);
718 static inline const QString OFFSET_STR = u
"Position: %1."_s;
732 quint32 deriveValue()
const override;
733 QString derivePrimary()
const override;
734 QString deriveSecondary()
const override;
773 requires json_root<T>
796 requires json_root<T>
803 requires json_root<T>
822 requires json_root<T>
833 serialized = jd.
toJson(fmt);
837 requires json_root<T>
856 if(jsonData.isEmpty())
876 requires json_root<T>
892 if(serialized.
write(jsonData) != jsonData.size())
899 requires json_root<T>
902 QFile file(filePath);
908 requires json_root<T>
911 QFile file(serializedPath);
The array element key class represents a JSON Array element node for use in error contexts.
Definition qx-json.h:146
The array class represents a JSON array node for use in error contexts.
Definition qx-json.h:138
The document class represents a JSON data node for use in error contexts.
Definition qx-json.h:100
The document class represents a JSON document node for use in error contexts.
Definition qx-json.h:108
The file class represents a JSON file node for use in error contexts.
Definition qx-json.h:86
The object key class represents a JSON Object key node for use in error contexts.
Definition qx-json.h:127
The object class represents a JSON object node for use in error contexts.
Definition qx-json.h:119
The AbstractError template class completes the Error interface and acts as the base class from which ...
Definition qx-abstracterror.h:86
The JsonError class is used to report errors related to JSON manipulation.
Definition qx-json.h:164
Form
Definition qx-json.h:168
@ EmptyDoc
Definition qx-json.h:172
@ InaccessibleFile
Definition qx-json.h:176
@ InvalidValue
Definition qx-json.h:173
@ FileReadError
Definition qx-json.h:177
@ TypeMismatch
Definition qx-json.h:171
@ MissingKey
Definition qx-json.h:170
@ FileWriteError
Definition qx-json.h:178
@ MissingFile
Definition qx-json.h:175
JsonError & withContext(const QxJson::ContextNode &node)
Definition qx-json.cpp:220
bool isValid() const
Definition qx-json.cpp:189
Allows QJsonParseError to be used via the Qx::Error interface.
Definition qx-json.h:715
Specifies that a type is an associative container, the value type of which is convertible,...
Definition qx-json.h:280
Specifies that a type is a non-associative container, the value type of which is convertible to/from ...
Definition qx-json.h:276
Specifies that a type is a container, and abides by the other corresponding restrictions for that kin...
Definition qx-json.h:285
Specifies that a type is generally convertible to/from JSON.
Definition qx-json.h:256
Specifies that a type has a known method for creating a corresponding key.
Definition qx-json.h:271
Specifies that a type is a specialization of std::optional that manages values of a JSON convertible ...
Definition qx-json.h:289
Specifies that a type is a JSON-tied struct registered with QX_JSON_STRUCT().
Definition qx-json.h:242
Specifies that a type is a JSON-tied struct registered with QX_JSON_STRUCT_OUTSIDE().
Definition qx-json.h:247
Specifies that a type is a JSON-tied struct.
Definition qx-json.h:252
Specifies that a type is one of the fundamental JSON types within Qt's JSON system.
Definition qx-json.h:239
Specifies that a type is one of several types.
Definition qx-concepts.h:502
Specifies that a type is a valid analogue for a JSON document root element.
Definition qx-json.h:710
Specifies that a type is a Qt-based associative container type.
Definition qx-concepts.h:510
Specifies that a type is a Qt-based collection type.
Definition qx-concepts.h:514
Specifies that a type is a specialization of a template.
Definition qx-concepts.h:506
The QxJson namespace encapsulates the user-extensible implementation of Qx's JSON parsing facilities.
Definition qx-json.cpp:440
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...
std::variant< File, Data, Document, Object, ObjectKey, Array, ArrayElement > ContextNode
Definition qx-json.h:156
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:750
QString asString(const QJsonValue &value)
Definition qx-json.cpp:414
JsonError parseJson(T &parsed, const QJsonObject &obj)
Definition qx-json.h:740
QList< QJsonValue > findAllValues(const QJsonValue &rootValue, QStringView key)
Definition qx-json.cpp:402
bool isEmpty() const const
bool exists(const QString &fileName)
virtual QString fileName() const const override
bool open(FILE *fh, QIODeviceBase::OpenMode mode, QFileDevice::FileHandleFlags handleFlags)
virtual void close() override
QFileDevice::FileError error() const const
QString errorString() const const
bool isOpen() const const
qint64 write(const QByteArray &data)
void append(const QJsonValue &value)
qsizetype count() const const
QJsonArray array() const const
QJsonDocument fromJson(const QByteArray &json, QJsonParseError *error)
bool isArray() const const
bool isEmpty() const const
bool isObject() const const
QJsonObject object() const const
QByteArray toJson(QJsonDocument::JsonFormat format) const const
bool contains(QLatin1StringView key) const const
QJsonObject::iterator insert(QLatin1StringView key, const QJsonValue &value)
QJsonValue value(QLatin1StringView key) const const
QString errorString() const const
bool isArray() const const
bool isBool() const const
bool isDouble() const const
bool isObject() const const
bool isString() const const
QJsonArray toArray() const const
bool toBool(bool defaultValue) const const
double toDouble(double defaultValue) const const
QJsonObject toObject() const const
QString toString() const const
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:132
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:228
The StringLiteral template struct acts as a literal class type wrapper around a C-style string that e...
Definition qx-stringliteral.h:11