12#if PROMEKI_ENABLE_CORE
16#include <initializer_list>
22#include <nlohmann/json_fwd.hpp>
24#include <promeki/config.h>
37PROMEKI_NAMESPACE_BEGIN
60 RefCount _promeki_refct;
61 const DataType::Data *typeData =
nullptr;
67 const void *payload()
const;
78 VariantBox *_promeki_clone()
const;
81 static constexpr size_t payloadOffset(
size_t typeAlign) {
82 const size_t headerEnd =
sizeof(VariantBox);
83 const size_t alignment = typeAlign == 0 ? 1 : typeAlign;
84 return (headerEnd + alignment - 1) & ~(alignment - 1);
88 static size_t totalSize(
const DataType::Data *td) {
89 return payloadOffset(td->align) + td->size;
99 static VariantBox *allocate(
const DataType::Data *td,
const void *src);
110 static void operator delete(
void *p, std::size_t sz)
noexcept;
166 static const char *typeName(DataTypeID
id);
181 static Variant fromJson(
const nlohmann::json &val);
200 static Variant readFromStream(DataStream &stream,
const DataType &dt);
217 static Variant createDefault(
const DataType &dt);
241 using ConverterFn = Variant (*)(
const Variant &src, Error *err);
259 static void registerConverter(DataTypeID from, DataTypeID to, ConverterFn fn);
277 template <auto Fn>
static void registerConverter();
297 static void registerBuiltinConverters();
307 static ConverterFn findConverter(DataTypeID from, DataTypeID to);
318 Variant() { registerBuiltinDataTypes(); }
321 Variant(
const Variant &) =
default;
324 Variant(Variant &&) noexcept = default;
327 Variant &operator=(const Variant &) = default;
330 Variant &operator=(Variant &&) noexcept = default;
333 ~Variant() = default;
348 template <typename T,
349 typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, Variant> &&
350 !std::is_same_v<std::decay_t<T>, VariantBox>>>
351 Variant(const T &value) {
367 template <
typename T,
368 typename = std::enable_if_t<!std::is_same_v<std::decay_t<T>, Variant> &&
369 !std::is_same_v<std::decay_t<T>, VariantBox> &&
370 !std::is_lvalue_reference_v<T>>>
372 setValueMove<std::remove_cv_t<std::remove_reference_t<T>>>(std::move(value));
377 bool isValid()
const {
return _box.isValid(); }
389 template <
typename T>
void set(
const T &value) {
403 template <
typename T,
404 typename = std::enable_if_t<!std::is_lvalue_reference_v<T> &&
405 !std::is_same_v<std::decay_t<T>, Variant>>>
406 void set(T &&value) {
407 setValueMove<std::remove_cv_t<std::remove_reference_t<T>>>(std::move(value));
425 template <
typename To> To get(Error *err =
nullptr)
const;
441 template <
typename T>
const T *peek() const noexcept;
444 DataTypeID type() const;
447 const
char *typeName()
const {
return typeName(type()); }
450 DataType dataType()
const;
466 const void *payloadPtr()
const;
475 Variant toStandardType()
const;
490 String toString(Error *err =
nullptr)
const;
511 String format(
const String &spec, Error *err =
nullptr)
const;
529 Enum asEnum(Enum::Type enumType, Error *err =
nullptr)
const;
542 bool operator==(
const Variant &other)
const;
545 bool operator!=(
const Variant &other)
const {
return !(*
this == other); }
561 Variant convertTo(DataTypeID to, Error *err =
nullptr)
const;
565 using BoxPtr = SharedPtr<VariantBox>;
567 template <
typename T>
void setValue(
const T &value);
568 template <
typename T>
void setValueMove(T &&value);
602 PROMEKI_DATATYPE(VariantList, DataTypeVariantList, 1)
605 using ItemList = List<Variant>;
607 using Iterator = Variant *;
609 using ConstIterator = const Variant *;
612 VariantList(std::initializer_list<Variant> il);
613 explicit VariantList(const ItemList &other);
614 explicit VariantList(ItemList &&other);
616 VariantList(const VariantList &other);
617 VariantList(VariantList &&other) noexcept;
620 VariantList &operator=(const VariantList &other);
621 VariantList &operator=(VariantList &&other) noexcept;
624 bool isEmpty() const;
626 void reserve(
size_t capacity);
628 Variant &operator[](
size_t index);
629 const Variant &operator[](
size_t index) const;
630 Variant &at(
size_t index);
631 const Variant &at(
size_t index) const;
633 void pushToBack(const Variant &v);
634 void pushToBack(Variant &&v);
638 const Variant *data() const;
642 ConstIterator begin() const;
643 ConstIterator end() const;
644 ConstIterator cbegin() const;
645 ConstIterator cend() const;
648 const ItemList &list() const;
650 bool operator==(const VariantList &other) const;
651 bool operator!=(const VariantList &other)
const {
return !(*
this == other); }
653 String toJsonString()
const;
654 static VariantList fromJsonString(
const String &json, Error *err =
nullptr);
664 String toString()
const {
return toJsonString(); }
674 static Result<VariantList> fromString(
const String &json) {
676 VariantList v = fromJsonString(json, &e);
677 if (e.isError())
return makeError<VariantList>(e);
678 return makeResult(std::move(v));
690 Error writeToStream(DataStream &s)
const;
696 template <u
int32_t V>
static Result<VariantList> readFromStream(DataStream &s);
699 UniquePtr<ItemList> _list;
716 PROMEKI_DATATYPE(VariantMap, DataTypeVariantMap, 1)
719 using EntryMap = Map<String, Variant>;
721 using EntryPair = Pair<String, Variant>;
723 using ForEachFn = Function<
void(const String &, const Variant &)>;
726 VariantMap(std::initializer_list<EntryPair> il);
727 explicit VariantMap(const EntryMap &other);
728 explicit VariantMap(EntryMap &&other);
730 VariantMap(const VariantMap &other);
731 VariantMap(VariantMap &&other) noexcept;
734 VariantMap &operator=(const VariantMap &other);
735 VariantMap &operator=(VariantMap &&other) noexcept;
738 bool isEmpty() const;
740 bool contains(const String &key) const;
742 void insert(const String &key, const Variant &value);
743 void insert(const String &key, Variant &&value);
744 bool remove(const String &key);
746 Variant value(const String &key) const;
747 Variant value(const String &key, const Variant &defaultValue) const;
749 Variant *find(const String &key);
750 const Variant *find(const String &key) const;
752 StringList keys() const;
753 void forEach(ForEachFn fn) const;
756 const EntryMap &map() const;
758 bool operator==(const VariantMap &other) const;
759 bool operator!=(const VariantMap &other)
const {
return !(*
this == other); }
761 String toJsonString()
const;
762 static VariantMap fromJsonString(
const String &json, Error *err =
nullptr);
772 String toString()
const {
return toJsonString(); }
782 static Result<VariantMap> fromString(
const String &json) {
784 VariantMap v = fromJsonString(json, &e);
785 if (e.isError())
return makeError<VariantMap>(e);
786 return makeResult(std::move(v));
797 Error writeToStream(DataStream &s)
const;
803 template <u
int32_t V>
static Result<VariantMap> readFromStream(DataStream &s);
806 UniquePtr<EntryMap> _map;
824SharedPtr<VariantBox> makeVariantBox(
const DataType::Data *typeData,
const void *value);
834SharedPtr<VariantBox> makeVariantBoxMove(
const DataType::Data *typeData,
void *value);
838template <
typename T>
void Variant::setValue(
const T &value) {
844 if constexpr (std::is_base_of_v<Enum, T> && !std::is_same_v<T, Enum>) {
845 const Enum &sliced =
static_cast<const Enum &
>(value);
846 _box = Detail::makeVariantBox(DataType::of<Enum>().data(), &sliced);
849 const DataType dt = DataType::of<T>();
851 _box = Detail::makeVariantBox(dt.data(), &value);
860 if constexpr (!std::is_same_v<T, String> &&
861 std::is_constructible_v<String, const T &>) {
863 _box = Detail::makeVariantBox(DataType::of<String>().data(), &s);
871template <
typename T>
void Variant::setValueMove(T &&value) {
877 using U = std::remove_cv_t<std::remove_reference_t<T>>;
878 if constexpr (std::is_base_of_v<Enum, U> && !std::is_same_v<U, Enum>) {
879 Enum sliced =
static_cast<Enum &&
>(value);
880 _box = Detail::makeVariantBoxMove(DataType::of<Enum>().data(), &sliced);
883 const DataType dt = DataType::of<U>();
885 U tmp(std::move(value));
886 _box = Detail::makeVariantBoxMove(dt.data(), &tmp);
890 if constexpr (!std::is_same_v<U, String> &&
891 std::is_constructible_v<String, U &&>) {
892 String s(std::move(value));
893 _box = Detail::makeVariantBoxMove(DataType::of<String>().data(), &s);
901template <
typename T>
const T *Variant::peek() const noexcept {
902 if (_box.isNull())
return nullptr;
903 const DataType::Data *td = _box->typeData;
904 if (td ==
nullptr)
return nullptr;
905 if (td->cppType != std::type_index(
typeid(T)))
return nullptr;
906 return static_cast<const T *
>(_box->payload());
909template <
typename To> To Variant::get(Error *err)
const {
910 if (err !=
nullptr) *err = Error::Ok;
911 if (
const To *direct = peek<To>())
return *direct;
913 const DataType targetDt = DataType::of<To>();
914 if (!targetDt.isValid()) {
915 if (err !=
nullptr) *err = Error::Invalid;
919 Variant out = convertTo(targetDt.id(), &convErr);
920 if (convErr.isError()) {
921 if (err !=
nullptr) *err = convErr;
924 if (
const To *converted = out.peek<To>())
return *converted;
925 if (err !=
nullptr) *err = Error::Invalid;
939template <
typename Fn>
struct ConverterFnTraits;
941template <
typename To,
typename From>
struct ConverterFnTraits<To (*)(
const From &, Error *)> {
942 using FromType = From;
948template <auto Fn>
void Variant::registerConverter() {
949 using Traits = Detail::ConverterFnTraits<
decltype(Fn)>;
950 using From =
typename Traits::FromType;
951 using To =
typename Traits::ToType;
952 registerConverter(DataType::of<From>().
id(), DataType::of<To>().
id(),
953 +[](
const Variant &v, Error *err) -> Variant {
954 const From *p = v.peek<From>();
956 if (err !=
nullptr) *err = Error::Invalid;
959 return Variant(Fn(*p, err));
975inline Variant variantConvertStringTo(
const Variant &src, Error *err) {
976 if (err !=
nullptr) *err = Error::Ok;
977 const String *s = src.peek<String>();
979 if (err !=
nullptr) *err = Error::Invalid;
982 const DataType dt = DataType::of<T>();
983 const DataType::Data *td = dt.data();
984 if (td ==
nullptr || td->ops.fromString ==
nullptr) {
985 if (err !=
nullptr) *err = Error::Invalid;
990 if (!td->ops.fromString(*s, &tmp, &e)) {
991 if (err !=
nullptr) *err = e.isError() ? e : Error::Invalid;
994 return Variant(std::move(tmp));
1004template <
typename T>
1005inline Variant variantConvertToString(
const Variant &src, Error *err) {
1006 if (err !=
nullptr) *err = Error::Ok;
1007 const T *p = src.peek<T>();
1009 if (err !=
nullptr) *err = Error::Invalid;
1012 const DataType dt = DataType::of<T>();
1013 const DataType::Data *td = dt.data();
1014 if (td ==
nullptr || td->ops.toString ==
nullptr) {
1015 if (err !=
nullptr) *err = Error::Invalid;
1019 String result = td->ops.toString(p, &e);
1021 if (err !=
nullptr) *err = e;
1024 return Variant(std::move(result));
1036template <
typename Integer,
typename T>
1037inline Variant variantConvertIntegerTo(
const Variant &src, Error *err) {
1038 if (err !=
nullptr) *err = Error::Ok;
1039 const Integer *p = src.peek<Integer>();
1041 if (err !=
nullptr) *err = Error::Invalid;
1044 const DataType dt = DataType::of<T>();
1045 const DataType::Data *td = dt.data();
1046 if (td ==
nullptr || td->ops.fromInt ==
nullptr) {
1047 if (err !=
nullptr) *err = Error::Invalid;
1052 if (!td->ops.fromInt(
static_cast<int64_t
>(*p), &tmp, &e)) {
1053 if (err !=
nullptr) *err = e.isError() ? e : Error::Invalid;
1056 return Variant(std::move(tmp));
1066template <
typename T,
typename Integer>
1067inline Variant variantConvertToInteger(
const Variant &src, Error *err) {
1068 if (err !=
nullptr) *err = Error::Ok;
1069 const T *p = src.peek<T>();
1071 if (err !=
nullptr) *err = Error::Invalid;
1074 const DataType dt = DataType::of<T>();
1075 const DataType::Data *td = dt.data();
1076 if (td ==
nullptr || td->ops.toInt ==
nullptr) {
1077 if (err !=
nullptr) *err = Error::Invalid;
1081 int64_t raw = td->ops.toInt(p, &e);
1083 if (err !=
nullptr) *err = e;
1086 return Variant(
static_cast<Integer
>(raw));
1096template <
typename Float,
typename T>
1097inline Variant variantConvertFloatTo(
const Variant &src, Error *err) {
1098 if (err !=
nullptr) *err = Error::Ok;
1099 const Float *p = src.peek<Float>();
1101 if (err !=
nullptr) *err = Error::Invalid;
1104 const DataType dt = DataType::of<T>();
1105 const DataType::Data *td = dt.data();
1106 if (td ==
nullptr || td->ops.fromFloat ==
nullptr) {
1107 if (err !=
nullptr) *err = Error::Invalid;
1112 if (!td->ops.fromFloat(
static_cast<double>(*p), &tmp, &e)) {
1113 if (err !=
nullptr) *err = e.isError() ? e : Error::Invalid;
1116 return Variant(std::move(tmp));
1126template <
typename T,
typename Float>
1127inline Variant variantConvertToFloat(
const Variant &src, Error *err) {
1128 if (err !=
nullptr) *err = Error::Ok;
1129 const T *p = src.peek<T>();
1131 if (err !=
nullptr) *err = Error::Invalid;
1134 const DataType dt = DataType::of<T>();
1135 const DataType::Data *td = dt.data();
1136 if (td ==
nullptr || td->ops.toFloat ==
nullptr) {
1137 if (err !=
nullptr) *err = Error::Invalid;
1141 double raw = td->ops.toFloat(p, &e);
1143 if (err !=
nullptr) *err = e;
1146 return Variant(
static_cast<Float
>(raw));
1156template <
typename T>
1157inline Variant variantConvertJsonObjectTo(
const Variant &src, Error *err) {
1158 if (err !=
nullptr) *err = Error::Ok;
1159 const DataType jsonDt = DataType::byCppType(std::type_index(
typeid(JsonObject)));
1160 if (!jsonDt.isValid()) {
1161 if (err !=
nullptr) *err = Error::Invalid;
1164 const void *raw = src.payloadPtr();
1165 if (raw ==
nullptr || src.type() != jsonDt.id()) {
1166 if (err !=
nullptr) *err = Error::Invalid;
1169 const JsonObject *p =
static_cast<const JsonObject *
>(raw);
1170 const DataType dt = DataType::of<T>();
1171 const DataType::Data *td = dt.data();
1172 if (td ==
nullptr || td->ops.fromJson ==
nullptr) {
1173 if (err !=
nullptr) *err = Error::Invalid;
1178 if (!td->ops.fromJson(*p, &tmp, &e)) {
1179 if (err !=
nullptr) *err = e.isError() ? e : Error::Invalid;
1182 return Variant(std::move(tmp));
1192template <
typename T>
1193inline Variant variantConvertToJsonObject(
const Variant &src, Error *err) {
1194 if (err !=
nullptr) *err = Error::Ok;
1195 const T *p = src.peek<T>();
1197 if (err !=
nullptr) *err = Error::Invalid;
1200 const DataType dt = DataType::of<T>();
1201 const DataType::Data *td = dt.data();
1202 if (td ==
nullptr || td->ops.toJson ==
nullptr) {
1203 if (err !=
nullptr) *err = Error::Invalid;
1207 JsonObject result = td->ops.toJson(p, &e);
1209 if (err !=
nullptr) *err = e;
1212 return Variant(std::move(result));
1215template <
typename T>
inline void registerAutoConverters(
const DataType &dt) {
1216 if (!dt.isValid())
return;
1221 const DataType stringDt = DataType::byCppType(std::type_index(
typeid(String)));
1222 if (!stringDt.isValid())
return;
1223 if (dt == stringDt)
return;
1224 if (dt.ops().fromString !=
nullptr) {
1225 Variant::registerConverter(stringDt.id(), dt.id(), &variantConvertStringTo<T>);
1227 if (dt.ops().toString !=
nullptr) {
1228 Variant::registerConverter(dt.id(), stringDt.id(), &variantConvertToString<T>);
1233 const DataType jsonDt = DataType::byCppType(std::type_index(
typeid(JsonObject)));
1234 if (jsonDt.isValid() && dt != jsonDt) {
1235 if (dt.ops().fromJson !=
nullptr) {
1236 Variant::registerConverter(jsonDt.id(), dt.id(),
1237 &variantConvertJsonObjectTo<T>);
1239 if (dt.ops().toJson !=
nullptr) {
1240 Variant::registerConverter(dt.id(), jsonDt.id(),
1241 &variantConvertToJsonObject<T>);
1249 auto wireIntPair = [&dt]<
typename Integer>() {
1250 const DataType intDt = DataType::byCppType(std::type_index(
typeid(Integer)));
1251 if (!intDt.isValid())
return;
1252 if (dt.ops().fromInt !=
nullptr) {
1253 Variant::registerConverter(intDt.id(), dt.id(),
1254 &variantConvertIntegerTo<Integer, T>);
1256 if (dt.ops().toInt !=
nullptr) {
1257 Variant::registerConverter(dt.id(), intDt.id(),
1258 &variantConvertToInteger<T, Integer>);
1261 if (dt.ops().toInt !=
nullptr || dt.ops().fromInt !=
nullptr) {
1262 wireIntPair.template operator()<
bool>();
1263 wireIntPair.template operator()<uint8_t>();
1264 wireIntPair.template operator()<int8_t>();
1265 wireIntPair.template operator()<uint16_t>();
1266 wireIntPair.template operator()<int16_t>();
1267 wireIntPair.template operator()<uint32_t>();
1268 wireIntPair.template operator()<int32_t>();
1269 wireIntPair.template operator()<uint64_t>();
1270 wireIntPair.template operator()<int64_t>();
1276 auto wireFloatPair = [&dt]<
typename Float>() {
1277 const DataType floatDt = DataType::byCppType(std::type_index(
typeid(Float)));
1278 if (!floatDt.isValid())
return;
1279 if (dt.ops().fromFloat !=
nullptr) {
1280 Variant::registerConverter(floatDt.id(), dt.id(),
1281 &variantConvertFloatTo<Float, T>);
1283 if (dt.ops().toFloat !=
nullptr) {
1284 Variant::registerConverter(dt.id(), floatDt.id(),
1285 &variantConvertToFloat<T, Float>);
1288 if (dt.ops().toFloat !=
nullptr || dt.ops().fromFloat !=
nullptr) {
1289 wireFloatPair.template operator()<
float>();
1290 wireFloatPair.template operator()<
double>();
1314Variant promekiResolveVariantPath(
const Variant &root,
const String &path, Error *err =
nullptr);
1316PROMEKI_NAMESPACE_END
1326template <>
struct std::formatter<promeki::Variant> : std::formatter<std::string_view> {
1327 using Base = std::formatter<std::string_view>;
1328 template <
typename FormatContext>
1329 auto format(
const promeki::Variant &v, FormatContext &ctx)
const {
1330 promeki::String s = v.get<promeki::String>();
1331 return Base::format(std::string_view(s.cstr(), s.byteCount()), ctx);