/* * Copyright (c) Meta Platforms, Inc. and affiliates. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include struct memory_buffer { void write(const char* begin, const char* end) { buffer_.insert(buffer_.end(), begin, end); } const char* read(std::size_t size) { assert(index_ <= buffer_.size()); if (buffer_.size() - index_ < size) { throw std::underflow_error("not enough data"); } const auto data = std::next(buffer_.data(), index_); index_ += size; return data; } bool empty() const { return index_ == buffer_.size(); } private: using buffer_type = std::vector; buffer_type buffer_; buffer_type::size_type index_ = 0; }; struct data_writer { explicit data_writer(memory_buffer& buffer) : buffer_(buffer) {} template void write_opaque(T const* data, std::size_t size) { buffer_.write( reinterpret_cast(data), reinterpret_cast(std::next(data, size))); } template void write_raw(T const& value) { write_opaque(std::addressof(value), 1); } template void write_string(T const* data, std::size_t size) { write_raw(size); write_opaque(data, size); } private: memory_buffer& buffer_; }; struct data_reader { explicit data_reader(memory_buffer& buffer) : buffer_(buffer) {} template std::pair read_opaque(std::size_t size) { const auto data = buffer_.read(size * sizeof(T)); return std::make_pair( reinterpret_cast(data), reinterpret_cast(std::next(data, size))); } template T read_raw() { const auto data = read_opaque(sizeof(T)); T out; std::copy( data.first, data.second, reinterpret_cast(std::addressof(out))); return out; } template void read_string(std::basic_string& out) { const auto data = read_opaque(read_raw()); out.append(data.first, data.second); } private: memory_buffer& buffer_; }; using namespace apache::thrift; template struct serializer { static_assert( !std::is_same::value, "no static reflection support for the given type" " - did you forget to include the reflection metadata?" " see thrift/lib/cpp2/reflection/reflection.h"); template static void serialize(T const& what, data_writer& writer) { writer.write_raw(what); } template static void deserialize(T& out, data_reader& reader) { out = reader.read_raw(); } }; template <> struct serializer { template static void serialize(T const& what, data_writer& writer) { writer.write_string(what.data(), what.size()); } template static void deserialize(T& out, data_reader& reader) { reader.read_string(out); } }; template <> struct serializer { template static void serialize(T const& what, data_writer& writer) { const auto name = fatal::enum_to_string(what, nullptr); writer.write_string(name, std::strlen(name)); } template static void deserialize(T& out, data_reader& reader) { std::string name; reader.read_string(name); out = fatal::enum_traits::parse(name); } }; template struct serializer> { template static void serialize(T const& what, data_writer& writer) { writer.write_raw(what.size()); for (const auto& i : what) { serializer::serialize(i, writer); } } template static void deserialize(T& out, data_reader& reader) { auto count = reader.read_raw(); while (count--) { out.emplace_back(); serializer::deserialize(out.back(), reader); } } }; template struct serializer> { template static void serialize(T const& what, data_writer& writer) { writer.write_raw(what.size()); for (const auto& i : what) { serializer::serialize(i, writer); } } template static void deserialize(T& out, data_reader& reader) { auto count = reader.read_raw(); while (count--) { typename T::value_type value; serializer::deserialize(value, reader); out.emplace(std::move(value)); } } }; template struct serializer> { template static void serialize(T const& what, data_writer& writer) { writer.write_raw(what.size()); for (const auto& i : what) { serializer::serialize(i.first, writer); serializer::serialize(i.second, writer); } } template static void deserialize(T& out, data_reader& reader) { auto count = reader.read_raw(); while (count--) { typename T::key_type key; serializer::deserialize(key, reader); auto& value = out[std::move(key)]; serializer::deserialize(value, reader); } } }; struct struct_member_serializer { template void operator()( fatal::indexed, T const& what, data_writer& writer) const { const auto& value = typename Member::getter{}(what); serializer::serialize(value, writer); } }; struct struct_member_deserializer { template void operator()( fatal::indexed, T& out, data_reader& reader) const { auto& member_ref = typename Member::getter{}(out); serializer::deserialize(member_ref, reader); } }; template <> struct serializer { template static void serialize(T const& what, data_writer& writer) { fatal::foreach::members>( struct_member_serializer(), what, writer); } template static void deserialize(T& out, data_reader& reader) { fatal::foreach::members>( struct_member_deserializer(), out, reader); } }; struct variant_member_serializer { template void operator()( fatal::indexed, T const& variant, data_writer& writer) const { using name = typename Member::metadata::name; writer.write_string(fatal::z_data(), fatal::size::value); const auto& value = Member::get(variant); using type_class = typename Member::metadata::type_class; serializer::serialize(value, writer); } }; struct variant_member_deserializer { template void operator()(fatal::tag, T& out, data_reader& reader) const { Member::set(out); auto& value = Member::get(out); using type_class = typename Member::metadata::type_class; serializer::deserialize(value, reader); } }; struct get_variant_member_name { template using apply = typename Member::metadata::name; }; template <> struct serializer { template static void serialize(T const& what, data_writer& writer) { bool found = fatal::scalar_search< typename fatal::variant_traits::descriptors, fatal::get_type::id>( what.getType(), variant_member_serializer(), what, writer); if (!found) { writer.write_string("", 0); } } template static void deserialize(T& out, data_reader& reader) { std::string which; reader.read_string(which); bool found = fatal::trie_find< typename fatal::variant_traits::descriptors, get_variant_member_name>( which.begin(), which.end(), variant_member_deserializer(), out, reader); if (!found) { fatal::variant_traits::clear(out); } } }; template void serialize(T const& what, data_writer& writer) { serializer>::serialize(what, writer); } template void deserialize(T& out, data_reader& reader) { serializer>::deserialize(out, reader); } template void test(T const& what) { try { memory_buffer buffer; data_writer writer(buffer); serialize(what, writer); data_reader reader(buffer); T deserialized; deserialize(deserialized, reader); if (!buffer.empty()) { throw std::runtime_error("found unused bytes after deserializing"); } if (what != deserialized) { throw std::runtime_error("mismatch between input and deserialized data"); } std::cout << "success\n"; } catch (const std::exception& e) { std::cout << "FAILURE: " << e.what() << '\n'; } } int main() { std::cerr << "example 1: "; test(static_reflection::demo::data_constants::example_1()); std::cerr << "example 2: "; test(static_reflection::demo::data_constants::example_2()); std::cerr << "example 3: "; test(static_reflection::demo::data_constants::example_3()); return 0; }