/* * 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" namespace ser { template void set_size(seastar::simple_output_stream& os, const T& obj) { serialize(os, get_sizeof(obj)); } template void set_size(seastar::measuring_output_stream& os, const T& obj) { serialize(os, uint32_t(0)); } template void set_size(bytes_ostream& 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 { 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 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 inline void deserialize_array(Input& in, Container& v, size_t sz) { deserialize_array_helper(), T>::doit(in, v, sz); } template inline void serialize(Output& out, const std::vector& v) { safe_serialize_as_uint32(out, v.size()); serialize_array(out, v); } template inline std::vector deserialize(Input& in, boost::type>) { auto sz = deserialize(in, boost::type()); std::vector v; v.reserve(sz); deserialize_array(in, v, sz); return v; } template inline void serialize(Output& out, const std::chrono::duration& d) { serialize(out, d.count()); }; template inline std::chrono::duration deserialize(Input& in, boost::type>) { return std::chrono::duration(deserialize(in, boost::type())); }; template inline void serialize(Output& out, const std::array& v) { serialize_array(out, v); } template inline std::array deserialize(Input& in, boost::type>) { std::array v; deserialize_array(in, v, N); return v; } template inline void serialize(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 inline std::map deserialize(Input& in, boost::type>) { 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 void serialize(Output& out, const bytes_view& v) { safe_serialize_as_uint32(out, uint32_t(v.size())); out.write(reinterpret_cast(v.begin()), v.size()); } template void serialize(Output& out, const managed_bytes& v) { safe_serialize_as_uint32(out, uint32_t(v.size())); out.write(reinterpret_cast(v.begin()), v.size()); } template void serialize(Output& out, const bytes& v) { safe_serialize_as_uint32(out, uint32_t(v.size())); out.write(reinterpret_cast(v.begin()), v.size()); } template bytes deserialize(Input& in, boost::type) { auto sz = deserialize(in, boost::type()); bytes v(bytes::initialized_later(), sz); in.read(reinterpret_cast(v.begin()), sz); return v; } template void serialize(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 bytes_ostream deserialize(Input& in, boost::type) { bytes_ostream v; v.write(deserialize(in, boost::type())); return v; } template inline void serialize(Output& out, const std::experimental::optional& v) { serialize(out, bool(v)); if (v) { serialize(out, v.value()); } } template inline std::experimental::optional deserialize(Input& in, boost::type>) { std::experimental::optional v; auto b = deserialize(in, boost::type()); if (b) { v = deserialize(in, boost::type()); } return v; } template void serialize(Output& out, const sstring& v) { safe_serialize_as_uint32(out, uint32_t(v.size())); out.write(v.begin(), v.size()); } template sstring deserialize(Input& in, boost::type) { auto sz = deserialize(in, boost::type()); sstring v(sstring::initialized_later(), sz); in.read(v.begin(), sz); return v; } template inline void serialize(Output& out, const std::unique_ptr& v) { serialize(out, bool(v)); if (v) { serialize(out, *v); } } template inline std::unique_ptr deserialize(Input& in, boost::type>) { std::unique_ptr v; auto b = deserialize(in, boost::type()); if (b) { v = std::make_unique(deserialize(in, boost::type())); } return v; } template inline void serialize(Output& out, const std::chrono::time_point& v) { serialize(out, uint64_t(v.time_since_epoch().count())); } template inline std::chrono::time_point deserialize(Input& in, boost::type>) { return typename Clock::time_point(Duration(deserialize(in, boost::type()))); } template inline void serialize(Output& out, const enum_set& v) { serialize(out, uint64_t(v.mask())); } template inline enum_set deserialize(Input& in, boost::type>) { return enum_set::from_mask(deserialize(in, boost::type())); } 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()), 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 seastar::simple_input_stream as_input_stream(bytes_view b) { return seastar::simple_input_stream(reinterpret_cast(b.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) { 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)}; } }