#pragma once #include #include #include #include "llvm/ADT/ArrayRef.h" #include "llvm/ADT/StringRef.h" #include "llvm/Support/JSON.h" #include "Support/TypeTraits.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::state; requires Serde::state; }; /// 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)...); } }; return try_each(try_each, std::forward(serdes)...); } else { 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)...); } }; 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 { 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 { 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 { 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(float v) { return json::Value(v); } static float deserialize(const json::Value& value) { assert(value.kind() == json::Value::Number && "Expect number"); return value.getAsNumber().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 = 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 = std::array; constexpr inline static bool state = stateful_serde; template static json::Value serialize(const V& v, Serdes&&... serdes) { json::Array array; for(const auto& element: v) { array.push_back(json::serialize(element, std::forward(serdes)...)); } return array; } template static V deserialize(const json::Value& value, Serdes&&... serdes) { assert(value.kind() == json::Value::Array && "Expect array"); V array; for(std::size_t i = 0; i < N; ++i) { array[i] = json::deserialize((*value.getAsArray())[i], std::forward(serdes)...); } return array; } }; template struct Serde> { using V = std::vector; constexpr inline static bool state = stateful_serde; template static json::Value serialize(const V& v, Serdes&&... serdes) { json::Array array; for(const auto& element: v) { array.push_back(json::serialize(element, std::forward(serdes)...)); } return array; } template static V deserialize(const json::Value& value, Serdes&&... serdes) { assert(value.kind() == json::Value::Array && "Expect array"); V array; for(const auto& element: *value.getAsArray()) { array.emplace_back(json::deserialize(element, std::forward(serdes)...)); } return array; } }; template struct Serde> { using V = llvm::ArrayRef; constexpr inline static bool state = stateful_serde; /// Only support serialization. template static json::Value serialize(const V& v, Serdes&&... serdes) { json::Array array; for(const auto& element: v) { array.push_back(json::serialize(element, std::forward(serdes)...)); } return array; } }; } // namespace clice::json