#pragma once #include #include #include #include #include "Enum.h" #include "Ranges.h" #include "Struct.h" #include "TypeTraits.h" #include "llvm/Support/JSON.h" namespace clice::json { using namespace llvm::json; /// Specialize this struct to provide custom serialization and deserialization for a type. template struct Serde; template concept serializable = requires { sizeof(Serde); }; /// Serialize an object to a JSON value. template json::Value serialize(const V& v) { return Serde::serialize(v); } /// Deserialize a JSON value to an object. template T deserialize(const json::Value& value) { return Serde::deserialize(value); } template <> struct Serde { static json::Value serialize(auto&& value) { return json::Value(std::forward(value)); } static json::Value deserialize(auto&& value) { return json::Value(std::forward(value)); } }; template <> struct Serde { static json::Value serialize(std::nullptr_t) { return json::Value(nullptr); } static std::nullptr_t deserialize(const json::Value& value) { assert(value.kind() == json::Value::Null && "Expect null"); return nullptr; } }; template <> struct Serde { static json::Value serialize(std::nullopt_t) { return json::Value(nullptr); } static std::nullopt_t deserialize(const json::Value& value) { assert(value.kind() == json::Value::Null && "Expect null"); return std::nullopt; } }; template <> struct Serde { static json::Value serialize(bool v) { return json::Value(v); } static bool deserialize(const json::Value& value) { assert(value.kind() == json::Value::Boolean && "Expect boolean"); return value.getAsBoolean().value(); } }; template struct Serde { static json::Value serialize(I v) { return json::Value(static_cast(v)); } static I deserialize(const json::Value& value) { assert(value.kind() == json::Value::Number && "Expect number"); return static_cast(value.getAsInteger().value()); } }; template requires std::is_enum_v struct Serde { static json::Value serialize(E v) { return json::Value(static_cast(v)); } static E deserialize(const json::Value& value) { assert(value.kind() == json::Value::Number && "Expect number"); return static_cast(value.getAsInteger().value()); } }; template struct Serde { static json::Value serialize(F v) { return json::Value(static_cast(v)); } static F deserialize(const json::Value& value) { assert(value.kind() == json::Value::Number && "Expect number"); return static_cast(value.getAsNumber().value()); } }; template <> struct Serde { static json::Value serialize(const char* v) { return json::Value(llvm::StringRef(v)); } }; template struct Serde { static json::Value serialize(const char (&v)[N]) { return json::Value(llvm::StringRef(v, N)); } }; template <> struct Serde { using V = std::string; static json::Value serialize(const V& v) { return json::Value(v); } static V deserialize(const json::Value& value) { assert(value.kind() == json::Value::String && "Expect a string"); return value.getAsString().value().str(); } }; template <> struct Serde { using V = std::string_view; static json::Value serialize(const V& v) { return json::Value(llvm::StringRef(v.data(), v.size())); } static V deserialize(const json::Value& value) { assert(value.kind() == json::Value::String && "Expect string"); return value.getAsString().value(); } }; template <> struct Serde { using V = llvm::StringRef; static json::Value serialize(const V& v) { return json::Value(v.str()); } static V deserialize(const json::Value& value) { assert(value.kind() == json::Value::String && "Expect string"); return value.getAsString().value(); } }; template struct Serde> { using V = llvm::SmallString; static json::Value serialize(const V& v) { return json::Value(v.str()); } static V deserialize(const json::Value& value) { assert(value.kind() == json::Value::String && "Expect string"); return V{value.getAsString().value().str()}; } }; template struct Serde { using key_type = typename Range::key_type; using mapped_type = typename Range::mapped_type; template static json::Value serialize(const Range& range, Serdes&&... serdes) { json::Object object; for(const auto& [key, value]: range) { if constexpr(std::is_constructible_v) { object.try_emplace(key, json::serialize(value, std::forward(serdes)...)); } else { object.try_emplace( llvm::formatv("{}", json::serialize(key, std::forward(serdes)...)), json::serialize(value, std::forward(serdes)...)); } } return object; } template static Range deserialize(const json::Value& value, Serdes&&... serdes) { assert(value.kind() == json::Value::Object && "JSON must be object"); Range range; for(auto& [name, value]: *value.getAsObject()) { if constexpr(std::is_constructible_v) { range.try_emplace( name, json::deserialize(value, std::forward(serdes)...)); } else { if(auto key = json::parse(name)) { range.try_emplace( json::deserialize(std::move(*key), std::forward(serdes)...), json::deserialize(value, std::forward(serdes)...)); } } } return range; } }; template struct Serde { using key_type = typename Range::key_type; template static json::Value serialize(const Range& range, Serdes&&... serdes) { json::Array array; for(const auto& element: range) { array.emplace_back(json::serialize(element, std::forward(serdes)...)); } return array; } template static Range deserialize(const json::Value& value, Serdes&&... serdes) { assert(value.kind() == json::Value::Array && "JSON must be array"); Range range; for(auto& element: *value.getAsArray()) { range.emplace(json::deserialize(element, std::forward(serdes)...)); } return range; } }; template struct Serde { using value_type = typename Range::value_type; template static json::Value serialize(const Range& range, Serdes&&... serdes) { json::Array array; for(const auto& element: range) { array.emplace_back(json::serialize(element, std::forward(serdes)...)); } return array; } template static Range deserialize(const json::Value& value, Serdes&&... serdes) { assert(value.kind() == json::Value::Array && "JSON must be array"); Range range; for(auto& element: *value.getAsArray()) { range.emplace_back( json::deserialize(element, std::forward(serdes)...)); } return range; } }; template struct Serde { static json::Value serialize(const E& e) { return json::Value(e.value()); } static E deserialize(const json::Value& value) { return E(json::deserialize(value)); } }; template constexpr inline bool is_optional_v = false; template constexpr inline bool is_optional_v> = true; template requires (!sequence_range) struct Serde { template static json::Value serialize(const T& t) { json::Object object; refl::foreach(t, [&](std::string_view name, const Field& field) { if constexpr(is_optional_v) { if(field) { object.try_emplace(llvm::StringRef(name), json::serialize(*field)); } } else { object.try_emplace(llvm::StringRef(name), json::serialize(field)); } }); return object; } template static T deserialize(const json::Value& value) { T t = {}; if constexpr(!std::is_empty_v) { assert(value.kind() == json::Value::Object && "Expect an object"); refl::foreach(t, [&](std::string_view name, auto&& member) { using Field = std::remove_cvref_t; if(auto v = value.getAsObject()->get(llvm::StringRef(name))) { if constexpr(is_optional_v) { member.emplace(json::deserialize(*v)); } else { member = json::deserialize(*v); } } }); } return t; } }; } // namespace clice::json