#pragma once #include #include #include #include #include "Ranges.h" #include "TypeTraits.h" #include "Enum.h" #include "Struct.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; /// Check if the serde if given type is stateful. template concept stateful_serde = requires { Serde::stateful; requires Serde::stateful; }; /// Serialize an object to a JSON value. template json::Value serialize(const V& v, Serdes&&... serdes) { if constexpr(!stateful_serde) { return Serde::serialize(v); } else if constexpr(sizeof...(Serdes) > 0) { using S = Serde; if constexpr((std::is_same_v> || ...)) { auto try_each = [&](auto& self, First&& first, Rest&&... rest) { if constexpr(std::is_same_v, S>) { /// If we already have a direct serde, use it. return std::forward(first).serialize(v); } else if constexpr(sizeof...(rest) > 0) { /// Try the next serde. return self(self, std::forward(rest)...); } else { static_assert(dependent_false, "Unexpected control flow"); } }; return try_each(try_each, std::forward(serdes)...); } else { /// Otherwise, pass the serdes to the next serde. return Serde::serialize(v, std::forward(serdes)...); } } else { static_assert(dependent_false, "Stateful serde requires at least one serde"); } } /// Deserialize a JSON value to an object. template T deserialize(const json::Value& value, Serdes&&... serdes) { if constexpr(!stateful_serde) { return Serde::deserialize(value); } else if constexpr(sizeof...(Serdes) > 0) { using S = Serde; if constexpr((std::is_same_v> || ...)) { auto try_each = [&](auto& self, First&& first, Rest&&... rest) { if constexpr(std::is_same_v, S>) { /// If we already have a direct serde, use it. return std::forward(first).deserialize(value); } else if constexpr(sizeof...(rest) > 0) { /// Try the next serde. return self(self, std::forward(rest)...); } else { static_assert(dependent_false, "Unexpected control flow"); } }; return try_each(try_each, std::forward(serdes)...); } else { /// Otherwise, pass the serdes to the next serde. return Serde::deserialize(value, std::forward(serdes)...); } } else { static_assert(dependent_false, "Stateful Serde requires at least one serde"); } } template <> struct Serde { /// Never use json::Value as a serde. }; 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; constexpr inline static bool stateful = stateful_serde || stateful_serde; 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; constexpr inline static bool stateful = stateful_serde; 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; constexpr inline static bool stateful = stateful_serde; 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 struct Serde { constexpr inline static bool stateful = refl::member_types::apply([] { return (stateful_serde || ...); }); template static json::Value serialize(const T& t, Serdes&&... serdes) { json::Object object; refl::foreach(t, [&](std::string_view name, auto& member) { object.try_emplace(llvm::StringRef(name), json::serialize(member, std::forward(serdes)...)); }); return object; } template static T deserialize(const json::Value& value, Serdes&&... serdes) { 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) { if(auto v = value.getAsObject()->get(llvm::StringRef(name))) { member = json::deserialize>( *v, std::forward(serdes)...); } }); } return t; } }; } // namespace clice::json