#pragma once #include #include "convert.hpp" #include "for_each_field.hpp" #include "stream.hpp" #include #include #include #include #include #include #include #include namespace eosio { template void from_bin(T& obj, S& stream); template void varuint32_from_bin(uint32_t& dest, S& stream) { dest = 0; int shift = 0; uint8_t b = 0; do { check( shift < 35, convert_stream_error(stream_error::invalid_varuint_encoding) ); from_bin(b, stream); dest |= uint32_t(b & 0x7f) << shift; shift += 7; } while (b & 0x80); } template void varuint64_from_bin(uint64_t& dest, S& stream) { dest = 0; int shift = 0; uint8_t b = 0; do { check( shift < 70, convert_stream_error(stream_error::invalid_varuint_encoding) ); from_bin(b, stream); dest |= uint64_t(b & 0x7f) << shift; shift += 7; } while (b & 0x80); } template void varint32_from_bin(int32_t& result, S& stream) { uint32_t v; varuint32_from_bin(v, stream); if (v & 1) result = ((~v) >> 1) | 0x8000'0000; else result = v >> 1; } template void from_bin_assoc(T& v, S& stream) { uint32_t size; varuint32_from_bin(size, stream); for (size_t i = 0; i < size; ++i) { typename T::value_type elem; from_bin(elem, stream); v.emplace(elem); } } template void from_bin_sequence(T& v, S& stream) { uint32_t size; varuint32_from_bin(size, stream); for (size_t i = 0; i < size; ++i) { v.emplace_back(); from_bin(v.back(), stream); } } template void from_bin(T (&v)[N], S& stream) { uint32_t size; varuint32_from_bin(size, stream); check( size == N, convert_stream_error(stream_error::array_size_mismatch) ); if constexpr (has_bitwise_serialization()) { stream.read(reinterpret_cast(v), size * sizeof(T)); } else { for (size_t i = 0; i < size; ++i) { from_bin(v[i], stream); } } } template void from_bin(std::vector& v, S& stream) { if constexpr (has_bitwise_serialization()) { if constexpr (sizeof(size_t) >= 8) { uint64_t size; varuint64_from_bin(size, stream); stream.check_available(size * sizeof(T)); v.resize(size); stream.read(reinterpret_cast(v.data()), size * sizeof(T)); } else { uint32_t size; varuint32_from_bin(size, stream); stream.check_available(size * sizeof(T)); v.resize(size); stream.read(reinterpret_cast(v.data()), size * sizeof(T)); } } else { uint32_t size; varuint32_from_bin(size, stream); v.resize(size); for (size_t i = 0; i < size; ++i) { from_bin(v[i], stream); } } } template void from_bin(std::set& v, S& stream) { return from_bin_assoc(v, stream); } template void from_bin(std::map& v, S& stream) { uint32_t size; varuint32_from_bin(size, stream); for (size_t i = 0; i < size; ++i) { std::pair elem; from_bin(elem, stream); v.emplace(elem); } } template void from_bin(std::deque& v, S& stream) { return from_bin_sequence(v, stream); } template void from_bin(std::list& v, S& stream) { return from_bin_sequence(v, stream); } template void from_bin(input_stream& obj, S& stream) { if constexpr (sizeof(size_t) >= 8) { uint64_t size; varuint64_from_bin(size, stream); stream.check_available(size); stream.read_reuse_storage(obj.pos, size); obj.end = obj.pos + size; } else { uint32_t size; varuint32_from_bin(size, stream); stream.check_available(size); stream.read_reuse_storage(obj.pos, size); obj.end = obj.pos + size; } } template void from_bin(std::pair& obj, S& stream) { from_bin(obj.first, stream); from_bin(obj.second, stream); } template inline void from_bin(std::string& obj, S& stream) { uint32_t size; varuint32_from_bin(size, stream); obj.resize(size); stream.read(obj.data(), obj.size()); } template inline void from_bin(std::string_view& obj, S& stream) { uint32_t size; varuint32_from_bin(size, stream); obj = std::string_view(stream.get_pos(),size); stream.skip(size); } template void from_bin(std::optional& obj, S& stream) { bool present; from_bin(present, stream); if (!present) { obj.reset(); return; } obj.emplace(); from_bin(*obj, stream); } template void variant_from_bin(std::variant& v, uint32_t i, S& stream) { if constexpr (I < std::variant_size_v>) { if (i == I) { auto& x = v.template emplace(); from_bin(x, stream); } else { variant_from_bin(v, i, stream); } } else { check( false, convert_stream_error(stream_error::bad_variant_index) ); } } template void from_bin(std::variant& obj, S& stream) { uint32_t u; varuint32_from_bin(u, stream); variant_from_bin<0>(obj, u, stream); } template void from_bin(std::array& obj, S& stream) { for (T& elem : obj) { from_bin(elem, stream); } } template void from_bin_tuple(T& obj, S& stream) { if constexpr (N < std::tuple_size_v) { from_bin(std::get(obj), stream); from_bin_tuple(obj, stream); } } template void from_bin(std::tuple& obj, S& stream) { return from_bin_tuple<0>(obj, stream); } template void from_bin(T& obj, S& stream) { if constexpr (has_bitwise_serialization()) { stream.read(reinterpret_cast(&obj), sizeof(T)); } else if constexpr (std::is_same_v, void>) { for_each_field(obj, [&](auto& member) { from_bin(member, stream); }); } else { // TODO: This can operate in place for standard serializers decltype(serialize_as(obj)) temp; from_bin(temp, stream); convert(temp, obj, choose_first); } } template T from_bin(S& stream) { T obj; from_bin(obj, stream); return obj; } template void convert_from_bin(T& obj, const std::vector& bin) { input_stream stream{ bin }; return from_bin(obj, stream); } template T convert_from_bin(const std::vector& bin) { T obj; convert_from_bin(obj, bin); return obj; } } // namespace eosio