diff --git a/rx/include/rx/Serializer.hpp b/rx/include/rx/Serializer.hpp index a1c9c03aa..4f7fcbb72 100644 --- a/rx/include/rx/Serializer.hpp +++ b/rx/include/rx/Serializer.hpp @@ -75,7 +75,7 @@ T callDeserializeFunction(Deserializer &s) } template -concept SerializableImpl = requires(Serializer &s, const T &value) { +constexpr auto SerializableImpl = requires(Serializer &s, const T &value) { value.serialize(s); } || requires(Serializer &s, const T &value) { callSerializeFunction(s, value); @@ -84,7 +84,7 @@ concept SerializableImpl = requires(Serializer &s, const T &value) { }; template -concept DeserializableImpl = requires(Deserializer &d, T &value) { +constexpr auto DeserializableImpl = requires(Deserializer &d, T &value) { value.deserialize(d); } || requires(Deserializer &d, T &value) { value = std::remove_cvref_t::deserialize(d); @@ -99,16 +99,20 @@ concept DeserializableImpl = requires(Deserializer &d, T &value) { } || requires(Deserializer &d, T &value) { TypeSerializer>::deserialize(d, value); }; + +template +constexpr auto IsSerializable = SerializableImpl && DeserializableImpl; + } // namespace detail template -concept Serializable = - detail::SerializableImpl && detail::DeserializableImpl; +concept Serializable = detail::IsSerializable; namespace detail { -struct SerializableFieldTest { - template - requires(std::is_default_constructible_v) +template struct SerializableFieldTest { + template + requires(std::is_default_constructible_v && + !std::is_same_v && detail::IsSerializable) constexpr operator FieldT(); }; @@ -121,7 +125,7 @@ template constexpr bool isSerializableField() { std::index_sequence, std::index_sequence) { return requires { - T{(Before, SerializableAnyFieldTest{})..., SerializableFieldTest{}, + T{(Before, SerializableAnyFieldTest{})..., SerializableFieldTest{}, (After, SerializableAnyFieldTest{})...}; }; }; @@ -130,18 +134,27 @@ template constexpr bool isSerializableField() { std::make_index_sequence - I - 1>{}); } -template > -constexpr bool isSerializableFields() { +template constexpr bool isSerializableFields() { auto impl = [](std::index_sequence) { - return requires { T{(I, SerializableFieldTest{})...}; }; + return requires { T{(I, SerializableFieldTest{})...}; }; }; - return impl(std::make_index_sequence{}); + if constexpr (!std::is_class_v) { + return false; + } else { + constexpr auto fieldCount = rx::fieldCount; + + if constexpr (fieldCount == 0) { + return false; + } else { + return impl(std::make_index_sequence{}); + } + } } template -concept SerializableClass = !detail::IsRange && std::is_class_v && - rx::fieldCount > 0 && isSerializableFields(); +constexpr auto SerializableClass = + !detail::IsRange && isSerializableFields(); } // namespace detail struct Serializer { @@ -259,7 +272,8 @@ template struct TypeSerializer { } }; -template +template + requires detail::IsSerializable && detail::IsSerializable struct TypeSerializer> { static void serialize(Serializer &s, const std::pair &t) { s.serialize(t.first); @@ -276,7 +290,9 @@ struct TypeSerializer> { } }; -template struct TypeSerializer> { +template + requires(detail::IsSerializable && ...) +struct TypeSerializer> { static void serialize(Serializer &s, const std::tuple &t) { std::apply([&s](auto &value) { s.serialize(value); }, t); } @@ -288,9 +304,9 @@ template struct TypeSerializer> { template requires std::is_default_constructible_v && - requires(Serializer &s, T &object) { - s.serialize(object.size()); - s.serialize(*object.begin()); + (!detail::TriviallyRelocatable) && requires(T &object) { + requires detail::IsSerializable; + requires detail::IsSerializable; object.resize(1); object.begin() != object.end(); } @@ -334,12 +350,13 @@ struct TypeSerializer { template requires( std::is_default_constructible_v && - requires(Serializer &s, T &object) { - s.serialize(object.size()); - s.serialize(*object.begin()); + (!detail::TriviallyRelocatable) && + requires(T &object) { + requires detail::IsSerializable; + requires detail::IsSerializable; object.insert(std::move(*object.begin())); object.begin() != object.end(); - } && !requires(Serializer &s, T &object) { object.resize(1); }) + } && !requires(T &object) { object.resize(1); }) struct TypeSerializer { using item_type = std::remove_cvref_t().begin())>; @@ -373,7 +390,7 @@ struct TypeSerializer { }; namespace detail { -template struct StructSerializerBuilder { +template struct StructSerializerBuilder { static constexpr std::array> build() { StructSerializerBuilder result; @@ -425,10 +442,8 @@ private: }; } // namespace detail -template - requires(!requires { - std::index_sequence::build().size()>{}; - }) +template + requires detail::SerializableClass && (!detail::TriviallyRelocatable) struct TypeSerializer { static const auto &getFields() { static const auto fields = detail::StructSerializerBuilder::build(); @@ -458,37 +473,4 @@ struct TypeSerializer { } } }; - -// all fields are constructable at compile time overload -template - requires requires { - std::index_sequence::build().size()>{}; - } -struct TypeSerializer { - static constexpr auto fields = detail::StructSerializerBuilder::build(); - - static void serialize(Serializer &s, const T &object) { - s.serialize(sizeof(object)); - auto bytes = std::bit_cast(&object); - for (auto field : fields) { - field.serialize(s, bytes + field.offset); - } - } - - static void deserialize(Deserializer &s, T &object) { - if (s.deserialize() != sizeof(object)) { - s.setFailure(); - return; - } - - auto bytes = std::bit_cast(&object); - for (auto field : fields) { - field.deserialize(s, bytes + field.offset); - - if (s.failure()) { - return; - } - } - } -}; } // namespace rx