Skip to content

Commit d28760c

Browse files
committed
Allow format choice in, and add additional serializeJson overloads
1 parent aa74341 commit d28760c

File tree

2 files changed

+77
-17
lines changed

2 files changed

+77
-17
lines changed

lib/core/include/qx/core/qx-json.h

Lines changed: 53 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ class QX_CORE_EXPORT File
9696
QString string() const;
9797
};
9898

99+
class QX_CORE_EXPORT Data
100+
{
101+
public:
102+
Data();
103+
104+
QString string() const;
105+
};
106+
99107
class QX_CORE_EXPORT Document
100108
{
101109
private:
@@ -145,7 +153,7 @@ class QX_CORE_EXPORT ArrayElement
145153
QString string() const;
146154
};
147155

148-
using ContextNode = std::variant<File, Document, Object, ObjectKey, Array, ArrayElement>;
156+
using ContextNode = std::variant<File, Data, Document, Object, ObjectKey, Array, ArrayElement>;
149157

150158
} // namespace QxJson
151159

@@ -163,6 +171,7 @@ class QX_CORE_EXPORT JsonError final : public AbstractError<"Qx::JsonError", 5>
163171
TypeMismatch,
164172
EmptyDoc,
165173
InvalidValue,
174+
InvalidData,
166175
MissingFile,
167176
InaccessibleFile,
168177
FileReadError,
@@ -177,6 +186,7 @@ class QX_CORE_EXPORT JsonError final : public AbstractError<"Qx::JsonError", 5>
177186
{TypeMismatch, u"Value type mismatch."_s},
178187
{EmptyDoc, u"The document is empty."_s},
179188
{InvalidValue, u"Invalid value for type."_s},
189+
{InvalidData, u"Data parse error."_s},
180190
{MissingFile, u"File does not exist."_s},
181191
{InaccessibleFile, u"Cannot open the file."_s},
182192
{FileReadError, u"File read error."_s},
@@ -289,6 +299,7 @@ static inline const QString ERR_CONV_TYPE = u"JSON Error: Converting value to %1
289299
static inline const QString ERR_NO_KEY = u"JSON Error: Could not retrieve key '%1'."_s;
290300
static inline const QString ERR_PARSE_DOC = u"JSON Error: Could not parse JSON document."_s;
291301
static inline const QString ERR_READ_FILE = u"JSON Error: Could not read JSON file."_s;
302+
static inline const QString ERR_READ_DATA = u"JSON Error: Could not read JSON data."_s;
292303
static inline const QString ERR_WRITE_FILE = u"JSON Error: Could not write JSON file."_s;
293304

294305
//-Structs---------------------------------------------------------------
@@ -788,10 +799,45 @@ void serializeJson(QJsonDocument& serialized, const T& root)
788799
serialized = QJsonDocument(QxJson::Converter<T>::toJson(root));
789800
}
790801

