12#include <promeki/config.h>
13#if PROMEKI_ENABLE_CORE
23#include <nlohmann/json.hpp>
25PROMEKI_NAMESPACE_BEGIN
48 PROMEKI_SHARED_FINAL(JsonData)
52 explicit JsonData(nlohmann::json v) : j(std::move(v)) {}
109 JsonValue(int64_t i);
111 JsonValue(uint64_t i);
115 JsonValue(
const char *s);
117 JsonValue(
const promeki::String &s);
119 inline JsonValue(
const JsonObject &obj);
121 inline JsonValue(
const JsonArray &arr);
124 static JsonValue undefined();
127 static JsonValue fromVariant(
const Variant &val);
133 bool isNull()
const {
return _d->j.is_null(); }
135 bool isBool()
const {
return _d->j.is_boolean(); }
137 bool isDouble()
const {
return _d->j.is_number(); }
139 bool isString()
const {
return _d->j.is_string(); }
141 bool isArray()
const {
return _d->j.is_array(); }
143 bool isObject()
const {
return _d->j.is_object(); }
152 bool isUndefined()
const {
return _d->j.is_discarded(); }
155 bool toBool(
bool def =
false)
const;
157 int64_t toInt(int64_t def = 0)
const;
159 uint64_t toUInt(uint64_t def = 0)
const;
161 double toDouble(
double def = 0.0)
const;
163 promeki::String toString(
const promeki::String &def = promeki::String())
const;
165 inline JsonObject toObject()
const;
167 inline JsonArray toArray()
const;
169 Variant toVariant()
const;
172 promeki::String toJsonString(
unsigned int indent = 0)
const;
175 bool operator==(
const JsonValue &other)
const;
177 bool operator!=(
const JsonValue &other)
const {
return !(*
this == other); }
180 friend class JsonObject;
181 friend class JsonArray;
183 SharedPtr<JsonData> _d = SharedPtr<JsonData>::create();
185 explicit JsonValue(nlohmann::json j) : _d(SharedPtr<JsonData>::create(std::move(j))) {}
186 explicit JsonValue(
const SharedPtr<JsonData> &d) : _d(d) {}
188 template <
typename T>
static T extract(
const nlohmann::json &val,
bool *good);
248 static JsonObject parse(
const String &str, Error *err =
nullptr) {
250 nlohmann::json j = nlohmann::json::parse(str.str());
251 if (!j.is_object())
throw std::runtime_error(
"not an object");
252 if (err) *err = Error::Ok;
253 return JsonObject(std::move(j));
255 if (err) *err = Error::Invalid;
268 static Result<JsonObject> fromString(
const String &str) {
270 JsonObject o = parse(str, &e);
271 if (e.isError())
return makeError<JsonObject>(e);
272 return makeResult(std::move(o));
276 static JsonObject fromVariantMap(
const VariantMap &map);
279 JsonObject() =
default;
282 int size()
const {
return static_cast<int>(_d->j.size()); }
285 int count()
const {
return size(); }
288 bool isEmpty()
const {
return _d->j.empty(); }
291 bool isValid()
const {
return !isEmpty(); }
294 List<String> keys()
const;
301 bool valueIsNull(
const String &key)
const {
302 auto it = _d->j.find(key.str());
303 return it != _d->j.end() && it->is_null();
311 bool valueIsObject(
const String &key)
const {
312 auto it = _d->j.find(key.str());
313 return it != _d->j.end() && it->is_object();
321 bool valueIsArray(
const String &key)
const {
322 auto it = _d->j.find(key.str());
323 return it != _d->j.end() && it->is_array();
331 bool contains(
const String &key)
const {
return _d->j.contains(key.str()); }
341 JsonValue value(
const String &key)
const;
344 JsonValue operator[](
const String &key)
const {
return value(key); }
352 bool getBool(
const String &key, Error *err =
nullptr)
const {
return get<bool>(key, err); }
360 int64_t getInt(
const String &key, Error *err =
nullptr)
const {
return get<int64_t>(key, err); }
368 uint64_t getUInt(
const String &key, Error *err =
nullptr)
const {
return get<uint64_t>(key, err); }
376 double getDouble(
const String &key, Error *err =
nullptr)
const {
return get<double>(key, err); }
384 String getString(
const String &key, Error *err =
nullptr)
const {
385 return get<std::string>(key, err);
394 JsonObject getObject(
const String &key, Error *err =
nullptr)
const {
395 auto it = _d->j.find(key.str());
396 if (it == _d->j.end() || !it->is_object()) {
397 if (err) *err = Error::Invalid;
400 if (err) *err = Error::Ok;
401 return JsonObject(*it);
410 inline JsonArray getArray(
const String &key, Error *err =
nullptr)
const;
417 String toString(
unsigned int indent = 0)
const {
418 if (indent == 0)
return _d->j.dump();
419 return _d->j.dump(
static_cast<int>(indent));
423 VariantMap toVariantMap()
const;
426 void clear() { _d.modify()->j.clear(); }
432 bool remove(
const String &key);
438 JsonValue take(
const String &key);
444 void setNull(
const String &key) { _d.modify()->j[key.str()] =
nullptr; }
451 inline void set(
const String &key,
const JsonObject &val);
454 inline void set(
const String &key, JsonObject &&val);
461 inline void set(
const String &key,
const JsonArray &val);
464 inline void set(
const String &key, JsonArray &&val);
467 void set(
const String &key,
const JsonValue &val);
470 void set(
const String &key,
bool val) { _d.modify()->j[key.str()] = val; }
472 void set(
const String &key,
int val) { _d.modify()->j[key.str()] = val; }
474 void set(
const String &key,
unsigned int val) { _d.modify()->j[key.str()] = val; }
476 void set(
const String &key, int64_t val) { _d.modify()->j[key.str()] = val; }
478 void set(
const String &key, uint64_t val) { _d.modify()->j[key.str()] = val; }
480 void set(
const String &key,
float val) { _d.modify()->j[key.str()] = val; }
482 void set(
const String &key,
double val) { _d.modify()->j[key.str()] = val; }
484 void set(
const String &key,
const char *val) {
485 _d.modify()->j[key.str()] = std::string(val);
488 void set(
const String &key,
const String &val) {
489 _d.modify()->j[key.str()] = val.str();
492 void set(
const String &key,
const UUID &val);
499 void setFromVariant(
const String &key,
const Variant &val);
505 void forEach(Function<
void(
const String &key,
const Variant &val)> func)
const;
508 bool operator==(
const JsonObject &other)
const {
509 if (_d == other._d)
return true;
510 return _d->j == other._d->j;
514 bool operator!=(
const JsonObject &other)
const {
return !(*
this == other); }
517 friend class JsonArray;
518 friend class JsonValue;
520 SharedPtr<JsonData> _d = SharedPtr<JsonData>::create(JsonData(nlohmann::json::object()));
523 explicit JsonObject(nlohmann::json j) : _d(SharedPtr<JsonData>::create(JsonData(std::move(j)))) {}
526 explicit JsonObject(
const SharedPtr<JsonData> &d) : _d(d) {}
528 template <
typename T> T get(
const String &key, Error *err =
nullptr)
const {
529 auto it = _d->j.find(key.str());
530 if (it == _d->j.end()) {
531 if (err) *err = Error::Invalid;
535 T ret = JsonValue::extract<T>(*it, &good);
536 if (err) *err = good ? Error::Ok : Error::Invalid;
569 static JsonArray parse(
const String &str, Error *err =
nullptr) {
571 nlohmann::json j = nlohmann::json::parse(str.str());
572 if (!j.is_array())
throw std::runtime_error(
"not an array");
573 if (err) *err = Error::Ok;
574 return JsonArray(std::move(j));
576 if (err) *err = Error::Invalid;
588 static Result<JsonArray> fromString(
const String &str) {
590 JsonArray a = parse(str, &e);
591 if (e.isError())
return makeError<JsonArray>(e);
592 return makeResult(std::move(a));
596 static JsonArray fromVariantList(
const VariantList &list);
599 JsonArray() =
default;
602 int size()
const {
return static_cast<int>(_d->j.size()); }
605 int count()
const {
return size(); }
608 bool isEmpty()
const {
return _d->j.empty(); }
611 bool isValid()
const {
return !isEmpty(); }
617 bool valueIsNull(
int index)
const {
618 return index >= 0 && index < size() && _d->j[index].is_null();
625 bool valueIsObject(
int index)
const {
626 return index >= 0 && index < size() && _d->j[index].is_object();
633 bool valueIsArray(
int index)
const {
634 return index >= 0 && index < size() && _d->j[index].is_array();
643 JsonValue at(
int index)
const;
646 JsonValue operator[](
int index)
const {
return at(index); }
649 JsonValue first()
const {
return at(0); }
652 JsonValue last()
const {
return at(size() - 1); }
660 bool getBool(
int index, Error *err =
nullptr)
const {
return get<bool>(index, err); }
668 int64_t getInt(
int index, Error *err =
nullptr)
const {
return get<int64_t>(index, err); }
676 uint64_t getUInt(
int index, Error *err =
nullptr)
const {
return get<uint64_t>(index, err); }
684 double getDouble(
int index, Error *err =
nullptr)
const {
return get<double>(index, err); }
692 String getString(
int index, Error *err =
nullptr)
const {
return get<std::string>(index, err); }
700 JsonObject getObject(
int index, Error *err =
nullptr)
const {
701 if (index < 0 || index >= size() || !_d->j[index].is_object()) {
702 if (err) *err = Error::Invalid;
705 if (err) *err = Error::Ok;
706 return JsonObject(_d->j[index]);
715 JsonArray getArray(
int index, Error *err =
nullptr)
const {
716 if (index < 0 || index >= size() || !_d->j[index].is_array()) {
717 if (err) *err = Error::Invalid;
720 if (err) *err = Error::Ok;
721 return JsonArray(_d->j[index]);
729 String toString(
unsigned int indent = 0)
const {
730 if (indent == 0)
return _d->j.dump();
731 return _d->j.dump(
static_cast<int>(indent));
735 VariantList toVariantList()
const;
738 void clear() { _d.modify()->j.clear(); }
744 bool removeAt(
int index);
750 JsonValue takeAt(
int index);
753 void addNull() { _d.modify()->j.push_back(
nullptr); }
755 inline void add(
const JsonObject &val);
757 inline void add(JsonObject &&val);
759 inline void add(
const JsonArray &val);
761 inline void add(JsonArray &&val);
763 void add(
const JsonValue &val);
765 void add(
bool val) { _d.modify()->j.push_back(val); }
767 void add(
int val) { _d.modify()->j.push_back(val); }
769 void add(
unsigned int val) { _d.modify()->j.push_back(val); }
771 void add(int64_t val) { _d.modify()->j.push_back(val); }
773 void add(uint64_t val) { _d.modify()->j.push_back(val); }
775 void add(
float val) { _d.modify()->j.push_back(val); }
777 void add(
double val) { _d.modify()->j.push_back(val); }
779 void add(
const char *val) { _d.modify()->j.push_back(std::string(val)); }
781 void add(
const String &val) { _d.modify()->j.push_back(val.str()); }
783 void add(
const UUID &val);
789 void addFromVariant(
const Variant &val);
792 template <
typename T>
void append(T &&val) { add(std::forward<T>(val)); }
801 void insert(
int index,
const JsonValue &val);
804 void prepend(
const JsonValue &val) { insert(0, val); }
810 void forEach(Function<
void(
const Variant &val)> func)
const;
813 bool operator==(
const JsonArray &other)
const {
814 if (_d == other._d)
return true;
815 return _d->j == other._d->j;
819 bool operator!=(
const JsonArray &other)
const {
return !(*
this == other); }
822 class const_iterator {
824 using iterator_category = std::forward_iterator_tag;
825 using value_type = JsonValue;
826 using difference_type = std::ptrdiff_t;
827 using pointer = void;
828 using reference = JsonValue;
830 const_iterator() =
default;
832 JsonValue operator*()
const;
833 const_iterator &operator++() {
837 const_iterator operator++(
int) {
838 const_iterator tmp = *
this;
842 bool operator==(
const const_iterator &other)
const {
843 return _arr == other._arr && _index == other._index;
845 bool operator!=(
const const_iterator &other)
const {
return !(*
this == other); }
848 friend class JsonArray;
849 const_iterator(
const JsonArray *arr,
int index) : _arr(arr), _index(index) {}
851 const JsonArray *_arr =
nullptr;
856 const_iterator begin()
const {
return const_iterator(
this, 0); }
858 const_iterator end()
const {
return const_iterator(
this, size()); }
860 const_iterator cbegin()
const {
return begin(); }
862 const_iterator cend()
const {
return end(); }
865 friend class JsonObject;
866 friend class JsonValue;
868 SharedPtr<JsonData> _d = SharedPtr<JsonData>::create(JsonData(nlohmann::json::array()));
871 explicit JsonArray(nlohmann::json j) : _d(SharedPtr<JsonData>::create(JsonData(std::move(j)))) {}
874 explicit JsonArray(
const SharedPtr<JsonData> &d) : _d(d) {}
876 template <
typename T> T get(
int index, Error *err =
nullptr)
const {
877 if (index < 0 || index >= size()) {
878 if (err) *err = Error::Invalid;
882 T ret = JsonValue::extract<T>(_d->j[index], &good);
883 if (err) *err = good ? Error::Ok : Error::Invalid;
892inline JsonValue::JsonValue(
const JsonObject &obj) : _d(obj._d) {}
893inline JsonValue::JsonValue(
const JsonArray &arr) : _d(arr._d) {}
895template <
typename T> T JsonValue::extract(
const nlohmann::json &val,
bool *good) {
899 if constexpr (std::is_same_v<T, bool>) {
900 if (val.is_boolean()) {
901 ret = val.get<
bool>();
903 }
else if (val.is_number_integer()) {
904 ret = val.get<int64_t>() != 0;
907 }
else if constexpr (std::is_integral_v<T>) {
908 if (val.is_number()) {
909 ret =
static_cast<T
>(val.get<int64_t>());
911 }
else if (val.is_boolean()) {
912 ret = val.get<
bool>() ? 1 : 0;
915 }
else if constexpr (std::is_floating_point_v<T>) {
916 if (val.is_number()) {
920 }
else if constexpr (std::is_same_v<T, std::string>) {
921 if (val.is_string()) {
922 ret = val.get<std::string>();
924 }
else if (!val.is_null() && !val.is_discarded()) {
930 if (good) *good = ok;
934inline JsonObject JsonValue::toObject()
const {
935 if (!_d->j.is_object())
return JsonObject();
936 return JsonObject(_d);
939inline JsonArray JsonValue::toArray()
const {
940 if (!_d->j.is_array())
return JsonArray();
941 return JsonArray(_d);
944inline JsonArray JsonObject::getArray(
const String &key, Error *err)
const {
945 auto it = _d->j.find(key.str());
946 if (it == _d->j.end() || !it->is_array()) {
947 if (err) *err = Error::Invalid;
950 if (err) *err = Error::Ok;
951 return JsonArray(*it);
954inline void JsonObject::set(
const String &key,
const JsonObject &val) {
955 _d.modify()->j[key.str()] = val._d->j;
958inline void JsonObject::set(
const String &key, JsonObject &&val) {
963 _d.modify()->j[key.str()] = std::move(val._d.modify()->j);
966inline void JsonObject::set(
const String &key,
const JsonArray &val) {
967 _d.modify()->j[key.str()] = val._d->j;
970inline void JsonObject::set(
const String &key, JsonArray &&val) {
971 _d.modify()->j[key.str()] = std::move(val._d.modify()->j);
974inline void JsonArray::add(
const JsonObject &val) { _d.modify()->j.push_back(val._d->j); }
976inline void JsonArray::add(JsonObject &&val) { _d.modify()->j.push_back(std::move(val._d.modify()->j)); }
978inline void JsonArray::add(
const JsonArray &val) { _d.modify()->j.push_back(val._d->j); }
980inline void JsonArray::add(JsonArray &&val) { _d.modify()->j.push_back(std::move(val._d.modify()->j)); }
982inline JsonValue JsonArray::const_iterator::operator*()
const {
return _arr->at(_index); }
992PROMEKI_FORMAT_VIA_TOSTRING(promeki::JsonObject);
993PROMEKI_FORMAT_VIA_TOSTRING(promeki::JsonArray);