/* * Copyright 2016 ScyllaDB */ /* * This file is part of Scylla. * * Scylla is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * Scylla is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with Scylla. If not, see . */ #pragma once #include "serializer.hh" #include #include namespace ser { template void set_size(seastar::measuring_output_stream& os, const T& obj) { serialize(os, uint32_t(0)); } template void set_size(Stream& os, const T& obj) { serialize(os, get_sizeof(obj)); } template void safe_serialize_as_uint32(Output& out, uint64_t data) { if (data > std::numeric_limits::max()) { throw std::runtime_error("Size is too big for serialization"); } serialize(out, uint32_t(data)); } template constexpr bool can_serialize_fast() { return !std::is_same::value && std::is_integral::value && (sizeof(T) == 1 || __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__); } template struct serialize_array_helper; template struct serialize_array_helper { template static void doit(Output& out, const Container& v) { out.write(reinterpret_cast(v.data()), v.size() * sizeof(T)); } }; template struct serialize_array_helper { template static void doit(Output& out, const Container& v) { for (auto&& e : v) { serialize(out, e); } } }; template static inline void serialize_array(Output& out, const Container& v) { serialize_array_helper(), T>::doit(out, v); } template struct container_traits; template struct container_traits> { struct back_emplacer { std::vector& c; back_emplacer(std::vector& c_) : c(c_) {} void operator()(T&& v) { c.emplace_back(std::move(v)); } }; void resize(std::vector& c, size_t size) { c.resize(size); } }; template struct container_traits> { struct back_emplacer { utils::chunked_vector& c; back_emplacer(utils::chunked_vector& c_) : c(c_) {} void operator()(T&& v) { c.emplace_back(std::move(v)); } }; void resize(utils::chunked_vector& c, size_t size) { c.resize(size); } }; template struct container_traits> { struct back_emplacer { std::array& c; size_t idx = 0; back_emplacer(std::array& c_) : c(c_) {} void operator()(T&& v) { c[idx++] = std::move(v); } }; void resize(std::array& c, size_t size) {} }; template struct deserialize_array_helper; template struct deserialize_array_helper { template static void doit(Input& in, Container& v, size_t sz) { container_traits t; t.resize(v, sz); in.read(reinterpret_cast(v.data()), v.size() * sizeof(T)); } template static void skip(Input& in, size_t sz) { in.skip(sz * sizeof(T)); } }; template struct deserialize_array_helper { template static void doit(Input& in, Container& v, size_t sz) { typename container_traits::back_emplacer be(v); while (sz--) { be(deserialize(in, boost::type())); } } template static void skip(Input& in, size_t sz) { while (sz--) { serializer::skip(in); } } }; template static inline void deserialize_array(Input& in, Container& v, size_t sz) { deserialize_array_helper(), T>::doit(in, v, sz); } template static inline void skip_array(Input& in, size_t sz) { deserialize_array_helper(), T>::skip(in, sz); } template struct serializer> { template static std::vector read(Input& in) { auto sz = deserialize(in, boost::type()); std::vector v; v.reserve(sz); deserialize_array(in, v, sz); return v; } template static void write(Output& out, const std::vector& v) { safe_serialize_as_uint32(out, v.size()); serialize_array(out, v); } template static void skip(Input& in) { auto sz = deserialize(in, boost::type()); skip_array(in, sz); } }; template struct serializer> { template static utils::chunked_vector read(Input& in) { auto sz = deserialize(in, boost::type()); utils::chunked_vector v; v.reserve(sz); deserialize_array(in, v, sz); return v; } template static void write(Output& out, const utils::chunked_vector& v) { safe_serialize_as_uint32(out, v.size()); serialize_array(out, v); } template static void skip(Input& in) { auto sz = deserialize(in, boost::type()); skip_array(in, sz); } }; template struct serializer> { template static std::chrono::duration read(Input& in) { return std::chrono::duration(deserialize(in, boost::type())); } template static void write(Output& out, const std::chrono::duration& d) { serialize(out, d.count()); } template static void skip(Input& in) { read(in); } }; template struct serializer> { using value_type = std::chrono::time_point; template static value_type read(Input& in) { return typename Clock::time_point(Duration(deserialize(in, boost::type()))); } template static void write(Output& out, const value_type& v) { serialize(out, uint64_t(v.time_since_epoch().count())); } template static void skip(Input& in) { read(in); } }; template struct serializer> { template static std::array read(Input& in) { std::array v; deserialize_array(in, v, N); return v; } template static void write(Output& out, const std::array& v) { serialize_array(out, v); } template static void skip(Input& in) { skip_array(in, N); } }; template struct serializer> { template static std::map read(Input& in) { auto sz = deserialize(in, boost::type()); std::map m; while (sz--) { K k = deserialize(in, boost::type()); V v = deserialize(in, boost::type()); m[k] = v; } return m; } template static void write(Output& out, const std::map& v) { safe_serialize_as_uint32(out, v.size()); for (auto&& e : v) { serialize(out, e.first); serialize(out, e.second); } } template static void skip(Input& in) { auto sz = deserialize(in, boost::type()); while (sz--) { serializer::skip(in); serializer::skip(in); } } }; template struct serializer> { template static std::unordered_map read(Input& in) { auto sz = deserialize(in, boost::type()); std::unordered_map m; m.reserve(sz); while (sz--) { auto k = deserialize(in, boost::type()); auto v = deserialize(in, boost::type()); m.emplace(std::move(k), std::move(v)); } return m; } template static void write(Output& out, const std::unordered_map& v) { safe_serialize_as_uint32(out, v.size()); for (auto&& e : v) { serialize(out, e.first); serialize(out, e.second); } } template static void skip(Input& in) { auto sz = deserialize(in, boost::type()); while (sz--) { serializer::skip(in); serializer::skip(in); } } }; template struct serializer> { template static bool_class read(Input& in) { return bool_class(deserialize(in, boost::type())); } template static void write(Output& out, bool_class v) { serialize(out, bool(v)); } template static void skip(Input& in) { read(in); } }; template class deserialized_bytes_proxy { Stream _stream; template friend class deserialized_bytes_proxy; public: explicit deserialized_bytes_proxy(Stream stream) : _stream(std::move(stream)) { } template>> deserialized_bytes_proxy(deserialized_bytes_proxy proxy) : _stream(std::move(proxy._stream)) { } auto view() const { if constexpr (std::is_same_v) { return bytes_view(reinterpret_cast(_stream.begin()), _stream.size()); } else { using iterator_type = typename Stream::iterator_type ; GCC6_CONCEPT(static_assert(FragmentRange>)); return seastar::with_serialized_stream(_stream, seastar::make_visitor( [&] (typename seastar::memory_input_stream::simple stream) { return buffer_view(bytes_view(reinterpret_cast(stream.begin()), stream.size())); }, [&] (typename seastar::memory_input_stream::fragmented stream) { return buffer_view(bytes_view(reinterpret_cast(stream.first_fragment_data()), stream.first_fragment_size()), stream.size(), stream.fragment_iterator()); } )); } } [[gnu::always_inline]] operator bytes() && { bytes v(bytes::initialized_later(), _stream.size()); _stream.read(reinterpret_cast(v.begin()), _stream.size()); return v; } [[gnu::always_inline]] operator managed_bytes() && { managed_bytes v(managed_bytes::initialized_later(), _stream.size()); _stream.read(reinterpret_cast(v.begin()), _stream.size()); return v; } [[gnu::always_inline]] operator bytes_ostream() && { bytes_ostream v; _stream.copy_to(v); return v; } }; template<> struct serializer { template static deserialized_bytes_proxy read(Input& in) { auto sz = deserialize(in, boost::type()); return deserialized_bytes_proxy(in.read_substream(sz)); } template static void write(Output& out, bytes_view v) { safe_serialize_as_uint32(out, uint32_t(v.size())); out.write(reinterpret_cast(v.begin()), v.size()); } template static void write(Output& out, const bytes& v) { write(out, static_cast(v)); } template static void write(Output& out, const managed_bytes& v) { write(out, static_cast(v)); } template static void write(Output& out, const bytes_ostream& v) { safe_serialize_as_uint32(out, uint32_t(v.size())); for (bytes_view frag : v.fragments()) { out.write(reinterpret_cast(frag.begin()), frag.size()); } } template GCC6_CONCEPT(requires FragmentRange) static void write_fragmented(Output& out, FragmentedBuffer&& fragments) { safe_serialize_as_uint32(out, uint32_t(fragments.size_bytes())); using boost::range::for_each; for_each(fragments, [&out] (bytes_view frag) { out.write(reinterpret_cast(frag.begin()), frag.size()); }); } template static void skip(Input& in) { auto sz = deserialize(in, boost::type()); in.skip(sz); } }; template void serialize(Output& out, const bytes_view& v) { serializer::write(out, v); } template void serialize(Output& out, const managed_bytes& v) { serializer::write(out, v); } template void serialize(Output& out, const bytes_ostream& v) { serializer::write(out, v); } template GCC6_CONCEPT(requires FragmentRange) void serialize_fragmented(Output& out, FragmentedBuffer&& v) { serializer::write_fragmented(out, std::forward(v)); } template struct serializer> { template static std::experimental::optional read(Input& in) { std::experimental::optional v; auto b = deserialize(in, boost::type()); if (b) { v = deserialize(in, boost::type()); } return v; } template static void write(Output& out, const std::experimental::optional& v) { serialize(out, bool(v)); if (v) { serialize(out, v.value()); } } template static void skip(Input& in) { auto present = deserialize(in, boost::type()); if (present) { serializer::skip(in); } } }; template<> struct serializer { template static sstring read(Input& in) { auto sz = deserialize(in, boost::type()); sstring v(sstring::initialized_later(), sz); in.read(v.begin(), sz); return v; } template static void write(Output& out, const sstring& v) { safe_serialize_as_uint32(out, uint32_t(v.size())); out.write(v.begin(), v.size()); } template static void skip(Input& in) { in.skip(deserialize(in, boost::type())); } }; template struct serializer> { template static std::unique_ptr read(Input& in) { std::unique_ptr v; auto b = deserialize(in, boost::type()); if (b) { v = std::make_unique(deserialize(in, boost::type())); } return v; } template static void write(Output& out, const std::unique_ptr& v) { serialize(out, bool(v)); if (v) { serialize(out, *v); } } template static void skip(Input& in) { auto present = deserialize(in, boost::type()); if (present) { serializer::skip(in); } } }; template struct serializer> { template static enum_set read(Input& in) { return enum_set::from_mask(deserialize(in, boost::type())); } template static void write(Output& out, enum_set v) { serialize(out, uint64_t(v.mask())); } template static void skip(Input& in) { read(in); } }; template size_type get_sizeof(const T& obj) { seastar::measuring_output_stream ms; serialize(ms, obj); auto size = ms.size(); if (size > std::numeric_limits::max()) { throw std::runtime_error("Object is too big for get_sizeof"); } return size; } template Buffer serialize_to_buffer(const T& v, size_t head_space) { seastar::measuring_output_stream measure; ser::serialize(measure, v); Buffer ret(typename Buffer::initialized_later(), measure.size() + head_space); seastar::simple_output_stream out(reinterpret_cast(ret.begin()), ret.size(), head_space); ser::serialize(out, v); return ret; } template T deserialize_from_buffer(const Buffer& buf, boost::type type, size_t head_space) { seastar::simple_input_stream in(reinterpret_cast(buf.begin() + head_space), buf.size() - head_space); return deserialize(in, std::move(type)); } inline utils::input_stream as_input_stream(bytes_view b) { return utils::input_stream::simple(reinterpret_cast(b.begin()), b.size()); } inline utils::input_stream as_input_stream(const bytes_ostream& b) { if (b.is_linearized()) { return as_input_stream(b.view()); } return utils::input_stream::fragmented(b.fragments().begin(), b.size()); } template void serialize(Output& out, const boost::variant& v) {} template boost::variant deserialize(Input& in, boost::type>) { return boost::variant(); } template void serialize(Output& out, const unknown_variant_type& v) { out.write(v.data.begin(), v.data.size()); } template unknown_variant_type deserialize(Input& in, boost::type) { return seastar::with_serialized_stream(in, [] (auto& in) { auto size = deserialize(in, boost::type()); auto index = deserialize(in, boost::type()); auto sz = size - sizeof(size_type) * 2; sstring v(sstring::initialized_later(), sz); in.read(v.begin(), sz); return unknown_variant_type{ index, std::move(v) }; }); } }