802+
template<typename T>
803+
requires json_root<T>
804+
JsonError parseJson(T& parsed, const QByteArray& data)
805+
{
806+
// Check for no data
807+
if(data.isEmpty())
808+
return JsonError(QxJsonPrivate::ERR_READ_DATA, JsonError::EmptyDoc).withContext(QxJson::Data());
809+
810+
// Basic parse
811+
QJsonParseError jpe;
812+
QJsonDocument jd = QJsonDocument::fromJson(data, &jpe);
813+
814+
if(jpe.error != jpe.NoError)
815+
return JsonError(QxJsonPrivate::ERR_READ_DATA, JsonError::InvalidData).withContext(QxJson::Data());
816+
817+
// True parse
818+
return parseJson(parsed, jd).withContext(QxJson::Data());
819+
}
820+
821+
template<typename T>
822+
requires json_root<T>
823+
void serializeJson(QByteArray& serialized, const T& root, QJsonDocument::JsonFormat fmt = QJsonDocument::Indented)
824+
{
825+
// Ensure buffer is clear
826+
serialized.clear();
827+
828+
// Create document
829+
QJsonDocument jd;
830+
serializeJson(jd, root);
831+
832+
// Write data
833+
serialized = jd.toJson(fmt);
834+
}
835+
791836
template<typename T>
792837
requires json_root<T>
793838
JsonError parseJson(T& parsed, QFile& file)
794839
{
840+
// NOTE: Don't utilize the QByteArray "data" overload here as we would lose the better error info
795841
if(!file.exists())
796842
return JsonError(QxJsonPrivate::ERR_READ_FILE, JsonError::MissingFile).withContext(QxJson::File(file.fileName()));
797843

@@ -828,7 +874,7 @@ JsonError parseJson(T& parsed, QFile& file)
828874

829875
template<typename T>
830876
requires json_root<T>
831-
JsonError serializeJson(QFile& serialized, const T& root)
877+
JsonError serializeJson(QFile& serialized, const T& root, QJsonDocument::JsonFormat fmt = QJsonDocument::Indented)
832878
{
833879
// Close and re-open file, if open, to ensure correct mode and start of file
834880
if(serialized.isOpen())
@@ -840,15 +886,9 @@ JsonError serializeJson(QFile& serialized, const T& root)
840886
// Close file when finished
841887
QScopeGuard fileGuard([&serialized]{ serialized.close(); });
842888

843-
// Create document
844-
QJsonDocument jd;
845-
serializeJson(jd, root);
846-
847-
// Write data
848-
QByteArray jsonData = jd.toJson();
849-
if(jsonData.isEmpty())
850-
return JsonError(); // No-op
851-
889+
// Serialize
890+
QByteArray jsonData;
891+
serializeJson(jsonData, root, fmt);
852892
if(serialized.write(jsonData) != jsonData.size())
853893
return JsonError(QxJsonPrivate::ERR_WRITE_FILE, JsonError::FileWriteError).withContext(QxJson::File(serialized.fileName(), serialized.errorString()));
854894

@@ -866,11 +906,11 @@ JsonError parseJson(T& parsed, const QString& filePath)
866906

867907
template<typename T>
868908
requires json_root<T>
869-
JsonError serializeJson(const QString& serializedPath, const T& root)
909+
JsonError serializeJson(const QString& serializedPath, const T& root, QJsonDocument::JsonFormat fmt = QJsonDocument::Indented)
870910
{
871911
QFile file(serializedPath);
872912

873-
return serializeJson(file, root);
913+
return serializeJson(file, root, fmt);
874914
}
875915

876916
QX_CORE_EXPORT QList<QJsonValue> findAllValues(const QJsonValue& rootValue, QStringView key);

lib/core/src/qx-json.cpp

Lines changed: 24 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -334,11 +334,11 @@ QString QJsonParseErrorAdapter::deriveSecondary() const { return OFFSET_STR.arg(
334334
*/
335335

336336
/*!
337-
* @fn JsonError serializeJson(QFile& serialized, const T& root)
337+
* @fn JsonError serializeJson(QFile& serialized, const T& root, QJsonDocument::JsonFormat fmt)
338338
*
339339
* @overload
340340
*
341-
* Serializes the entire JSON root structure @a root and writes the result to @a serialized in indented format,
341+
* Serializes the entire JSON root structure @a root and writes the result to @a serialized in format @a fmt,
342342
* replacing existing contents, if any.
343343
*
344344
* @a T must satisfy the Qx::json_root concept.
@@ -357,12 +357,12 @@ QString QJsonParseErrorAdapter::deriveSecondary() const { return OFFSET_STR.arg(
357357
*/
358358

359359
/*!
360-
* @fn JsonError serializeJson(const QString& filePath, const T& root)
360+
* @fn JsonError serializeJson(const QString& filePath, const T& root, QJsonDocument::JsonFormat fmt)
361361
*
362362
* @overload
363363
*
364364
* Serializes the entire JSON root structure @a root and writes the result to the file at path @a
365-
* filePath in indented format, replacing existing contents, if any.
365+
* filePath in format @a fmt, replacing existing contents, if any.
366366
*
367367
* @a T must satisfy the Qx::json_root concept.
368368
*
@@ -476,6 +476,26 @@ QString File::string() const
476476
return str;
477477
}
478478

479+
/*!
480+
* @class Data
481+
* @brief The document class represents a JSON data node for use in error contexts.
482+
*
483+
* @note This class is irrelevant in user code except for some instances of complex
484+
* custom JSON parsing
485+
*
486+
* @sa Qx::JsonError::withContext().
487+
*/
488+
489+
/*!
490+
* Constructs a data element node.
491+
*/
492+
Data::Data() {}
493+
494+
/*!
495+
* Returns the string representation of the node.
496+
*/
497+
QString Data::string() const { return u"Data"_s; }
498+
479499
/*!
480500
* @class Document
481501
* @brief The document class represents a JSON document node for use in error contexts.

0 commit comments

Comments
 (0)