From e4ef0f1a1c2dfed5fd6c93806376a6b4d0a7add1 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Tue, 21 May 2024 17:41:37 +0800 Subject: [PATCH 01/26] sync code --- .../ylt/standalone/iguana/detail/pb_type.hpp | 135 +++++ .../iguana/detail/string_resize.hpp | 131 +++++ .../ylt/standalone/iguana/detail/traits.hpp | 34 ++ include/ylt/standalone/iguana/pb_reader.hpp | 260 +++++++++ include/ylt/standalone/iguana/pb_util.hpp | 539 ++++++++++++++++++ include/ylt/standalone/iguana/pb_writer.hpp | 215 +++++++ include/ylt/standalone/iguana/reflection.hpp | 143 ++++- include/ylt/standalone/iguana/util.hpp | 6 - include/ylt/standalone/iguana/version.hpp | 2 +- 9 files changed, 1452 insertions(+), 13 deletions(-) create mode 100644 include/ylt/standalone/iguana/detail/pb_type.hpp create mode 100644 include/ylt/standalone/iguana/detail/string_resize.hpp create mode 100644 include/ylt/standalone/iguana/pb_reader.hpp create mode 100644 include/ylt/standalone/iguana/pb_util.hpp create mode 100644 include/ylt/standalone/iguana/pb_writer.hpp diff --git a/include/ylt/standalone/iguana/detail/pb_type.hpp b/include/ylt/standalone/iguana/detail/pb_type.hpp new file mode 100644 index 000000000..2ce5f60b1 --- /dev/null +++ b/include/ylt/standalone/iguana/detail/pb_type.hpp @@ -0,0 +1,135 @@ +#pragma once + +namespace iguana { + +struct sint32_t { + using value_type = int32_t; + int32_t val; + bool operator==(const sint32_t& other) const { return val == other.val; } +}; + +inline bool operator==(sint32_t value1, int32_t value2) { + return value1.val == value2; +} + +// for key in std::map +inline bool operator<(const sint32_t& lhs, const sint32_t& rhs) { + return lhs.val < rhs.val; +} + +struct sint64_t { + using value_type = int64_t; + int64_t val; + bool operator==(const sint64_t& other) const { return val == other.val; } +}; + +inline bool operator==(sint64_t value1, int64_t value2) { + return value1.val == value2; +} + +inline bool operator<(const sint64_t& lhs, const sint64_t& rhs) { + return lhs.val < rhs.val; +} + +struct fixed32_t { + using value_type = uint32_t; + uint32_t val; + bool operator==(const fixed32_t& other) const { return val == other.val; } +}; + +inline bool operator==(fixed32_t value1, uint32_t value2) { + return value1.val == value2; +} + +inline bool operator<(const fixed32_t& lhs, const fixed32_t& rhs) { + return lhs.val < rhs.val; +} + +struct fixed64_t { + using value_type = uint64_t; + uint64_t val; + bool operator==(const fixed64_t& other) const { return val == other.val; } +}; + +inline bool operator==(fixed64_t value1, uint64_t value2) { + return value1.val == value2; +} + +inline bool operator<(const fixed64_t& lhs, const fixed64_t& rhs) { + return lhs.val < rhs.val; +} + +struct sfixed32_t { + using value_type = int32_t; + int32_t val; + bool operator==(const sfixed32_t& other) const { return val == other.val; } +}; + +inline bool operator==(sfixed32_t value1, int32_t value2) { + return value1.val == value2; +} + +inline bool operator<(const sfixed32_t& lhs, const sfixed32_t& rhs) { + return lhs.val < rhs.val; +} + +struct sfixed64_t { + using value_type = int64_t; + int64_t val; + bool operator==(const sfixed64_t& other) const { return val == other.val; } +}; + +inline bool operator==(sfixed64_t value1, int64_t value2) { + return value1.val == value2; +} + +inline bool operator<(const sfixed64_t& lhs, const sfixed64_t& rhs) { + return lhs.val < rhs.val; +} + +} // namespace iguana + +// for key in std::unordered_map +namespace std { +template <> +struct hash { + size_t operator()(const iguana::sint32_t& x) const noexcept { + return std::hash()(x.val); + } +}; + +template <> +struct hash { + size_t operator()(const iguana::sint64_t& x) const noexcept { + return std::hash()(x.val); + } +}; + +template <> +struct hash { + size_t operator()(const iguana::fixed32_t& x) const noexcept { + return std::hash()(x.val); + } +}; + +template <> +struct hash { + size_t operator()(const iguana::fixed64_t& x) const noexcept { + return std::hash()(x.val); + } +}; + +template <> +struct hash { + size_t operator()(const iguana::sfixed32_t& x) const noexcept { + return std::hash()(x.val); + } +}; + +template <> +struct hash { + size_t operator()(const iguana::sfixed64_t& x) const noexcept { + return std::hash()(x.val); + } +}; +} // namespace std diff --git a/include/ylt/standalone/iguana/detail/string_resize.hpp b/include/ylt/standalone/iguana/detail/string_resize.hpp new file mode 100644 index 000000000..81d4605e5 --- /dev/null +++ b/include/ylt/standalone/iguana/detail/string_resize.hpp @@ -0,0 +1,131 @@ +#pragma once +#include +#include +#include +#include + +namespace iguana::detail { + +#if __cpp_lib_string_resize_and_overwrite >= 202110L +template +inline void resize(std::basic_string &str, std::size_t sz) { + str.resize_and_overwrite(sz, [sz](ch *, std::size_t) { + return sz; + }); +} +#elif (defined(_MSC_VER) && _MSC_VER <= 1920) +// old msvc don't support visit private, discard it. + +#else + +template +class string_thief { + public: + friend void string_set_length_hacker(std::string &self, std::size_t sz) { +#if defined(_MSVC_STL_VERSION) + (self.*func_ptr)._Myval2._Mysize = sz; +#else +#if defined(_LIBCPP_VERSION) + (self.*func_ptr)(sz); +#else +#if (_GLIBCXX_USE_CXX11_ABI == 0) && defined(__GLIBCXX__) + (self.*func_ptr)()->_M_set_length_and_sharable(sz); +#else +#if defined(__GLIBCXX__) + (self.*func_ptr)(sz); +#endif +#endif +#endif +#endif + } +}; + +#if defined(__GLIBCXX__) // libstdc++ +#if (_GLIBCXX_USE_CXX11_ABI == 0) +template class string_thief; +#else +template class string_thief; +#endif +#elif defined(_LIBCPP_VERSION) +template class string_thief; +#elif defined(_MSVC_STL_VERSION) +template class string_thief; +#endif + +void string_set_length_hacker(std::string &, std::size_t); + +template +inline void resize(std::basic_string &raw_str, std::size_t sz) { + std::string &str = *reinterpret_cast(&raw_str); +#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) || \ + defined(_MSVC_STL_VERSION) + if (sz > str.capacity()) { + str.reserve(sz); + } + string_set_length_hacker(str, sz); + str[sz] = '\0'; +#else + raw_str.resize(sz); +#endif +} + +#endif + +#if (defined(_MSC_VER) && _MSC_VER <= 1920) +#else +void vector_set_length_hacker(std::vector &self, std::size_t sz); + +template +class vector_thief { + public: + friend void vector_set_length_hacker(std::vector &self, + std::size_t sz) { +#if defined(_MSVC_STL_VERSION) + (self.*func_ptr)._Myval2._Mylast = self.data() + sz; +#else +#if defined(_LIBCPP_VERSION) +#if _LIBCPP_VERSION < 14000 + ((*(std::__vector_base > *)(&self)).*func_ptr) = + self.data() + sz; +#else + (self.*func_ptr) = self.data() + sz; +#endif +#else +#if defined(__GLIBCXX__) + ((*(std::_Vector_base > *)(&self)).*func_ptr) + ._M_finish = self.data() + sz; +#endif +#endif +#endif + } +}; + +#if defined(__GLIBCXX__) // libstdc++ +template class vector_thief::_M_impl), + &std::vector::_M_impl>; +#elif defined(_LIBCPP_VERSION) +template class vector_thief::__end_), + &std::vector::__end_>; +#elif defined(_MSVC_STL_VERSION) +template class vector_thief::_Mypair), + &std::vector::_Mypair>; +#endif + +template +inline void resize(std::vector &raw_vec, std::size_t sz) { +#if defined(__GLIBCXX__) || \ + (defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_ASAN)) || \ + defined(_MSVC_STL_VERSION) + std::vector &vec = *reinterpret_cast *>(&raw_vec); + vec.reserve(sz); + vector_set_length_hacker(vec, sz); +#else + raw_vec.resize(sz); +#endif +} +#endif +}; // namespace iguana::detail \ No newline at end of file diff --git a/include/ylt/standalone/iguana/detail/traits.hpp b/include/ylt/standalone/iguana/detail/traits.hpp index 64f082e03..57a9fa45d 100644 --- a/include/ylt/standalone/iguana/detail/traits.hpp +++ b/include/ylt/standalone/iguana/detail/traits.hpp @@ -79,5 +79,39 @@ struct member_tratis { template inline constexpr bool is_int64_v = std::is_same_v || std::is_same_v; + +template +struct is_variant : std::false_type {}; + +template +struct is_variant> : std::true_type {}; + +template +struct member_traits { + using value_type = T; +}; + +template +struct member_traits { + using owner_type = Owner; + using value_type = T; +}; + +template +using member_value_type_t = typename member_traits::value_type; + +template +struct variant_type_at { + using type = T; +}; + +template +struct variant_type_at::value>> { + using type = std::variant_alternative_t; +}; +template +using variant_type_at_t = + typename variant_type_at::value_type, I>::type; + } // namespace iguana #endif // SERIALIZE_TRAITS_HPP diff --git a/include/ylt/standalone/iguana/pb_reader.hpp b/include/ylt/standalone/iguana/pb_reader.hpp new file mode 100644 index 000000000..8d10fe084 --- /dev/null +++ b/include/ylt/standalone/iguana/pb_reader.hpp @@ -0,0 +1,260 @@ +#pragma once +#include "detail/string_resize.hpp" +#include "pb_util.hpp" + +namespace iguana { + +template +IGUANA_INLINE void from_pb(T& t, std::string_view pb_str); + +namespace detail { + +template +IGUANA_INLINE void from_pb_impl(T& val, std::string_view& pb_str, + uint32_t field_no = 0); + +template +IGUANA_INLINE void decode_pair_value(T& val, std::string_view& pb_str) { + size_t pos; + uint32_t key = detail::decode_varint(pb_str, pos); + pb_str = pb_str.substr(pos); + WireType wire_type = static_cast(key & 0b0111); + if (wire_type != detail::get_wire_type>()) { + return; + } + from_pb_impl(val, pb_str); +} + +template +IGUANA_INLINE void from_pb_impl(T& val, std::string_view& pb_str, + uint32_t field_no) { + size_t pos = 0; + if constexpr (is_reflection_v) { + size_t pos; + uint32_t size = detail::decode_varint(pb_str, pos); + pb_str = pb_str.substr(pos); + if (pb_str.size() < size) + IGUANA_UNLIKELY { + throw std::invalid_argument("Invalid fixed int value: too few bytes."); + } + if (size == 0) { + return; + } + from_pb(val, pb_str.substr(0, size)); + pb_str = pb_str.substr(size); + } + else if constexpr (is_sequence_container::value) { + using item_type = typename T::value_type; + if constexpr (is_lenprefix_v) { + // item_type non-packed + while (!pb_str.empty()) { + item_type item{}; + from_pb_impl(item, pb_str); + val.push_back(std::move(item)); + if (pb_str.empty()) { + break; + } + uint32_t key = detail::decode_varint(pb_str, pos); + uint32_t field_number = key >> 3; + if (field_number != field_no) { + break; + } + else { + pb_str = pb_str.substr(pos); + } + } + } + else { + // item_type packed + size_t pos; + uint32_t size = detail::decode_varint(pb_str, pos); + pb_str = pb_str.substr(pos); + if (pb_str.size() < size) + IGUANA_UNLIKELY { + throw std::invalid_argument( + "Invalid fixed int value: too few bytes."); + } + using item_type = typename T::value_type; + size_t start = pb_str.size(); + + while (!pb_str.empty()) { + item_type item; + from_pb_impl(item, pb_str); + val.push_back(std::move(item)); + if (start - pb_str.size() == size) { + break; + } + } + } + } + else if constexpr (is_map_container::value) { + using item_type = std::pair; + while (!pb_str.empty()) { + size_t pos; + uint32_t size = detail::decode_varint(pb_str, pos); + pb_str = pb_str.substr(pos); + if (pb_str.size() < size) + IGUANA_UNLIKELY { + throw std::invalid_argument( + "Invalid fixed int value: too few bytes."); + } + item_type item = {}; + decode_pair_value(item.first, pb_str); + decode_pair_value(item.second, pb_str); + val.emplace(std::move(item)); + + if (pb_str.empty()) { + break; + } + uint32_t key = detail::decode_varint(pb_str, pos); + uint32_t field_number = key >> 3; + if (field_number != field_no) { + break; + } + pb_str = pb_str.substr(pos); + } + } + else if constexpr (std::is_integral_v) { + val = static_cast(detail::decode_varint(pb_str, pos)); + pb_str = pb_str.substr(pos); + } + else if constexpr (detail::is_signed_varint_v) { + constexpr size_t len = sizeof(typename T::value_type); + uint64_t temp = detail::decode_varint(pb_str, pos); + if constexpr (len == 8) { + val.val = detail::decode_zigzag(temp); + } + else { + val.val = detail::decode_zigzag(static_cast(temp)); + } + pb_str = pb_str.substr(pos); + } + else if constexpr (detail::is_fixed_v) { + constexpr size_t size = sizeof(typename T::value_type); + if (pb_str.size() < size) + IGUANA_UNLIKELY { + throw std::invalid_argument("Invalid fixed int value: too few bytes."); + } + memcpy(&(val.val), pb_str.data(), size); + pb_str = pb_str.substr(size); + } + else if constexpr (std::is_same_v || std::is_same_v) { + constexpr size_t size = sizeof(T); + if (pb_str.size() < size) + IGUANA_UNLIKELY { + throw std::invalid_argument("Invalid fixed int value: too few bytes."); + } + memcpy(&(val), pb_str.data(), size); + pb_str = pb_str.substr(size); + } + else if constexpr (std::is_same_v || + std::is_same_v) { + size_t size = detail::decode_varint(pb_str, pos); + if (pb_str.size() < pos + size) + IGUANA_UNLIKELY { + throw std::invalid_argument("Invalid string value: too few bytes."); + } + if constexpr (std::is_same_v) { + val = std::string_view(pb_str.data() + pos, size); + } + else { + detail::resize(val, size); + memcpy(val.data(), pb_str.data() + pos, size); + } + pb_str = pb_str.substr(size + pos); + } + else if constexpr (std::is_enum_v) { + using U = std::underlying_type_t; + U value{}; + from_pb_impl(value, pb_str); + val = static_cast(value); + } + else if constexpr (optional_v) { + from_pb_impl(val.emplace(), pb_str); + } + else { + static_assert(!sizeof(T), "err"); + } +} + +template +IGUANA_INLINE void parse_oneof(T& t, const Field& f, std::string_view& pb_str) { + using item_type = typename std::decay_t::sub_type; + from_pb_impl(t.template emplace(), pb_str, f.field_no); +} +} // namespace detail + +template +IGUANA_INLINE void from_pb(T& t, std::string_view pb_str) { + if (pb_str.empty()) + IGUANA_UNLIKELY { return; } + size_t pos = 0; + uint32_t key = detail::decode_varint(pb_str, pos); + WireType wire_type = static_cast(key & 0b0111); + uint32_t field_number = key >> 3; +#ifdef SEQUENTIAL_PARSE + constexpr static auto tp = get_members_tuple(); + constexpr size_t SIZE = std::tuple_size_v>; + bool parse_done = false; + detail::for_each_n( + [&](auto i) IGUANA__INLINE_LAMBDA { + constexpr auto val = std::get(tp); + using sub_type = typename std::decay_t::sub_type; + using value_type = typename std::decay_t::value_type; + // sub_type is the element type when value_type is the variant type; + // otherwise, they are the same. + if (parse_done || field_number != val.field_no) { + return; + } + pb_str = pb_str.substr(pos); + if (wire_type != detail::get_wire_type()) + IGUANA_UNLIKELY { throw std::runtime_error("unmatched wire_type"); } + if constexpr (variant_v) { + detail::parse_oneof(val.value(t), val, pb_str); + } + else { + detail::from_pb_impl(val.value(t), pb_str, val.field_no); + } + if (pb_str.empty()) { + parse_done = true; + return; + } + key = detail::decode_varint(pb_str, pos); + wire_type = static_cast(key & 0b0111); + field_number = key >> 3; + }, + std::make_index_sequence{}); + if (parse_done) + IGUANA_LIKELY { return; } +#endif + while (true) { + pb_str = pb_str.substr(pos); + constexpr static auto map = get_members(); + auto& member = map.at(field_number); + std::visit( + [&t, &pb_str, wire_type](auto& val) { + using sub_type = typename std::decay_t::sub_type; + using value_type = typename std::decay_t::value_type; + if (wire_type != detail::get_wire_type()) { + throw std::runtime_error("unmatched wire_type"); + } + if constexpr (variant_v) { + detail::parse_oneof(val.value(t), val, pb_str); + } + else { + detail::from_pb_impl(val.value(t), pb_str, val.field_no); + } + }, + member); + if (!pb_str.empty()) + IGUANA_LIKELY { + key = detail::decode_varint(pb_str, pos); + wire_type = static_cast(key & 0b0111); + field_number = key >> 3; + } + else { + return; + } + } +} +} // namespace iguana diff --git a/include/ylt/standalone/iguana/pb_util.hpp b/include/ylt/standalone/iguana/pb_util.hpp new file mode 100644 index 000000000..44c26af57 --- /dev/null +++ b/include/ylt/standalone/iguana/pb_util.hpp @@ -0,0 +1,539 @@ +#pragma once +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "detail/pb_type.hpp" +#include "reflection.hpp" +#include "util.hpp" + +namespace iguana { + +enum class WireType : uint32_t { + Varint = 0, + Fixed64 = 1, + LengthDelimeted = 2, + StartGroup = 3, + EndGroup = 4, + Fixed32 = 5, + Unknown +}; + +struct pb_base { + size_t cache_size; +}; + +template +constexpr bool inherits_from_pb_base_v = std::is_base_of_v; + +namespace detail { +template +constexpr bool is_fixed_v = + std::is_same_v || std::is_same_v || + std::is_same_v || std::is_same_v; + +template +constexpr bool is_signed_varint_v = + std::is_same_v || std::is_same_v; + +template +constexpr inline WireType get_wire_type() { + if constexpr (std::is_integral_v || is_signed_varint_v || + std::is_enum_v || std::is_same_v) { + return WireType::Varint; + } + else if constexpr (std::is_same_v || + std::is_same_v || + std::is_same_v) { + return WireType::Fixed32; + } + else if constexpr (std::is_same_v || + std::is_same_v || + std::is_same_v) { + return WireType::Fixed64; + } + else if constexpr (std::is_same_v || + std::is_same_v || + is_reflection_v || is_sequence_container::value || + is_map_container::value) { + return WireType::LengthDelimeted; + } + else if constexpr (optional_v) { + return get_wire_type(); + } + else { + throw std::runtime_error("unknown type"); + } +} + +template +constexpr bool is_lenprefix_v = (get_wire_type() == + WireType::LengthDelimeted); + +[[nodiscard]] IGUANA_INLINE uint32_t encode_zigzag(int32_t v) { + return (static_cast(v) << 1U) ^ + static_cast( + -static_cast(static_cast(v) >> 31U)); +} +[[nodiscard]] IGUANA_INLINE uint64_t encode_zigzag(int64_t v) { + return (static_cast(v) << 1U) ^ + static_cast( + -static_cast(static_cast(v) >> 63U)); +} + +[[nodiscard]] IGUANA_INLINE int64_t decode_zigzag(uint64_t u) { + return static_cast((u >> 1U)) ^ + static_cast(-static_cast(u & 1U)); +} +[[nodiscard]] IGUANA_INLINE int64_t decode_zigzag(uint32_t u) { + return static_cast((u >> 1U)) ^ + static_cast(-static_cast(u & 1U)); +} + +template +IGUANA_INLINE uint64_t decode_varint(T& data, size_t& pos) { + const int8_t* begin = reinterpret_cast(data.data()); + const int8_t* end = begin + data.size(); + const int8_t* p = begin; + uint64_t val = 0; + + if ((static_cast(*p) & 0x80) == 0) { + pos = 1; + return static_cast(*p); + } + + // end is always greater than or equal to begin, so this subtraction is safe + if (size_t(end - begin) >= 10) + IGUANA_LIKELY { // fast path + int64_t b; + do { + b = *p++; + val = (b & 0x7f); + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 7; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 14; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 21; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 28; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 35; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 42; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 49; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x7f) << 56; + if (b >= 0) { + break; + } + b = *p++; + val |= (b & 0x01) << 63; + if (b >= 0) { + break; + } + throw std::invalid_argument("Invalid varint value: too many bytes."); + } while (false); + } + else { + int shift = 0; + while (p != end && *p < 0) { + val |= static_cast(*p++ & 0x7f) << shift; + shift += 7; + } + if (p == end) + IGUANA_UNLIKELY { + throw std::invalid_argument("Invalid varint value: too few bytes."); + } + val |= static_cast(*p++) << shift; + } + + pos = (p - begin); + return val; +} + +// value == 0 ? 1 : floor(log2(value)) / 7 + 1 +constexpr size_t variant_uint32_size_constexpr(uint32_t value) { + if (value == 0) { + return 1; + } + int log = 0; + while (value >>= 1) ++log; + return log / 7 + 1; +} + +template +IGUANA_INLINE void append_varint_u32_constexpr_help(It&& it) { + *(it++) = static_cast((v >> (7 * I)) | 0x80); +} + +template +IGUANA_INLINE void append_varint_u32_constexpr(It&& it, + std::index_sequence) { + (append_varint_u32_constexpr_help(it), ...); +} + +template +IGUANA_INLINE void serialize_varint_u32_constexpr(It&& it) { + constexpr auto size = variant_uint32_size_constexpr(v); + append_varint_u32_constexpr(it, std::make_index_sequence{}); + *(it++) = static_cast(v >> (7 * (size - 1))); +} + +template +IGUANA_INLINE void serialize_varint(uint64_t v, It&& it) { + if (v < 0x80) { + *(it++) = static_cast(v); + return; + } + *(it++) = static_cast(v | 0x80); + v >>= 7; + if (v < 0x80) { + *(it++) = static_cast(v); + return; + } + do { + *(it++) = static_cast(v | 0x80); + v >>= 7; + } while (v >= 0x80); + *(it++) = static_cast(v); +} + +IGUANA_INLINE uint32_t log2_floor_uint32(uint32_t n) { +#if defined(__GNUC__) + return 31 ^ static_cast(__builtin_clz(n)); +#else + unsigned long where; + _BitScanReverse(&where, n); + return where; +#endif +} + +IGUANA_INLINE size_t variant_uint32_size(uint32_t value) { + // This computes value == 0 ? 1 : floor(log2(value)) / 7 + 1 + // Use an explicit multiplication to implement the divide of + // a number in the 1..31 range. + // Explicit OR 0x1 to avoid calling Bits::Log2FloorNonZero(0), which is + // undefined. + uint32_t log2value = log2_floor_uint32(value | 0x1); + return static_cast((log2value * 9 + 73) / 64); +} + +IGUANA_INLINE uint32_t log2_floor_uint64(uint64_t n) { +#if defined(__GNUC__) + return 63 ^ static_cast(__builtin_clzll(n)); +#else + unsigned long where; + _BitScanReverse64(&where, n); + return where; +#endif +} + +IGUANA_INLINE size_t variant_uint64_size(uint64_t value) { + // This computes value == 0 ? 1 : floor(log2(value)) / 7 + 1 + // Use an explicit multiplication to implement the divide of + // a number in the 1..63 range. + // Explicit OR 0x1 to avoid calling Bits::Log2FloorNonZero(0), which is + // undefined. + uint32_t log2value = log2_floor_uint64(value | 0x1); + return static_cast((log2value * 9 + 73) / 64); +} + +template +constexpr IGUANA_INLINE size_t variant_intergal_size(U value) { + using T = std::remove_reference_t; + if constexpr (sizeof(T) == 8) { + return variant_uint64_size(static_cast(value)); + } + else if constexpr (sizeof(T) <= 4) { + if constexpr (std::is_signed_v) { + if (value < 0) { + return 10; + } + } + return variant_uint32_size(static_cast(value)); + } + else { + static_assert(!sizeof(T), "intergal in not supported"); + } +} + +template +IGUANA_INLINE constexpr void for_each_n(F&& f, std::index_sequence) { + (std::forward(f)(std::integral_constant{}), ...); +} + +// cache the size of reflection type +template +IGUANA_INLINE auto& get_set_size_cache(T& t) { + static std::map cache; + return cache[reinterpret_cast(&t)]; +} + +template +IGUANA_INLINE size_t numeric_size(T&& t) { + using value_type = std::remove_const_t>; + if constexpr (omit_default_val) { + if constexpr (is_fixed_v || is_signed_varint_v) { + if (t.val == 0) + IGUANA_UNLIKELY { return 0; } + } + else { + if (t == static_cast(0)) + IGUANA_UNLIKELY { return 0; } + } + } + if constexpr (std::is_integral_v) { + if constexpr (std::is_same_v) { + return 1 + key_size; + } + else { + return key_size + variant_intergal_size(t); + } + } + else if constexpr (detail::is_signed_varint_v) { + return key_size + variant_intergal_size(encode_zigzag(t.val)); + } + else if constexpr (detail::is_fixed_v) { + return key_size + sizeof(typename value_type::value_type); + } + else if constexpr (std::is_same_v || + std::is_same_v) { + return key_size + sizeof(value_type); + } + else if constexpr (std::is_enum_v) { + using U = std::underlying_type_t; + return key_size + variant_intergal_size(static_cast(t)); + } + else { + static_assert(!sizeof(value_type), "err"); + } +} + +template +IGUANA_INLINE size_t pb_key_value_size(T&& t); + +template +constexpr inline size_t get_variant_index() { + if constexpr (I == 0) { + static_assert(std::is_same_v, T>, + "Type T is not found in Variant"); + return 0; + } + else if constexpr (std::is_same_v, + T>) { + return I; + } + else { + return get_variant_index(); + } +} + +template +IGUANA_INLINE size_t pb_oneof_size(Type&& t) { + using T = std::decay_t; + int len = 0; + std::visit( + [&len](auto&& value) IGUANA__INLINE_LAMBDA { + using value_type = + std::remove_const_t>; + constexpr auto offset = + get_variant_index - 1>(); + constexpr uint32_t key = + ((field_no + offset) << 3) | + static_cast(get_wire_type()); + len = pb_key_value_size( + std::forward(value)); + }, + std::forward(t)); + return len; +} + +// returns size = key_size + optional(len_size) + len +// when key_size == 0, return len +template +IGUANA_INLINE size_t pb_key_value_size(Type&& t) { + using T = std::remove_const_t>; + if constexpr (is_reflection_v || is_custom_reflection_v) { + size_t len = 0; + constexpr auto tuple = get_members_tuple(); + constexpr size_t SIZE = std::tuple_size_v>; + for_each_n( + [&len, &t](auto i) IGUANA__INLINE_LAMBDA { + constexpr auto tuple = get_members_tuple(); + using field_type = + std::tuple_element_t>; + constexpr auto value = std::get(tuple); + using U = typename field_type::value_type; + auto& val = value.value(t); + if constexpr (variant_v) { + constexpr auto offset = + get_variant_index - 1>(); + if constexpr (offset == 0) { + len += pb_oneof_size(val); + } + } + else { + constexpr uint32_t sub_key = + (value.field_no << 3) | + static_cast(get_wire_type()); + constexpr auto sub_keysize = variant_uint32_size_constexpr(sub_key); + len += pb_key_value_size(val); + } + }, + std::make_index_sequence{}); + if constexpr (inherits_from_pb_base_v) { + t.cache_size = len; + } + else { + get_set_size_cache(t) = len; + } + if constexpr (key_size == 0) { + // for top level + return len; + } + else { + if (len == 0) { + // equals key_size + variant_uint32_size(len) + return key_size + 1; + } + else { + return key_size + variant_uint32_size(static_cast(len)) + len; + } + } + } + else if constexpr (is_sequence_container::value) { + using item_type = typename T::value_type; + size_t len = 0; + if constexpr (is_lenprefix_v) { + for (auto& item : t) { + len += pb_key_value_size(item); + } + return len; + } + else { + for (auto& item : t) { + // here 0 to get pakced size + len += numeric_size<0, false>(item); + } + if (len == 0) { + return 0; + } + else { + return key_size + variant_uint32_size(static_cast(len)) + len; + } + } + } + else if constexpr (is_map_container::value) { + size_t len = 0; + for (auto& [k, v] : t) { + // the key_size of k and v is constant 1 + size_t kv_len = + pb_key_value_size<1, false>(k) + pb_key_value_size<1, false>(v); + len += key_size + variant_uint32_size(static_cast(kv_len)) + + kv_len; + } + return len; + } + else if constexpr (optional_v) { + if (!t.has_value()) { + return 0; + } + return pb_key_value_size(*t); + } + else if constexpr (std::is_same_v || + std::is_same_v) { + if constexpr (omit_default_val) { + if (t.size() == 0) + IGUANA_UNLIKELY { return 0; } + } + if constexpr (key_size == 0) { + return t.size(); + } + else { + return key_size + variant_uint32_size(static_cast(t.size())) + + t.size(); + } + } + else { + return numeric_size(t); + } +} + +// return the payload size +template +IGUANA_INLINE size_t pb_value_size(T&& t) { + using value_type = std::remove_const_t>; + if constexpr (is_reflection_v) { + if constexpr (inherits_from_pb_base_v) { + return t.cache_size; + } + else { + return get_set_size_cache(t); + } + } + else if constexpr (is_sequence_container::value) { + using item_type = typename value_type::value_type; + size_t len = 0; + if constexpr (!is_lenprefix_v) { + for (auto& item : t) { + len += numeric_size<0, false>(item); + } + return len; + } + else { + static_assert(!sizeof(item_type), "the size of this type is meaningless"); + } + } + else if constexpr (is_map_container::value) { + static_assert(!sizeof(value_type), "the size of this type is meaningless"); + } + else if constexpr (optional_v) { + if (!t.has_value()) { + return 0; + } + return pb_value_size(*t); + } + else { + return pb_key_value_size<0>(t); + } +} + +} // namespace detail +} // namespace iguana \ No newline at end of file diff --git a/include/ylt/standalone/iguana/pb_writer.hpp b/include/ylt/standalone/iguana/pb_writer.hpp new file mode 100644 index 000000000..957d0e97b --- /dev/null +++ b/include/ylt/standalone/iguana/pb_writer.hpp @@ -0,0 +1,215 @@ +#pragma once +#include "detail/string_resize.hpp" +#include "pb_util.hpp" + +namespace iguana { +namespace detail { + +template +IGUANA_INLINE void encode_varint_field(V val, It&& it) { + static_assert(std::is_integral_v, "must be integral"); + if constexpr (key != 0) { + serialize_varint_u32_constexpr(it); + } + serialize_varint(val, it); +} + +template +IGUANA_INLINE void encode_fixed_field(V val, It&& it) { + if constexpr (key != 0) { + serialize_varint_u32_constexpr(it); + } + constexpr size_t size = sizeof(V); + // TODO: check Stream continuous + memcpy(it, &val, size); + it += size; +} + +template +IGUANA_INLINE void to_pb_impl(Type&& t, It&& it); + +template +IGUANA_INLINE void encode_pair_value(V&& val, It&& it, size_t size) { + if (size == 0) + IGUANA_UNLIKELY { + // map keys can't be omitted even if values are empty + // TODO: repeated ? + serialize_varint_u32_constexpr(it); + serialize_varint(0, it); + } + else { + to_pb_impl(val, it); + } +} + +template +IGUANA_INLINE void encode_numeric_field(T t, It&& it) { + if constexpr (omit_default_val) { + if constexpr (is_fixed_v || is_signed_varint_v) { + if (t.val == 0) { + return; + } + } + else { + if (t == static_cast(0)) + IGUANA_UNLIKELY { return; } + } + } + if constexpr (std::is_integral_v) { + detail::encode_varint_field(t, it); + } + else if constexpr (detail::is_signed_varint_v) { + detail::encode_varint_field(encode_zigzag(t.val), it); + } + else if constexpr (detail::is_fixed_v) { + detail::encode_fixed_field(t.val, it); + } + else if constexpr (std::is_same_v || std::is_same_v) { + detail::encode_fixed_field(t, it); + } + else if constexpr (std::is_enum_v) { + using U = std::underlying_type_t; + detail::encode_varint_field(static_cast(t), it); + } + else { + static_assert(!sizeof(T), "unsupported type"); + } +} + +template +IGUANA_INLINE void to_pb_oneof(Type&& t, It&& it) { + using T = std::decay_t; + std::visit( + [&it](auto&& value) IGUANA__INLINE_LAMBDA { + using value_type = + std::remove_const_t>; + constexpr auto offset = + get_variant_index - 1>(); + constexpr uint32_t key = + ((field_no + offset) << 3) | + static_cast(get_wire_type()); + to_pb_impl(std::forward(value), it); + }, + std::forward(t)); +} + +// omit_default_val = true indicates to omit the default value in searlization +template +IGUANA_INLINE void to_pb_impl(Type&& t, It&& it) { + using T = std::remove_const_t>; + if constexpr (is_reflection_v || is_custom_reflection_v) { + // TODO: improve the key serialize + auto len = pb_value_size(t); + // can't be omitted even if values are empty + if constexpr (key != 0) { + serialize_varint_u32_constexpr(it); + serialize_varint(len, it); + if (len == 0) + IGUANA_UNLIKELY { return; } + } + static constexpr auto tuple = get_members_tuple(); + constexpr size_t SIZE = std::tuple_size_v>; + for_each_n( + [&t, &it](auto i) IGUANA__INLINE_LAMBDA { + using field_type = + std::tuple_element_t>; + constexpr auto value = std::get(tuple); + auto& val = value.value(t); + + using U = typename field_type::value_type; + if constexpr (variant_v) { + constexpr auto offset = + get_variant_index - 1>(); + if constexpr (offset == 0) { + to_pb_oneof(val, it); + } + } + else { + constexpr uint32_t sub_key = + (value.field_no << 3) | + static_cast(get_wire_type()); + to_pb_impl(val, it); + } + }, + std::make_index_sequence{}); + } + else if constexpr (is_sequence_container::value) { + // TODO support std::array + // repeated values can't be omitted even if values are empty + using item_type = typename T::value_type; + if constexpr (is_lenprefix_v) { + // non-packed + for (auto& item : t) { + to_pb_impl(item, it); + } + } + else { + if (t.empty()) + IGUANA_UNLIKELY { return; } + serialize_varint_u32_constexpr(it); + serialize_varint(pb_value_size(t), it); + for (auto& item : t) { + encode_numeric_field(item, it); + } + } + } + else if constexpr (is_map_container::value) { + using first_type = typename T::key_type; + using second_type = typename T::mapped_type; + constexpr uint32_t key1 = + (1 << 3) | static_cast(get_wire_type()); + constexpr auto key1_size = variant_uint32_size_constexpr(key1); + constexpr uint32_t key2 = + (2 << 3) | static_cast(get_wire_type()); + constexpr auto key2_size = variant_uint32_size_constexpr(key2); + + for (auto& [k, v] : t) { + serialize_varint_u32_constexpr(it); + auto k_len = pb_value_size(k); + auto v_len = pb_value_size(v); + auto pair_len = key1_size + key2_size + k_len + v_len; + if constexpr (is_lenprefix_v) { + pair_len += variant_uint32_size(k_len); + } + if constexpr (is_lenprefix_v) { + pair_len += variant_uint32_size(v_len); + } + serialize_varint(pair_len, it); + // map k and v can't be omitted even if values are empty + encode_pair_value(k, it, k_len); + encode_pair_value(v, it, v_len); + } + } + else if constexpr (optional_v) { + if (!t.has_value()) { + return; + } + to_pb_impl(*t, it); + } + else if constexpr (std::is_same_v || + std::is_same_v) { + if constexpr (omit_default_val) { + if (t.size() == 0) + IGUANA_UNLIKELY { return; } + } + serialize_varint_u32_constexpr(it); + serialize_varint(t.size(), it); + memcpy(it, t.data(), t.size()); + it += t.size(); + } + else { + encode_numeric_field(t, it); + } +} +} // namespace detail + +template +IGUANA_INLINE void to_pb(T& t, Stream& out) { + auto byte_len = detail::pb_key_value_size<0>(t); + detail::resize(out, byte_len); + detail::to_pb_impl<0>(t, &out[0]); +} +} // namespace iguana diff --git a/include/ylt/standalone/iguana/reflection.hpp b/include/ylt/standalone/iguana/reflection.hpp index 234da95d6..c2ff73bdd 100644 --- a/include/ylt/standalone/iguana/reflection.hpp +++ b/include/ylt/standalone/iguana/reflection.hpp @@ -692,6 +692,143 @@ inline constexpr auto get_iguana_struct_map() { } } +template ::value_type> +struct field_t { + using member_type = T; + using owner_type = typename member_traits::owner_type; + using value_type = typename member_traits::value_type; + using sub_type = ElementType; + constexpr field_t() = default; + constexpr field_t(T member, uint32_t number, frozen::string name = "") + : member_ptr(member), field_name(name), field_no(number) {} + + T member_ptr; + frozen::string field_name; + uint32_t field_no; + + auto &value(owner_type &value) const { return value.*member_ptr; } +}; + +template +struct field_type_t; + +template +struct field_type_t> { + using value_type = std::variant; +}; + +template +struct is_custom_reflection : std::false_type {}; + +template +struct is_custom_reflection< + T, std::void_t()))>> + : std::true_type {}; + +template +struct is_reflection : std::false_type {}; + +template +inline constexpr bool is_reflection_v = is_reflection::value; + +template +inline constexpr bool is_custom_reflection_v = is_custom_reflection::value; + +template +constexpr inline auto build_variant_fields(T t, S &s, uint32_t base_idx, + std::index_sequence) { + using value_type = typename member_traits::value_type; + return std::tuple(field_t>{ + t, (base_idx + uint32_t(I)), s}...); +} + +template +constexpr inline auto build_fields(T t, S &s, uint32_t &index) { + using value_type = typename member_traits::value_type; + if constexpr (is_variant::value) { + constexpr uint32_t Size = std::variant_size_v; + index += (Size - 1); + return build_variant_fields(t, s, I + 1, std::make_index_sequence{}); + } + else { + uint32_t field_no = (I == index) ? (I + 1) : (I + index); + index++; + return std::tuple(field_t{t, field_no, s}); + } +} + +template +constexpr inline auto get_members_tuple_impl(T &&tp, U &&arr, + std::index_sequence &&) { + uint32_t index = 0; + return std::tuple_cat(build_fields(std::get(tp), arr[I], index)...); +} + +template +constexpr inline auto get_members_tuple() { + if constexpr (is_reflection::value) { + using reflect_members = decltype(iguana_reflect_type(std::declval())); + using Tuple = decltype(reflect_members::apply_impl()); + constexpr size_t Size = std::tuple_size_v; + return get_members_tuple_impl(reflect_members::apply_impl(), + reflect_members::arr(), + std::make_index_sequence{}); + } + else if constexpr (is_custom_reflection_v) { + using U = std::remove_const_t>; + return get_members_impl((U *)nullptr); + } + else { + static_assert(!sizeof(T), "expected reflection or custom reflection"); + } +} + +template +constexpr auto inline get_members_impl(Tuple &&tp, std::index_sequence) { + return frozen::unordered_map{ + {std::get(tp).field_no, + T{std::in_place_index, std::move(std::get(tp))}}...}; +} + +template +constexpr size_t count_variant_size() { + if constexpr (is_variant::value) { + return std::variant_size_v; + } + else { + return 1; + } +} + +template +constexpr size_t tuple_type_count_impl(std::index_sequence) { + return ( + (count_variant_size>>() + + ...)); +} + +template +constexpr size_t tuple_type_count() { + return tuple_type_count_impl( + std::make_index_sequence>{}); +} + +template +constexpr inline auto get_members() { + if constexpr (is_reflection_v || is_custom_reflection_v) { + constexpr auto tp = get_members_tuple(); + using Tuple = std::decay_t; + using value_type = typename field_type_t::value_type; + constexpr auto Size = tuple_type_count(); + return get_members_impl(tp, + std::make_index_sequence{}); + } + else { + static_assert(!sizeof(T), "expected reflection or custom reflection"); + } +} + #define REFLECTION(STRUCT_NAME, ...) \ MAKE_META_DATA(STRUCT_NAME, #STRUCT_NAME, GET_ARG_COUNT(__VA_ARGS__), \ __VA_ARGS__) @@ -800,9 +937,6 @@ struct is_private_reflection< template constexpr bool is_private_reflection_v = is_private_reflection::value; -template -struct is_reflection : std::false_type {}; - template struct is_reflection>> : std::true_type {}; @@ -821,9 +955,6 @@ inline auto iguana_reflect_type(const T &t) { } } -template -inline constexpr bool is_reflection_v = is_reflection::value; - template typename Condition, typename Tuple, typename Owner> constexpr int element_index_helper() { diff --git a/include/ylt/standalone/iguana/util.hpp b/include/ylt/standalone/iguana/util.hpp index 47959618a..3f6768a91 100644 --- a/include/ylt/standalone/iguana/util.hpp +++ b/include/ylt/standalone/iguana/util.hpp @@ -130,12 +130,6 @@ constexpr inline bool shared_ptr_v = template constexpr inline bool smart_ptr_v = shared_ptr_v || unique_ptr_v; -template -struct is_variant : std::false_type {}; - -template -struct is_variant> : std::true_type {}; - template constexpr inline bool variant_v = is_variant>::value; diff --git a/include/ylt/standalone/iguana/version.hpp b/include/ylt/standalone/iguana/version.hpp index 202ea4a3a..bdb1121b5 100644 --- a/include/ylt/standalone/iguana/version.hpp +++ b/include/ylt/standalone/iguana/version.hpp @@ -5,4 +5,4 @@ // IGUANA_VERSION % 100 is the sub-minor version // IGUANA_VERSION / 100 % 1000 is the minor version // IGUANA_VERSION / 100000 is the major version -#define IGUANA_VERSION 100004 // 1.0.4 \ No newline at end of file +#define IGUANA_VERSION 100005 // 1.0.5 \ No newline at end of file From bc7f3e1484b5492603210b8e17897f511c8ecb51 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 22 May 2024 11:39:10 +0800 Subject: [PATCH 02/26] add bench --- include/ylt/standalone/iguana/pb_util.hpp | 26 +-- include/ylt/struct_pb/struct_pb_reader.hpp | 18 ++ include/ylt/struct_pb/struct_pb_writer.hpp | 18 ++ include/ylt/struct_pb0.hpp | 18 ++ src/struct_pack/benchmark/benchmark.cpp | 4 +- src/struct_pack/benchmark/config.hpp | 9 +- .../benchmark/struct_pb_sample0.hpp | 211 ++++++++++++++++++ 7 files changed, 279 insertions(+), 25 deletions(-) create mode 100644 include/ylt/struct_pb/struct_pb_reader.hpp create mode 100644 include/ylt/struct_pb/struct_pb_writer.hpp create mode 100644 include/ylt/struct_pb0.hpp create mode 100644 src/struct_pack/benchmark/struct_pb_sample0.hpp diff --git a/include/ylt/standalone/iguana/pb_util.hpp b/include/ylt/standalone/iguana/pb_util.hpp index 44c26af57..43c8f8357 100644 --- a/include/ylt/standalone/iguana/pb_util.hpp +++ b/include/ylt/standalone/iguana/pb_util.hpp @@ -297,13 +297,6 @@ IGUANA_INLINE constexpr void for_each_n(F&& f, std::index_sequence) { (std::forward(f)(std::integral_constant{}), ...); } -// cache the size of reflection type -template -IGUANA_INLINE auto& get_set_size_cache(T& t) { - static std::map cache; - return cache[reinterpret_cast(&t)]; -} - template IGUANA_INLINE size_t numeric_size(T&& t) { using value_type = std::remove_const_t>; @@ -418,12 +411,10 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t) { } }, std::make_index_sequence{}); - if constexpr (inherits_from_pb_base_v) { - t.cache_size = len; - } - else { - get_set_size_cache(t) = len; - } + static_assert(inherits_from_pb_base_v, + "must be inherited from iguana::pb_base"); + t.cache_size = len; + if constexpr (key_size == 0) { // for top level return len; @@ -501,12 +492,9 @@ template IGUANA_INLINE size_t pb_value_size(T&& t) { using value_type = std::remove_const_t>; if constexpr (is_reflection_v) { - if constexpr (inherits_from_pb_base_v) { - return t.cache_size; - } - else { - return get_set_size_cache(t); - } + static_assert(inherits_from_pb_base_v>, + "must be inherited from iguana::pb_base"); + return t.cache_size; } else if constexpr (is_sequence_container::value) { using item_type = typename value_type::value_type; diff --git a/include/ylt/struct_pb/struct_pb_reader.hpp b/include/ylt/struct_pb/struct_pb_reader.hpp new file mode 100644 index 000000000..5344e7b39 --- /dev/null +++ b/include/ylt/struct_pb/struct_pb_reader.hpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2024, Alibaba Group Holding Limited; + * + * 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. + */ +#pragma once +#include +namespace struct_pb0 = iguana; diff --git a/include/ylt/struct_pb/struct_pb_writer.hpp b/include/ylt/struct_pb/struct_pb_writer.hpp new file mode 100644 index 000000000..f54e6a878 --- /dev/null +++ b/include/ylt/struct_pb/struct_pb_writer.hpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2024, Alibaba Group Holding Limited; + * + * 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. + */ +#pragma once +#include +namespace struct_pb0 = iguana; diff --git a/include/ylt/struct_pb0.hpp b/include/ylt/struct_pb0.hpp new file mode 100644 index 000000000..37f64d425 --- /dev/null +++ b/include/ylt/struct_pb0.hpp @@ -0,0 +1,18 @@ +/* + * Copyright (c) 2024, Alibaba Group Holding Limited; + * + * 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. + */ +#pragma once +#include "struct_pb/struct_pb_reader.hpp" +#include "struct_pb/struct_pb_writer.hpp" diff --git a/src/struct_pack/benchmark/benchmark.cpp b/src/struct_pack/benchmark/benchmark.cpp index f32e2e160..5b127be0f 100644 --- a/src/struct_pack/benchmark/benchmark.cpp +++ b/src/struct_pack/benchmark/benchmark.cpp @@ -1,7 +1,7 @@ #include #include #include - +#define SEQUENTIAL_PARSE #include "struct_pack_sample.hpp" #if __has_include() @@ -18,6 +18,7 @@ #include "struct_pb_sample.hpp" #endif #endif +#include "struct_pb_sample0.hpp" #ifdef HAVE_FLATBUFFER #include "flatbuffer_sample.hpp" #endif @@ -125,6 +126,7 @@ int main(int argc, char** argv) { #endif map.emplace(LibType::PROTOBUF, new protobuf_sample_t()); #endif + map.emplace(LibType::STRUCT_PB0, new struct_pb_sample0()); #ifdef HAVE_FLATBUFFER map.emplace(LibType::FLATBUFFER, new flatbuffer_sample_t()); #endif diff --git a/src/struct_pack/benchmark/config.hpp b/src/struct_pack/benchmark/config.hpp index ab80af1d8..dff85263b 100644 --- a/src/struct_pack/benchmark/config.hpp +++ b/src/struct_pack/benchmark/config.hpp @@ -11,6 +11,7 @@ inline constexpr int ITERATIONS = 1000000; enum class LibType { STRUCT_PACK, STRUCT_PB, + STRUCT_PB0, MSGPACK, PROTOBUF, FLATBUFFER, @@ -47,11 +48,9 @@ inline const std::unordered_map g_sample_name_map = { std::to_string(OBJECT_COUNT) + " monsters(with zero-copy deserialize)"}}; inline const std::unordered_map g_lib_name_map = { - {LibType::STRUCT_PACK, "struct_pack"}, - {LibType::STRUCT_PB, "struct_pb"}, - {LibType::MSGPACK, "msgpack"}, - {LibType::PROTOBUF, "protobuf"}, - {LibType::FLATBUFFER, "flatbuffer"}}; + {LibType::STRUCT_PACK, "struct_pack"}, {LibType::STRUCT_PB, "struct_pb"}, + {LibType::STRUCT_PB0, "struct_pb0"}, {LibType::MSGPACK, "msgpack"}, + {LibType::PROTOBUF, "protobuf"}, {LibType::FLATBUFFER, "flatbuffer"}}; inline const std::vector g_sample_type_vec = { SampleType::RECT, SampleType::RECTS, SampleType::PERSON, diff --git a/src/struct_pack/benchmark/struct_pb_sample0.hpp b/src/struct_pack/benchmark/struct_pb_sample0.hpp new file mode 100644 index 000000000..fb133d212 --- /dev/null +++ b/src/struct_pack/benchmark/struct_pb_sample0.hpp @@ -0,0 +1,211 @@ +#pragma once +#include + +#include "ScopedTimer.hpp" +#include "no_op.h" +#include "sample.hpp" + +namespace pb_sample0 { +struct person : public iguana::pb_base { + int32_t id; + std::string name; + int age; + double salary; +}; +REFLECTION(person, id, name, age, salary); + +struct persons : public iguana::pb_base { + std::vector list; +}; +REFLECTION(persons, list); + +struct rect : public iguana::pb_base { + int32_t x = 1; + int32_t y = 0; + int32_t width = 11; + int32_t height = 1; +}; +REFLECTION(rect, x, y, width, height); + +struct rects : public iguana::pb_base { + std::vector list; +}; +REFLECTION(rects, list); + +struct Vec3 : public iguana::pb_base { + float x; + float y; + float z; + + REFLECTION(Vec3, x, y, z); +}; + +struct Weapon : public iguana::pb_base { + std::string name; + int32_t damage; +}; +REFLECTION(Weapon, name, damage); + +enum Color : uint8_t { Red, Green, Blue }; + +struct Monster : public iguana::pb_base { + Vec3 pos; + int32_t mana; + int32_t hp; + std::string name; + std::string inventory; + Color color; + std::vector weapons; + Weapon equipped; + std::vector path; +}; +REFLECTION(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, + path); + +struct Monsters : public iguana::pb_base { + std::vector list; +}; +REFLECTION(Monsters, list); + +inline auto create_rects(size_t object_count) { + rect rc{1, 0, 11, 1}; + std::vector v{}; + for (std::size_t i = 0; i < object_count; i++) { + v.push_back(rc); + } + return v; +} + +inline auto create_persons(size_t object_count) { + std::vector v{}; + person p{0, 432798, std::string(1024, 'A'), 24, 65536.42}; + + for (std::size_t i = 0; i < object_count; i++) { + v.push_back(p); + } + return v; +} + +inline std::vector create_monsters(size_t object_count) { + std::vector v{}; + Monster m = { + 0, + Vec3{0, 1, 2, 3}, + 16, + 24, + "it is a test", + "\1\2\3\4", + Color::Red, + {{0, "gun", 42}, {0, "shotgun", 56}}, + {0, "air craft", 67}, + {{0, 7, 8, 9}, {0, 71, 81, 91}}, + }; + + Monster m1 = { + 0, + {0, 11, 22, 33}, + 161, + 241, + "it is a test, ok", + "\24\25\26\24", + Color::Red, + {{0, "gun", 421}, {0, "shotgun", 561}}, + {0, "air craft", 671}, + {{0, 71, 82, 93}, {0, 711, 821, 931}}, + }; + + for (std::size_t i = 0; i < object_count / 2; i++) { + v.push_back(m); + v.push_back(m1); + } + + if (object_count % 2 == 1) { + v.push_back(m); + } + + return v; +} +} // namespace pb_sample0 + +struct struct_pb_sample0 : public base_sample { + static inline constexpr LibType lib_type = LibType::STRUCT_PB0; + std::string name() const override { return get_lib_name(lib_type); } + + void create_samples() override { + rects_.list = {pb_sample0::create_rects(OBJECT_COUNT)}; + persons_.list = {pb_sample0::create_persons(OBJECT_COUNT)}; + monsters_.list = {pb_sample0::create_monsters(OBJECT_COUNT)}; + } + + void do_serialization() override { + serialize(SampleType::RECT, rects_.list[0]); + struct_pb0::to_pb(rects_, buffer_); + struct_pb0::to_pb(rects_, buffer_); + struct_pb0::to_pb(rects_, buffer_); + std::cout << rects_.list.size() << "\n"; + serialize(SampleType::RECTS, rects_); + serialize(SampleType::PERSON, persons_.list[0]); + serialize(SampleType::PERSONS, persons_); + serialize(SampleType::MONSTER, monsters_.list[0]); + serialize(SampleType::MONSTERS, monsters_); + } + + void do_deserialization() override { + deserialize(SampleType::RECT, rects_.list[0]); + deserialize(SampleType::RECTS, rects_); + deserialize(SampleType::PERSON, persons_.list[0]); + deserialize(SampleType::PERSONS, persons_); + deserialize(SampleType::MONSTER, monsters_.list[0]); + deserialize(SampleType::MONSTERS, monsters_); + } + + private: + template + void serialize(SampleType sample_type, T &sample) { + { + struct_pb0::to_pb(sample, buffer_); + buffer_.clear(); + + uint64_t ns = 0; + std::string bench_name = + name() + " serialize " + get_sample_name(sample_type); + + { + ScopedTimer timer(bench_name.data(), ns); + for (int i = 0; i < ITERATIONS; ++i) { + struct_pb0::to_pb(sample, buffer_); + no_op(buffer_); + no_op((char *)&sample); + } + } + ser_time_elapsed_map_.emplace(sample_type, ns); + } + buf_size_map_.emplace(sample_type, buffer_.size()); + } + template + void deserialize(SampleType sample_type, T &sample) { + buffer_.clear(); + struct_pb0::to_pb(sample, buffer_); + + U obj; + + uint64_t ns = 0; + std::string bench_name = + name() + " deserialize " + get_sample_name(sample_type); + + { + ScopedTimer timer(bench_name.data(), ns); + for (int i = 0; i < ITERATIONS; ++i) { + struct_pb0::from_pb(obj, buffer_); + no_op((char *)&obj); + no_op(buffer_); + } + } + deser_time_elapsed_map_.emplace(sample_type, ns); + } + + pb_sample0::rects rects_; + pb_sample0::persons persons_; + pb_sample0::Monsters monsters_; + std::string buffer_; +}; From 153197fa78b962ca47ada61383a129d889542a51 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 22 May 2024 15:43:35 +0800 Subject: [PATCH 03/26] update --- src/struct_pack/benchmark/protobuf_sample.hpp | 3 +-- src/struct_pack/benchmark/struct_pack_sample.hpp | 3 +-- src/struct_pack/benchmark/struct_pb_sample.hpp | 4 +--- src/struct_pack/benchmark/struct_pb_sample0.hpp | 3 +-- 4 files changed, 4 insertions(+), 9 deletions(-) diff --git a/src/struct_pack/benchmark/protobuf_sample.hpp b/src/struct_pack/benchmark/protobuf_sample.hpp index 72f98b356..b9238e5b6 100644 --- a/src/struct_pack/benchmark/protobuf_sample.hpp +++ b/src/struct_pack/benchmark/protobuf_sample.hpp @@ -211,8 +211,6 @@ struct protobuf_sample_t : public base_sample { buffer_.clear(); sample.SerializeToString(&buffer_); - T obj; - uint64_t ns = 0; std::string bench_name = name() + " deserialize " + get_sample_name(sample_type); @@ -220,6 +218,7 @@ struct protobuf_sample_t : public base_sample { { ScopedTimer timer(bench_name.data(), ns); for (int i = 0; i < ITERATIONS; ++i) { + T obj; obj.ParseFromString(buffer_); no_op((char *)&obj); no_op(buffer_); diff --git a/src/struct_pack/benchmark/struct_pack_sample.hpp b/src/struct_pack/benchmark/struct_pack_sample.hpp index 1b19bd746..7a798642b 100644 --- a/src/struct_pack/benchmark/struct_pack_sample.hpp +++ b/src/struct_pack/benchmark/struct_pack_sample.hpp @@ -148,8 +148,6 @@ struct struct_pack_sample : public base_sample { buffer_.clear(); struct_pack::serialize_to(buffer_, sample); - U obj; - uint64_t ns = 0; std::string bench_name = name() + " deserialize " + get_sample_name(sample_type); @@ -157,6 +155,7 @@ struct struct_pack_sample : public base_sample { { ScopedTimer timer(bench_name.data(), ns); for (int i = 0; i < ITERATIONS; ++i) { + U obj; [[maybe_unused]] auto ec = struct_pack::deserialize_to(obj, buffer_); no_op((char *)&obj); no_op(buffer_); diff --git a/src/struct_pack/benchmark/struct_pb_sample.hpp b/src/struct_pack/benchmark/struct_pb_sample.hpp index bfec902d0..8706f8a10 100644 --- a/src/struct_pack/benchmark/struct_pb_sample.hpp +++ b/src/struct_pack/benchmark/struct_pb_sample.hpp @@ -155,9 +155,6 @@ struct struct_pb_sample_t : public base_sample { buffer_.resize(sz); struct_pb::internal::serialize_to(buffer_.data(), buffer_.size(), sample); - T obj; - // vec.resize(ITERATIONS); - uint64_t ns = 0; std::string bench_name = name() + " deserialize " + get_sample_name(sample_type); @@ -165,6 +162,7 @@ struct struct_pb_sample_t : public base_sample { { ScopedTimer timer(bench_name.data(), ns); for (int i = 0; i < ITERATIONS; ++i) { + T obj; [[maybe_unused]] auto ok = struct_pb::internal::deserialize_to( obj, buffer_.data(), buffer_.size()); assert(ok); diff --git a/src/struct_pack/benchmark/struct_pb_sample0.hpp b/src/struct_pack/benchmark/struct_pb_sample0.hpp index fb133d212..c492ec8a2 100644 --- a/src/struct_pack/benchmark/struct_pb_sample0.hpp +++ b/src/struct_pack/benchmark/struct_pb_sample0.hpp @@ -187,8 +187,6 @@ struct struct_pb_sample0 : public base_sample { buffer_.clear(); struct_pb0::to_pb(sample, buffer_); - U obj; - uint64_t ns = 0; std::string bench_name = name() + " deserialize " + get_sample_name(sample_type); @@ -196,6 +194,7 @@ struct struct_pb_sample0 : public base_sample { { ScopedTimer timer(bench_name.data(), ns); for (int i = 0; i < ITERATIONS; ++i) { + U obj; struct_pb0::from_pb(obj, buffer_); no_op((char *)&obj); no_op(buffer_); From 54db88c3c1c351be3f78fb82d4d214b31ede5247 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 22 May 2024 15:55:00 +0800 Subject: [PATCH 04/26] clean some --- .github/workflows/s390x.yml | 2 +- .github/workflows/ubuntu_clang.yml | 2 +- .github/workflows/ubuntu_gcc.yml | 2 +- CMakeLists.txt | 1 - README.md | 6 +- cmake/struct_pb.cmake | 224 --- cmake/subdir.cmake | 3 - src/struct_pack/benchmark/CMakeLists.txt | 13 - src/struct_pb/CMakeLists.txt | 2 - src/struct_pb/conformance/CMakeLists.txt | 68 - .../conformance/absl/status/status.h | 208 --- .../conformance/absl/status/statusor.h | 20 - .../conformance/absl/strings/str_cat.h | 29 - .../conformance/absl/strings/str_format.h | 92 - .../binary_json_conformance_suite.cc | 1606 ----------------- .../binary_json_conformance_suite.h | 123 -- .../conformance/conformance/conformance.proto | 180 -- src/struct_pb/conformance/conformance_cpp.cc | 304 ---- .../conformance/conformance_struct_pb.cc | 242 --- src/struct_pb/conformance/conformance_test.cc | 526 ------ src/struct_pb/conformance/conformance_test.h | 331 ---- .../conformance/conformance_test_main.cc | 38 - .../conformance/conformance_test_runner.cc | 407 ----- .../conformance/failure_list_cpp.txt | 9 - .../conformance/google/protobuf/any.proto | 161 -- .../google/protobuf/descriptor.proto | 921 ---------- .../google/protobuf/duration.proto | 115 -- .../google/protobuf/field_mask.proto | 245 --- .../google/protobuf/source_context.proto | 48 - .../conformance/google/protobuf/struct.proto | 95 - .../protobuf/test_messages_proto2.proto | 303 ---- .../protobuf/test_messages_proto3.proto | 288 --- .../google/protobuf/timestamp.proto | 144 -- .../conformance/google/protobuf/type.proto | 187 -- .../google/protobuf/wrappers.proto | 123 -- src/struct_pb/examples/CMakeLists.txt | 27 - src/struct_pb/examples/addressbook.proto | 26 - src/struct_pb/examples/demo.proto | 50 - src/struct_pb/examples/tutorial.cpp | 104 -- src/struct_pb/protoc-plugin/CMakeLists.txt | 18 - .../protoc-plugin/EnumFieldGenerator.cpp | 328 ---- .../protoc-plugin/EnumFieldGenerator.h | 56 - src/struct_pb/protoc-plugin/EnumGenerator.cpp | 37 - src/struct_pb/protoc-plugin/EnumGenerator.h | 20 - .../protoc-plugin/FieldGenerator.cpp | 557 ------ src/struct_pb/protoc-plugin/FieldGenerator.h | 90 - src/struct_pb/protoc-plugin/FileGenerator.cpp | 199 -- src/struct_pb/protoc-plugin/FileGenerator.h | 35 - src/struct_pb/protoc-plugin/GeneratorBase.cpp | 26 - src/struct_pb/protoc-plugin/GeneratorBase.h | 15 - .../protoc-plugin/MapFieldGenerator.cpp | 298 --- .../protoc-plugin/MapFieldGenerator.h | 44 - .../protoc-plugin/MessageFieldGenerator.cpp | 149 -- .../protoc-plugin/MessageFieldGenerator.h | 38 - .../protoc-plugin/MessageGenerator.cpp | 209 --- .../protoc-plugin/MessageGenerator.h | 33 - .../protoc-plugin/OneofFieldGenerator.cpp | 323 ---- .../protoc-plugin/OneofFieldGenerator.h | 64 - src/struct_pb/protoc-plugin/Options.hpp | 10 - .../protoc-plugin/PrimitiveFieldGenerator.cpp | 453 ----- .../protoc-plugin/PrimitiveFieldGenerator.h | 59 - .../protoc-plugin/StringFieldGenerator.cpp | 185 -- .../protoc-plugin/StringFieldGenerator.h | 46 - .../protoc-plugin/StructGenerator.cpp | 71 - src/struct_pb/protoc-plugin/StructGenerator.h | 15 - src/struct_pb/protoc-plugin/helpers.cpp | 67 - src/struct_pb/protoc-plugin/helpers.hpp | 279 --- src/struct_pb/protoc-plugin/main.cpp | 9 - src/struct_pb/tests/CMakeLists.txt | 55 - src/struct_pb/tests/data_def.proto | 60 - src/struct_pb/tests/helper.hpp | 78 - src/struct_pb/tests/hex_printer.hpp | 64 - src/struct_pb/tests/main.cpp | 24 - .../tests/test_bad_identifiers.proto | 191 -- .../tests/test_large_enum_value.proto | 43 - src/struct_pb/tests/test_pb.cpp | 851 --------- src/struct_pb/tests/test_pb.proto | 127 -- .../tests/test_pb_bad_identifiers.cpp | 46 - .../tests/test_pb_benchmark_struct.cpp | 335 ---- src/struct_pb/tests/test_pb_oneof.cpp | 108 -- .../docs/zh/guide/what_is_yalantinglibs.md | 6 +- 81 files changed, 7 insertions(+), 12989 deletions(-) delete mode 100644 cmake/struct_pb.cmake delete mode 100644 src/struct_pb/CMakeLists.txt delete mode 100644 src/struct_pb/conformance/CMakeLists.txt delete mode 100644 src/struct_pb/conformance/absl/status/status.h delete mode 100644 src/struct_pb/conformance/absl/status/statusor.h delete mode 100644 src/struct_pb/conformance/absl/strings/str_cat.h delete mode 100644 src/struct_pb/conformance/absl/strings/str_format.h delete mode 100644 src/struct_pb/conformance/binary_json_conformance_suite.cc delete mode 100644 src/struct_pb/conformance/binary_json_conformance_suite.h delete mode 100644 src/struct_pb/conformance/conformance/conformance.proto delete mode 100644 src/struct_pb/conformance/conformance_cpp.cc delete mode 100644 src/struct_pb/conformance/conformance_struct_pb.cc delete mode 100644 src/struct_pb/conformance/conformance_test.cc delete mode 100644 src/struct_pb/conformance/conformance_test.h delete mode 100644 src/struct_pb/conformance/conformance_test_main.cc delete mode 100644 src/struct_pb/conformance/conformance_test_runner.cc delete mode 100644 src/struct_pb/conformance/failure_list_cpp.txt delete mode 100644 src/struct_pb/conformance/google/protobuf/any.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/descriptor.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/duration.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/field_mask.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/source_context.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/struct.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/test_messages_proto2.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/test_messages_proto3.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/timestamp.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/type.proto delete mode 100644 src/struct_pb/conformance/google/protobuf/wrappers.proto delete mode 100644 src/struct_pb/examples/CMakeLists.txt delete mode 100644 src/struct_pb/examples/addressbook.proto delete mode 100644 src/struct_pb/examples/demo.proto delete mode 100644 src/struct_pb/examples/tutorial.cpp delete mode 100644 src/struct_pb/protoc-plugin/CMakeLists.txt delete mode 100644 src/struct_pb/protoc-plugin/EnumFieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/EnumFieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/EnumGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/EnumGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/FieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/FieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/FileGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/FileGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/GeneratorBase.cpp delete mode 100644 src/struct_pb/protoc-plugin/GeneratorBase.h delete mode 100644 src/struct_pb/protoc-plugin/MapFieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/MapFieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/MessageFieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/MessageFieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/MessageGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/MessageGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/OneofFieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/OneofFieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/Options.hpp delete mode 100644 src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/StringFieldGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/StringFieldGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/StructGenerator.cpp delete mode 100644 src/struct_pb/protoc-plugin/StructGenerator.h delete mode 100644 src/struct_pb/protoc-plugin/helpers.cpp delete mode 100644 src/struct_pb/protoc-plugin/helpers.hpp delete mode 100644 src/struct_pb/protoc-plugin/main.cpp delete mode 100644 src/struct_pb/tests/CMakeLists.txt delete mode 100644 src/struct_pb/tests/data_def.proto delete mode 100644 src/struct_pb/tests/helper.hpp delete mode 100644 src/struct_pb/tests/hex_printer.hpp delete mode 100644 src/struct_pb/tests/main.cpp delete mode 100644 src/struct_pb/tests/test_bad_identifiers.proto delete mode 100644 src/struct_pb/tests/test_large_enum_value.proto delete mode 100644 src/struct_pb/tests/test_pb.cpp delete mode 100644 src/struct_pb/tests/test_pb.proto delete mode 100644 src/struct_pb/tests/test_pb_bad_identifiers.cpp delete mode 100644 src/struct_pb/tests/test_pb_benchmark_struct.cpp delete mode 100644 src/struct_pb/tests/test_pb_oneof.cpp diff --git a/.github/workflows/s390x.yml b/.github/workflows/s390x.yml index 3edac918d..613aaee9e 100644 --- a/.github/workflows/s390x.yml +++ b/.github/workflows/s390x.yml @@ -30,7 +30,7 @@ jobs: CXX=g++ CC=gcc cmake -B ${{github.workspace}}/build \ -DCMAKE_BUILD_TYPE=Debug \ - -DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF -DBUILD_STRUCT_PB=OFF -DBUILD_EXAMPLES=OFF -DBUILD_BENCHMARK=OFF + -DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF -DBUILD_EXAMPLES=OFF -DBUILD_BENCHMARK=OFF cmake --build ${{github.workspace}}/build -j cd ${{github.workspace}}/build/output/tests ./struct_pack_test diff --git a/.github/workflows/ubuntu_clang.yml b/.github/workflows/ubuntu_clang.yml index 4c772f910..4bf8f25f9 100644 --- a/.github/workflows/ubuntu_clang.yml +++ b/.github/workflows/ubuntu_clang.yml @@ -146,7 +146,7 @@ jobs: -DBUILD_WITH_LIBCXX=${{matrix.libcxx}} \ -DYLT_ENABLE_IO_URING=${{matrix.io_uring}} \ -DUSE_CCACHE=${{env.ccache}} -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17\ - -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_PACK=OFF -DBUILD_STRUCT_PB=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF + -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_PACK=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF - name: Build run: cmake --build ${{github.workspace}}/build --config ${{matrix.mode}} diff --git a/.github/workflows/ubuntu_gcc.yml b/.github/workflows/ubuntu_gcc.yml index fa02eb7ea..b50b4d45c 100644 --- a/.github/workflows/ubuntu_gcc.yml +++ b/.github/workflows/ubuntu_gcc.yml @@ -118,7 +118,7 @@ jobs: -DCMAKE_BUILD_TYPE=${{matrix.mode}} \ -DYLT_ENABLE_IO_URING=${{matrix.io_uring}} \ -DUSE_CCACHE=${{env.ccache}} \ - -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_PACK=OFF -DBUILD_STRUCT_PB=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF + -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_PACK=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF - name: Build run: cmake --build ${{github.workspace}}/build --config ${{matrix.mode}} diff --git a/CMakeLists.txt b/CMakeLists.txt index b13fec170..0ed3a088a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -22,7 +22,6 @@ if(CMAKE_PROJECT_NAME STREQUAL "yaLanTingLibs") # if ylt is top-level project include_directories(src/include) include(cmake/utils.cmake) - include(cmake/struct_pb.cmake) include(cmake/build.cmake) include(cmake/develop.cmake) # add project config, such as enable_ssl. diff --git a/README.md b/README.md index e7a8bdaeb..364c8c734 100644 --- a/README.md +++ b/README.md @@ -504,11 +504,9 @@ No dependency. No dependency. -### struct_pb (optional) +### struct_pb -In default, struct_pb wont be installed. You need install protobuf manually. - -- [protobuf](https://protobuf.dev/) +No dependency. ## Standalone sublibraries diff --git a/cmake/struct_pb.cmake b/cmake/struct_pb.cmake deleted file mode 100644 index decd4e3b0..000000000 --- a/cmake/struct_pb.cmake +++ /dev/null @@ -1,224 +0,0 @@ -function(protobuf_generate_modified) - find_package(Protobuf REQUIRED) - set(_options APPEND_PATH DESCRIPTORS) - set(_singleargs LANGUAGE OUT_VAR EXPORT_MACRO PROTOC_OUT_DIR PLUGIN PROTOC_OPTION) - if(COMMAND target_sources) - list(APPEND _singleargs TARGET) - endif() - set(_multiargs PROTOS IMPORT_DIRS GENERATE_EXTENSIONS) - - cmake_parse_arguments(protobuf_generate "${_options}" "${_singleargs}" "${_multiargs}" "${ARGN}") - - if(NOT protobuf_generate_PROTOS AND NOT protobuf_generate_TARGET) - message(SEND_ERROR "Error: protobuf_generate called without any targets or source files") - return() - endif() - - if(NOT protobuf_generate_OUT_VAR AND NOT protobuf_generate_TARGET) - message(SEND_ERROR "Error: protobuf_generate called without a target or output variable") - return() - endif() - - if(NOT protobuf_generate_LANGUAGE) - set(protobuf_generate_LANGUAGE struct_pb) - endif() - string(TOLOWER ${protobuf_generate_LANGUAGE} protobuf_generate_LANGUAGE) - - if(NOT protobuf_generate_PROTOC_OUT_DIR) - set(protobuf_generate_PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) - endif() - - set(_opt) - if(protobuf_generate_PROTOC_OPTION) - set(_opt "${protobuf_generate_PROTOC_OPTION}") - endif() - if(protobuf_generate_EXPORT_MACRO AND protobuf_generate_LANGUAGE STREQUAL cpp) - set(_opt "${opt},dllexport_decl=${protobuf_generate_EXPORT_MACRO}") - endif() - set(_opt "${_opt}:") - if(protobuf_generate_PLUGIN) - set(_plugin "--plugin=${protobuf_generate_PLUGIN}") - endif() - - if(NOT protobuf_generate_GENERATE_EXTENSIONS) - if(protobuf_generate_LANGUAGE STREQUAL cpp) - set(protobuf_generate_GENERATE_EXTENSIONS .pb.h .pb.cc) - elseif(protobuf_generate_LANGUAGE STREQUAL python) - set(protobuf_generate_GENERATE_EXTENSIONS _pb2.py) - elseif(protobuf_generate_LANGUAGE STREQUAL struct_pb) - set(protobuf_generate_GENERATE_EXTENSIONS .struct_pb.h .struct_pb.cc) - else() - message(SEND_ERROR "Error: protobuf_generate given unknown Language ${LANGUAGE}, please provide a value for GENERATE_EXTENSIONS") - return() - endif() - endif() - - if(protobuf_generate_TARGET) - get_target_property(_source_list ${protobuf_generate_TARGET} SOURCES) - foreach(_file ${_source_list}) - if(_file MATCHES "proto$") - list(APPEND protobuf_generate_PROTOS ${_file}) - endif() - endforeach() - endif() - - if(NOT protobuf_generate_PROTOS) - message(SEND_ERROR "Error: protobuf_generate could not find any .proto files") - return() - endif() - - if(protobuf_generate_APPEND_PATH) - # Create an include path for each file specified - foreach(_file ${protobuf_generate_PROTOS}) - get_filename_component(_abs_file ${_file} ABSOLUTE) - get_filename_component(_abs_path ${_abs_file} PATH) - list(FIND _protobuf_include_path ${_abs_path} _contains_already) - if(${_contains_already} EQUAL -1) - list(APPEND _protobuf_include_path -I ${_abs_path}) - endif() - endforeach() - else() - set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR}) - endif() - - foreach(DIR ${protobuf_generate_IMPORT_DIRS}) - get_filename_component(ABS_PATH ${DIR} ABSOLUTE) - list(FIND _protobuf_include_path ${ABS_PATH} _contains_already) - if(${_contains_already} EQUAL -1) - list(APPEND _protobuf_include_path -I ${ABS_PATH}) - endif() - endforeach() - - set(_generated_srcs_all) - foreach(_proto ${protobuf_generate_PROTOS}) - get_filename_component(_abs_file ${_proto} ABSOLUTE) - get_filename_component(_abs_dir ${_abs_file} DIRECTORY) - get_filename_component(_basename ${_proto} NAME_WLE) - file(RELATIVE_PATH _rel_dir ${CMAKE_CURRENT_SOURCE_DIR} ${_abs_dir}) - - set(_possible_rel_dir) - if (NOT protobuf_generate_APPEND_PATH) - set(_possible_rel_dir ${_rel_dir}/) - endif() - - set(_generated_srcs) - foreach(_ext ${protobuf_generate_GENERATE_EXTENSIONS}) - list(APPEND _generated_srcs "${protobuf_generate_PROTOC_OUT_DIR}/${_possible_rel_dir}${_basename}${_ext}") - endforeach() - - if(protobuf_generate_DESCRIPTORS AND protobuf_generate_LANGUAGE STREQUAL cpp) - set(_descriptor_file "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.desc") - set(_dll_desc_out "--descriptor_set_out=${_descriptor_file}") - list(APPEND _generated_srcs ${_descriptor_file}) - endif() - list(APPEND _generated_srcs_all ${_generated_srcs}) - - add_custom_command( - OUTPUT ${_generated_srcs} - COMMAND protobuf::protoc - ARGS --${protobuf_generate_LANGUAGE}_out ${_opt}${protobuf_generate_PROTOC_OUT_DIR} ${_plugin} ${_dll_desc_out} ${_protobuf_include_path} ${_abs_file} - DEPENDS ${_abs_file} protobuf::protoc - COMMENT "Running ${protobuf_generate_LANGUAGE} protocol buffer compiler on ${_proto}" - VERBATIM ) - endforeach() - - set_source_files_properties(${_generated_srcs_all} PROPERTIES GENERATED TRUE) - if(protobuf_generate_OUT_VAR) - set(${protobuf_generate_OUT_VAR} ${_generated_srcs_all} PARENT_SCOPE) - endif() - if(protobuf_generate_TARGET) - target_sources(${protobuf_generate_TARGET} PRIVATE ${_generated_srcs_all}) - target_include_directories(${protobuf_generate_TARGET} PUBLIC ${protobuf_generate_PROTOC_OUT_DIR}) - endif() -endfunction() - - -function(protobuf_generate_struct_pb SRCS HDRS) - cmake_parse_arguments(protobuf_generate_struct_pb "" "EXPORT_MACRO;DESCRIPTORS;OPTION" "" ${ARGN}) - - set(_proto_files "${protobuf_generate_struct_pb_UNPARSED_ARGUMENTS}") - if(NOT _proto_files) - message(SEND_ERROR "Error: PROTOBUF_GENERATE_STRUCT_PB() called without any proto files") - return() - endif() - - if(PROTOBUF_GENERATE_STRUCT_PB_APPEND_PATH) - set(_append_arg APPEND_PATH) - endif() - - if(protobuf_generate_struct_pb_DESCRIPTORS) - set(_descriptors DESCRIPTORS) - endif() - - if(protobuf_generate_struct_pb_OPTION) - set(_opt ${protobuf_generate_struct_pb_OPTION}) - endif() - - if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS) - set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}") - endif() - - if(DEFINED Protobuf_IMPORT_DIRS) - set(_import_arg IMPORT_DIRS ${Protobuf_IMPORT_DIRS}) - endif() - - set(_outvar) - protobuf_generate_modified(${_append_arg} ${_descriptors} - LANGUAGE struct_pb EXPORT_MACRO ${protobuf_generate_struct_pb_EXPORT_MACRO} - PLUGIN $ - OUT_VAR _outvar ${_import_arg} PROTOS ${_proto_files} - PROTOC_OPTION ${_opt} - ) - - set(${SRCS}) - set(${HDRS}) - if(protobuf_generate_struct_pb_DESCRIPTORS) - set(${protobuf_generate_struct_pb_DESCRIPTORS}) - endif() - - foreach(_file ${_outvar}) - if(_file MATCHES "cc$") - list(APPEND ${SRCS} ${_file}) - elseif(_file MATCHES "desc$") - list(APPEND ${protobuf_generate_struct_pb_DESCRIPTORS} ${_file}) - else() - list(APPEND ${HDRS} ${_file}) - endif() - endforeach() - set(${SRCS} ${${SRCS}} PARENT_SCOPE) - set(${HDRS} ${${HDRS}} PARENT_SCOPE) - if(protobuf_generate_struct_pb_DESCRIPTORS) - set(${protobuf_generate_struct_pb_DESCRIPTORS} "${${protobuf_generate_struct_pb_DESCRIPTORS}}" PARENT_SCOPE) - endif() -endfunction() - -function(target_protos_struct_pb target) - set(_options APPEND_PATH DESCRIPTORS) - set(_singleargs LANGUAGE EXPORT_MACRO PROTOC_OUT_DIR PLUGIN OPTION) - set(_multiargs IMPORT_DIRS PRIVATE PUBLIC) - cmake_parse_arguments(target_protos_struct_pb "${_options}" "${_singleargs}" "${_multiargs}" "${ARGN}") - set(_proto_files "${target_protos_struct_pb_PRIVATE}" "${target_protos_struct_pb_PUBLIC}") - if (NOT _proto_files) - message(SEND_ERROR "Error: TARGET_PROTOS_STRUCT_PB() called without any proto files") - return() - endif () - - if (DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS) - set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}") - endif () - - if (DEFINED Protobuf_IMPORT_DIRS) - set(_import_arg IMPORT_DIRS ${Protobuf_IMPORT_DIRS}) - endif () - - if (target_protos_struct_pb_OPTION) - set(_opt ${target_protos_struct_pb_OPTION}) - endif () - protobuf_generate_modified( - TARGET ${target} - LANGUAGE struct_pb EXPORT_MACRO ${target_protos_struct_pb_EXPORT_MACRO} - PLUGIN $ - ${_import_arg} PROTOS ${_proto_files} - PROTOC_OPTION ${_opt} - ) -endfunction() diff --git a/cmake/subdir.cmake b/cmake/subdir.cmake index 90f1a08cc..7c33792b6 100644 --- a/cmake/subdir.cmake +++ b/cmake/subdir.cmake @@ -40,7 +40,4 @@ foreach(child ${children}) endif() endif() endforeach() -if (BUILD_STRUCT_PB) - add_subdirectory(src/struct_pb) -endif() message(STATUS "--------------------------------------------") \ No newline at end of file diff --git a/src/struct_pack/benchmark/CMakeLists.txt b/src/struct_pack/benchmark/CMakeLists.txt index 450428fd9..3054843e3 100644 --- a/src/struct_pack/benchmark/CMakeLists.txt +++ b/src/struct_pack/benchmark/CMakeLists.txt @@ -15,19 +15,6 @@ if (Protobuf_FOUND) target_link_libraries(struct_pack_benchmark PRIVATE protobuf::libprotobuf) target_compile_definitions(struct_pack_benchmark PRIVATE HAVE_PROTOBUF) - if (BUILD_STRUCT_PB) - protobuf_generate_struct_pb(STRUCT_PACK_BENCHMARK_PROTO_SRCS2 - STRUCT_PACK_BENCHMARK_PROTO_HDRS2 - data_def.proto - OPTION "namespace=struct_pb_sample" - ) - target_sources(struct_pack_benchmark PRIVATE - ${STRUCT_PACK_BENCHMARK_PROTO_SRCS2} - ${STRUCT_PACK_BENCHMARK_PROTO_HDRS2} - ) - target_compile_definitions(struct_pack_benchmark PRIVATE HAVE_STRUCT_PB) - endif() - target_compile_definitions(struct_pack_benchmark PRIVATE HAVE_PROTOBUF) endif () target_compile_definitions(struct_pack_benchmark PRIVATE MSGPACK_NO_BOOST) diff --git a/src/struct_pb/CMakeLists.txt b/src/struct_pb/CMakeLists.txt deleted file mode 100644 index 0dc65fab8..000000000 --- a/src/struct_pb/CMakeLists.txt +++ /dev/null @@ -1,2 +0,0 @@ -add_subdirectory(protoc-plugin) -add_subdirectory(conformance) diff --git a/src/struct_pb/conformance/CMakeLists.txt b/src/struct_pb/conformance/CMakeLists.txt deleted file mode 100644 index 20c962de6..000000000 --- a/src/struct_pb/conformance/CMakeLists.txt +++ /dev/null @@ -1,68 +0,0 @@ -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/tests/struct_pb) -find_package(Protobuf QUIET) -if (NOT Protobuf_FOUND) - message(INFO "to build struct_pb conformance test, you must install libprotoc first") - return() -endif () -set(CMAKE_INCLUDE_CURRENT_DIR ON) -add_executable(conformance_test_runner - binary_json_conformance_suite.cc - binary_json_conformance_suite.h - conformance_test_runner.cc - conformance_test_main.cc - conformance_test.cc - conformance_test.h - ) -target_sources(conformance_test_runner PRIVATE - conformance/conformance.proto - google/protobuf/test_messages_proto2.proto - google/protobuf/test_messages_proto3.proto - ) -protobuf_generate(TARGET conformance_test_runner) -target_include_directories(conformance_test_runner PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) -target_link_libraries(conformance_test_runner PRIVATE protobuf::libprotobuf) -add_executable(conformance_cpp conformance_cpp.cc) -target_link_libraries(conformance_cpp PRIVATE protobuf::libprotobuf) -target_sources(conformance_cpp PRIVATE - conformance/conformance.proto - google/protobuf/test_messages_proto2.proto - google/protobuf/test_messages_proto3.proto - ) -protobuf_generate(TARGET conformance_cpp) -target_include_directories(conformance_cpp PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - -add_test(NAME conformance_cpp_test - COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/conformance_test_runner - --failure_list ${CMAKE_CURRENT_SOURCE_DIR}/failure_list_cpp.txt - --output_dir ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/conformance_cpp - DEPENDS conformance_test_runner conformance_cpp) - -add_executable(conformance_struct_pb - conformance_struct_pb.cc - ) -protobuf_generate_struct_pb(SRCS HDRS - conformance/conformance.proto - google/protobuf/test_messages_proto2.proto - google/protobuf/test_messages_proto3.proto - google/protobuf/any.proto - google/protobuf/descriptor.proto - google/protobuf/duration.proto - google/protobuf/field_mask.proto - google/protobuf/struct.proto - google/protobuf/timestamp.proto - google/protobuf/type.proto - google/protobuf/wrappers.proto - google/protobuf/source_context.proto - TARGET conformance_struct_pb - ) -target_sources(conformance_struct_pb PRIVATE ${SRCS} ${HDRS}) -target_include_directories(conformance_struct_pb PRIVATE ${CMAKE_CURRENT_BINARY_DIR}) - - -add_test(NAME conformance_struct_pb_test - COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/conformance_test_runner - --failure_list ${CMAKE_CURRENT_SOURCE_DIR}/failure_list_cpp.txt - --output_dir ${CMAKE_CURRENT_BINARY_DIR} - ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/conformance_struct_pb - DEPENDS conformance_test_runner conformance_struct_pb) diff --git a/src/struct_pb/conformance/absl/status/status.h b/src/struct_pb/conformance/absl/status/status.h deleted file mode 100644 index 94ebfc9cf..000000000 --- a/src/struct_pb/conformance/absl/status/status.h +++ /dev/null @@ -1,208 +0,0 @@ -#pragma once -// absl compat -#include -#include - -#include "absl/strings/str_cat.h" -// #include "google/protobuf/stubs/status.h" -namespace absl { -// using namespace google::protobuf::util; -enum class StatusCode : int { - kOk = 0, - kCancelled = 1, - kUnknown = 2, - kInvalidArgument = 3, - kDeadlineExceeded = 4, - kNotFound = 5, - kAlreadyExists = 6, - kPermissionDenied = 7, - kResourceExhausted = 8, - kFailedPrecondition = 9, - kAborted = 10, - kOutOfRange = 11, - kUnimplemented = 12, - kInternal = 13, - kUnavailable = 14, - kDataLoss = 15, - kUnauthenticated = 16, -}; -class Status { - public: - Status(StatusCode code = StatusCode::kOk, std::string_view message = {}) - : code_(code), msg_(message) {} - bool ok() const { return code_ == StatusCode::kOk; } - std::string message() const { - // fix gcc 10 - return std::string(msg_); - } - - private: - StatusCode code_; - std::string_view msg_; - friend std::ostream& operator<<(std::ostream& os, const Status& x); -}; -inline std::ostream& operator<<(std::ostream& os, const Status& x) { - os << static_cast(x.code_) << " " << x.msg_; - return os; -} -Status DataLossError(std::string_view message) { - return Status(absl::StatusCode::kDataLoss, message); -} - -StatusCode ErrnoToStatusCode(int error_number) { - switch (error_number) { - case 0: - return StatusCode::kOk; - case EINVAL: // Invalid argument - case ENAMETOOLONG: // Filename too long - case E2BIG: // Argument list too long - case EDESTADDRREQ: // Destination address required - case EDOM: // Mathematics argument out of domain of function - case EFAULT: // Bad address - case EILSEQ: // Illegal byte sequence - case ENOPROTOOPT: // Protocol not available - case ENOSTR: // Not a STREAM - case ENOTSOCK: // Not a socket - case ENOTTY: // Inappropriate I/O control operation - case EPROTOTYPE: // Protocol wrong type for socket - case ESPIPE: // Invalid seek - return StatusCode::kInvalidArgument; - case ETIMEDOUT: // Connection timed out - case ETIME: // Timer expired - return StatusCode::kDeadlineExceeded; - case ENODEV: // No such device - case ENOENT: // No such file or directory -#ifdef ENOMEDIUM - case ENOMEDIUM: // No medium found -#endif - case ENXIO: // No such device or address - case ESRCH: // No such process - return StatusCode::kNotFound; - case EEXIST: // File exists - case EADDRNOTAVAIL: // Address not available - case EALREADY: // Connection already in progress -#ifdef ENOTUNIQ - case ENOTUNIQ: // Name not unique on network -#endif - return StatusCode::kAlreadyExists; - case EPERM: // Operation not permitted - case EACCES: // Permission denied -#ifdef ENOKEY - case ENOKEY: // Required key not available -#endif - case EROFS: // Read only file system - return StatusCode::kPermissionDenied; - case ENOTEMPTY: // Directory not empty - case EISDIR: // Is a directory - case ENOTDIR: // Not a directory - case EADDRINUSE: // Address already in use - case EBADF: // Invalid file descriptor -#ifdef EBADFD - case EBADFD: // File descriptor in bad state -#endif - case EBUSY: // Device or resource busy - case ECHILD: // No child processes - case EISCONN: // Socket is connected -#ifdef EISNAM - case EISNAM: // Is a named type file -#endif -#ifdef ENOTBLK - case ENOTBLK: // Block device required -#endif - case ENOTCONN: // The socket is not connected - case EPIPE: // Broken pipe -#ifdef ESHUTDOWN - case ESHUTDOWN: // Cannot send after transport endpoint shutdown -#endif - case ETXTBSY: // Text file busy -#ifdef EUNATCH - case EUNATCH: // Protocol driver not attached -#endif - return StatusCode::kFailedPrecondition; - case ENOSPC: // No space left on device -#ifdef EDQUOT - case EDQUOT: // Disk quota exceeded -#endif - case EMFILE: // Too many open files - case EMLINK: // Too many links - case ENFILE: // Too many open files in system - case ENOBUFS: // No buffer space available - case ENODATA: // No message is available on the STREAM read queue - case ENOMEM: // Not enough space - case ENOSR: // No STREAM resources -#ifdef EUSERS - case EUSERS: // Too many users -#endif - return StatusCode::kResourceExhausted; -#ifdef ECHRNG - case ECHRNG: // Channel number out of range -#endif - case EFBIG: // File too large - case EOVERFLOW: // Value too large to be stored in data type - case ERANGE: // Result too large - return StatusCode::kOutOfRange; -#ifdef ENOPKG - case ENOPKG: // Package not installed -#endif - case ENOSYS: // Function not implemented - case ENOTSUP: // Operation not supported - case EAFNOSUPPORT: // Address family not supported -#ifdef EPFNOSUPPORT - case EPFNOSUPPORT: // Protocol family not supported -#endif - case EPROTONOSUPPORT: // Protocol not supported -#ifdef ESOCKTNOSUPPORT - case ESOCKTNOSUPPORT: // Socket type not supported -#endif - case EXDEV: // Improper link - return StatusCode::kUnimplemented; - case EAGAIN: // Resource temporarily unavailable -#ifdef ECOMM - case ECOMM: // Communication error on send -#endif - case ECONNREFUSED: // Connection refused - case ECONNABORTED: // Connection aborted - case ECONNRESET: // Connection reset - case EINTR: // Interrupted function call -#ifdef EHOSTDOWN - case EHOSTDOWN: // Host is down -#endif - case EHOSTUNREACH: // Host is unreachable - case ENETDOWN: // Network is down - case ENETRESET: // Connection aborted by network - case ENETUNREACH: // Network unreachable - case ENOLCK: // No locks available - case ENOLINK: // Link has been severed -#ifdef ENONET - case ENONET: // Machine is not on the network -#endif - return StatusCode::kUnavailable; - case EDEADLK: // Resource deadlock avoided -#ifdef ESTALE - case ESTALE: // Stale file handle -#endif - return StatusCode::kAborted; - case ECANCELED: // Operation cancelled - return StatusCode::kCancelled; - default: - return StatusCode::kUnknown; - } -} -std::string MessageForErrnoToStatus(int error_number, std::string message) { - return message + ": " + std::to_string(error_number); -} -Status ErrnoToStatus(int error_number, std::string message) { - return Status(ErrnoToStatusCode(error_number), - MessageForErrnoToStatus(error_number, message)); -} -inline Status OkStatus() { return Status(); } -Status NotFoundError(std::string_view message) { - return Status(absl::StatusCode::kNotFound, message); -} -Status InvalidArgumentError(std::string_view message) { - return Status(absl::StatusCode::kInvalidArgument, message); -} -Status UnimplementedError(std::string_view message) { - return Status(absl::StatusCode::kUnimplemented, message); -} -} // namespace absl \ No newline at end of file diff --git a/src/struct_pb/conformance/absl/status/statusor.h b/src/struct_pb/conformance/absl/status/statusor.h deleted file mode 100644 index 22d1e78a0..000000000 --- a/src/struct_pb/conformance/absl/status/statusor.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -// absl compat -#include "status.h" - -namespace absl { -template -class StatusOr { - public: - StatusOr(Status status) : status_(status) {} - StatusOr(const T& data) : data_(data) {} - Status status() const { return status_; } - T* operator->() { return &data_; } - bool ok() const { return status_.ok(); } - const T& operator*() const& { return data_; } - - private: - Status status_; - T data_; -}; -} // namespace absl \ No newline at end of file diff --git a/src/struct_pb/conformance/absl/strings/str_cat.h b/src/struct_pb/conformance/absl/strings/str_cat.h deleted file mode 100644 index fedc56cfc..000000000 --- a/src/struct_pb/conformance/absl/strings/str_cat.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma -#include - -// #include "google/protobuf/stubs/strutil.h" -// compat for absl::StrCat -namespace absl { -// using google::protobuf::StrCat; -template -std::string StrCat(const T& t) { - if constexpr (std::same_as) { - return t; - } - else if constexpr (std::integral) { - return std::to_string(t); - } - else if constexpr (std::is_enum_v) { - int n = static_cast(t); - return std::to_string(n); - } - else { - return std::string(t); - } -} - -template -std::string StrCat(const T& t, const Args&... args) { - return StrCat(t) + StrCat(args...); -} -} // namespace absl \ No newline at end of file diff --git a/src/struct_pb/conformance/absl/strings/str_format.h b/src/struct_pb/conformance/absl/strings/str_format.h deleted file mode 100644 index 2160d2e0c..000000000 --- a/src/struct_pb/conformance/absl/strings/str_format.h +++ /dev/null @@ -1,92 +0,0 @@ -#pragma once -#include -// compat only -namespace absl { -template -auto to(const T& t) { - if constexpr (std::same_as) { - return t.c_str(); - } - else { - return t; - } -} -class SimpleAppender { - public: - SimpleAppender(std::string& buffer, std::string_view format) - : buffer(buffer), format_(format) {} - void format() { - buffer += format_.substr(index); - index = format_.size(); - } - template - void format(const T& t, const Args&... args) { - while (index < format_.size()) { - if (format_[index] != '%') { - buffer += format_[index]; - index++; - continue; - } - if (index + 1 < format_.size()) { - if (format_[index + 1] == 's') { - if constexpr (std::same_as) { - buffer += t; - } - else if constexpr (std::same_as) { - buffer += t; - } - else if constexpr (std::same_as>) { - buffer += std::string(t); - } - else { - buffer += "'ERROR FORMAT'"; - } - index++; - index++; - format(args...); - } - else if (format_[index + 1] == 'd') { - if constexpr (std::integral) { - buffer += std::to_string(t); - } - else { - buffer += "'ERROR FORMAT'"; - } - index++; - index++; - format(args...); - } - else if (format_[index + 1] == 'z') { - if (index + 2 < format_.size() && format_[index + 2] == 'u') { - if constexpr (std::integral) { - buffer += std::to_string(t); - } - else { - buffer += "'ERROR FORMAT'"; - } - index++; - index++; - index++; - format(args...); - } - } - } - else { - buffer += "'maybe ERROR FORMAT'"; - break; - } - } - } - - private: - std::string& buffer; - std::string_view format_; - int index = 0; -}; -template -void StrAppendFormat(std::string* output, const char* format, - const Args&... args) { - SimpleAppender(*output, format).format(args...); - // std::cout << "result: " << *output << std::endl; -} -} // namespace absl \ No newline at end of file diff --git a/src/struct_pb/conformance/binary_json_conformance_suite.cc b/src/struct_pb/conformance/binary_json_conformance_suite.cc deleted file mode 100644 index 858bbc2db..000000000 --- a/src/struct_pb/conformance/binary_json_conformance_suite.cc +++ /dev/null @@ -1,1606 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "binary_json_conformance_suite.h" - -#include "google/protobuf/text_format.h" -#include "google/protobuf/util/json_util.h" -#include "google/protobuf/util/type_resolver_util.h" -// #include "absl/status/status.h" -#include "absl/strings/str_cat.h" -// #include "json/json.h" -#include "conformance/conformance.pb.h" -#include "conformance_test.h" -#include "google/protobuf/test_messages_proto2.pb.h" -#include "google/protobuf/test_messages_proto3.pb.h" -#include "google/protobuf/wire_format_lite.h" - -namespace proto2_messages = protobuf_test_messages::proto2; - -using conformance::ConformanceRequest; -using conformance::ConformanceResponse; -using conformance::WireFormat; -using google::protobuf::Descriptor; -using google::protobuf::FieldDescriptor; -using google::protobuf::Message; -using google::protobuf::TextFormat; -using google::protobuf::internal::WireFormatLite; -using google::protobuf::util::NewTypeResolverForDescriptorPool; -using proto2_messages::TestAllTypesProto2; -using protobuf_test_messages::proto3::TestAllTypesProto3; -using std::string; - -namespace { - -static const char kTypeUrlPrefix[] = "type.googleapis.com"; - -// The number of repetitions to use for performance tests. -// Corresponds approx to 500KB wireformat bytes. -static const size_t kPerformanceRepeatCount = 50000; - -static string GetTypeUrl(const Descriptor* message) { - return string(kTypeUrlPrefix) + "/" + message->full_name(); -} - -/* Routines for building arbitrary protos *************************************/ - -// We would use CodedOutputStream except that we want more freedom to build -// arbitrary protos (even invalid ones). - -const string empty; - -string cat(const string& a, const string& b, const string& c = empty, - const string& d = empty, const string& e = empty, - const string& f = empty, const string& g = empty, - const string& h = empty, const string& i = empty, - const string& j = empty, const string& k = empty, - const string& l = empty) { - string ret; - ret.reserve(a.size() + b.size() + c.size() + d.size() + e.size() + f.size() + - g.size() + h.size() + i.size() + j.size() + k.size() + l.size()); - ret.append(a); - ret.append(b); - ret.append(c); - ret.append(d); - ret.append(e); - ret.append(f); - ret.append(g); - ret.append(h); - ret.append(i); - ret.append(j); - ret.append(k); - ret.append(l); - return ret; -} - -// The maximum number of bytes that it takes to encode a 64-bit varint. -#define VARINT_MAX_LEN 10 - -size_t vencode64(uint64_t val, int over_encoded_bytes, char* buf) { - if (val == 0) { - buf[0] = 0; - return 1; - } - size_t i = 0; - while (val) { - uint8_t byte = val & 0x7fU; - val >>= 7; - if (val || over_encoded_bytes) - byte |= 0x80U; - buf[i++] = byte; - } - while (over_encoded_bytes--) { - assert(i < 10); - uint8_t byte = over_encoded_bytes ? 0x80 : 0; - buf[i++] = byte; - } - return i; -} - -string varint(uint64_t x) { - char buf[VARINT_MAX_LEN]; - size_t len = vencode64(x, 0, buf); - return string(buf, len); -} - -// Encodes a varint that is |extra| bytes longer than it needs to be, but still -// valid. -string longvarint(uint64_t x, int extra) { - char buf[VARINT_MAX_LEN]; - size_t len = vencode64(x, extra, buf); - return string(buf, len); -} - -// TODO: proper byte-swapping for big-endian machines. -string fixed32(void* data) { return string(static_cast(data), 4); } -string fixed64(void* data) { return string(static_cast(data), 8); } - -string delim(const string& buf) { return cat(varint(buf.size()), buf); } -string u32(uint32_t u32) { return fixed32(&u32); } -string u64(uint64_t u64) { return fixed64(&u64); } -string flt(float f) { return fixed32(&f); } -string dbl(double d) { return fixed64(&d); } -string zz32(int32_t x) { return varint(WireFormatLite::ZigZagEncode32(x)); } -string zz64(int64_t x) { return varint(WireFormatLite::ZigZagEncode64(x)); } - -string tag(uint32_t fieldnum, char wire_type) { - return varint((fieldnum << 3) | wire_type); -} - -string GetDefaultValue(FieldDescriptor::Type type) { - switch (type) { - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_ENUM: - case FieldDescriptor::TYPE_BOOL: - return varint(0); - case FieldDescriptor::TYPE_SINT32: - return zz32(0); - case FieldDescriptor::TYPE_SINT64: - return zz64(0); - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED32: - return u32(0); - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - return u64(0); - case FieldDescriptor::TYPE_FLOAT: - return flt(0); - case FieldDescriptor::TYPE_DOUBLE: - return dbl(0); - case FieldDescriptor::TYPE_STRING: - case FieldDescriptor::TYPE_BYTES: - case FieldDescriptor::TYPE_MESSAGE: - return delim(""); - default: - return ""; - } - return ""; -} - -string GetNonDefaultValue(FieldDescriptor::Type type) { - switch (type) { - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_ENUM: - case FieldDescriptor::TYPE_BOOL: - return varint(1); - case FieldDescriptor::TYPE_SINT32: - return zz32(1); - case FieldDescriptor::TYPE_SINT64: - return zz64(1); - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED32: - return u32(1); - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - return u64(1); - case FieldDescriptor::TYPE_FLOAT: - return flt(1); - case FieldDescriptor::TYPE_DOUBLE: - return dbl(1); - case FieldDescriptor::TYPE_STRING: - case FieldDescriptor::TYPE_BYTES: - return delim("a"); - case FieldDescriptor::TYPE_MESSAGE: - return delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234))); - default: - return ""; - } - return ""; -} - -#define UNKNOWN_FIELD 666 - -enum class Packed { - kUnspecified = 0, - kTrue = 1, - kFalse = 2, -}; - -const FieldDescriptor* GetFieldForType(FieldDescriptor::Type type, - bool repeated, bool is_proto3, - Packed packed = Packed::kUnspecified) { - const Descriptor* d = is_proto3 ? TestAllTypesProto3().GetDescriptor() - : TestAllTypesProto2().GetDescriptor(); - for (int i = 0; i < d->field_count(); i++) { - const FieldDescriptor* f = d->field(i); - if (f->type() == type && f->is_repeated() == repeated) { - if ((packed == Packed::kTrue && !f->is_packed()) || - (packed == Packed::kFalse && f->is_packed())) { - continue; - } - return f; - } - } - - string packed_string = ""; - const string repeated_string = repeated ? "Repeated " : "Singular "; - const string proto_string = is_proto3 ? "Proto3" : "Proto2"; - if (packed == Packed::kTrue) { - packed_string = "Packed "; - } - if (packed == Packed::kFalse) { - packed_string = "Unpacked "; - } - GOOGLE_LOG(FATAL) << "Couldn't find field with type: " - << repeated_string.c_str() << packed_string.c_str() - << FieldDescriptor::TypeName(type) << " for " - << proto_string.c_str(); - return nullptr; -} - -const FieldDescriptor* GetFieldForMapType(FieldDescriptor::Type key_type, - FieldDescriptor::Type value_type, - bool is_proto3) { - const Descriptor* d = is_proto3 ? TestAllTypesProto3().GetDescriptor() - : TestAllTypesProto2().GetDescriptor(); - for (int i = 0; i < d->field_count(); i++) { - const FieldDescriptor* f = d->field(i); - if (f->is_map()) { - const Descriptor* map_entry = f->message_type(); - const FieldDescriptor* key = map_entry->field(0); - const FieldDescriptor* value = map_entry->field(1); - if (key->type() == key_type && value->type() == value_type) { - return f; - } - } - } - - const string proto_string = is_proto3 ? "Proto3" : "Proto2"; - GOOGLE_LOG(FATAL) << "Couldn't find map field with type: " - << FieldDescriptor::TypeName(key_type) << " and " - << FieldDescriptor::TypeName(key_type) << " for " - << proto_string.c_str(); - return nullptr; -} - -const FieldDescriptor* GetFieldForOneofType(FieldDescriptor::Type type, - bool is_proto3, - bool exclusive = false) { - const Descriptor* d = is_proto3 ? TestAllTypesProto3().GetDescriptor() - : TestAllTypesProto2().GetDescriptor(); - for (int i = 0; i < d->field_count(); i++) { - const FieldDescriptor* f = d->field(i); - if (f->containing_oneof() && ((f->type() == type) ^ exclusive)) { - return f; - } - } - - const string proto_string = is_proto3 ? "Proto3" : "Proto2"; - GOOGLE_LOG(FATAL) << "Couldn't find oneof field with type: " - << FieldDescriptor::TypeName(type) << " for " - << proto_string.c_str(); - return nullptr; -} - -string UpperCase(string str) { - for (size_t i = 0; i < str.size(); i++) { - str[i] = toupper(str[i]); - } - return str; -} - -std::unique_ptr NewTestMessage(bool is_proto3) { - std::unique_ptr prototype; - if (is_proto3) { - prototype.reset(new TestAllTypesProto3()); - } - else { - prototype.reset(new TestAllTypesProto2()); - } - return prototype; -} - -bool IsProto3Default(FieldDescriptor::Type type, const string& binary_data) { - switch (type) { - case FieldDescriptor::TYPE_DOUBLE: - return binary_data == dbl(0); - case FieldDescriptor::TYPE_FLOAT: - return binary_data == flt(0); - case FieldDescriptor::TYPE_BOOL: - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_SINT64: - case FieldDescriptor::TYPE_ENUM: - return binary_data == varint(0); - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - return binary_data == u64(0); - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED32: - return binary_data == u32(0); - case FieldDescriptor::TYPE_STRING: - case FieldDescriptor::TYPE_BYTES: - return binary_data == delim(""); - default: - return false; - } -} - -} // anonymous namespace - -namespace google { -namespace protobuf { - -bool BinaryAndJsonConformanceSuite::ParseResponse( - const ConformanceResponse& response, - const ConformanceRequestSetting& setting, Message* test_message) { - const ConformanceRequest& request = setting.GetRequest(); - WireFormat requested_output = request.requested_output_format(); - const string& test_name = setting.GetTestName(); - ConformanceLevel level = setting.GetLevel(); - - switch (response.result_case()) { - case ConformanceResponse::kProtobufPayload: { - if (requested_output != conformance::PROTOBUF) { - ReportFailure(test_name, level, request, response, - absl::StrCat("Test was asked for ", - WireFormatToString(requested_output), - " output but provided PROTOBUF instead.") - .c_str()); - return false; - } - - if (!test_message->ParseFromString(response.protobuf_payload())) { - ReportFailure(test_name, level, request, response, - "Protobuf output we received from test was unparseable."); - return false; - } - - break; - } - - case ConformanceResponse::kJsonPayload: { - GOOGLE_LOG(FATAL) << "json not support: " << response.DebugString(); - break; - } - - default: - GOOGLE_LOG(FATAL) << test_name - << ": unknown payload type: " << response.result_case(); - } - - return true; -} - -void BinaryAndJsonConformanceSuite::ExpectParseFailureForProtoWithProtoVersion( - const string& proto, const string& test_name, ConformanceLevel level, - bool is_proto3) { - std::unique_ptr prototype = NewTestMessage(is_proto3); - // We don't expect output, but if the program erroneously accepts the protobuf - // we let it send its response as this. We must not leave it unspecified. - ConformanceRequestSetting setting( - level, conformance::PROTOBUF, conformance::PROTOBUF, - conformance::BINARY_TEST, *prototype, test_name, proto); - - const ConformanceRequest& request = setting.GetRequest(); - ConformanceResponse response; - string effective_test_name = absl::StrCat( - setting.ConformanceLevelToString(level), - (is_proto3 ? ".Proto3" : ".Proto2"), ".ProtobufInput.", test_name); - - RunTest(effective_test_name, request, &response); - if (response.result_case() == ConformanceResponse::kParseError) { - ReportSuccess(effective_test_name); - } - else if (response.result_case() == ConformanceResponse::kSkipped) { - ReportSkip(effective_test_name, request, response); - } - else { - ReportFailure(effective_test_name, level, request, response, - "Should have failed to parse, but didn't."); - } -} - -// Expect that this precise protobuf will cause a parse error. -void BinaryAndJsonConformanceSuite::ExpectParseFailureForProto( - const string& proto, const string& test_name, ConformanceLevel level) { - ExpectParseFailureForProtoWithProtoVersion(proto, test_name, level, true); - ExpectParseFailureForProtoWithProtoVersion(proto, test_name, level, false); -} - -// Expect that this protobuf will cause a parse error, even if it is followed -// by valid protobuf data. We can try running this twice: once with this -// data verbatim and once with this data followed by some valid data. -// -// TODO(haberman): implement the second of these. -void BinaryAndJsonConformanceSuite::ExpectHardParseFailureForProto( - const string& proto, const string& test_name, ConformanceLevel level) { - return ExpectParseFailureForProto(proto, test_name, level); -} - -void BinaryAndJsonConformanceSuite::RunValidJsonTest( - const string& test_name, ConformanceLevel level, const string& input_json, - const string& equivalent_text_format, bool is_proto3) { - // if (is_proto3) { - // RunValidJsonTest(test_name, level, input_json, equivalent_text_format); - // } else { - // TestAllTypesProto2 prototype; - // RunValidJsonTestWithMessage(test_name, level, input_json, - // equivalent_text_format, prototype); - // } -} - -void BinaryAndJsonConformanceSuite::RunValidProtobufTest( - const string& test_name, ConformanceLevel level, - const string& input_protobuf, const string& equivalent_text_format, - bool is_proto3) { - std::unique_ptr prototype = NewTestMessage(is_proto3); - - ConformanceRequestSetting setting1( - level, conformance::PROTOBUF, conformance::PROTOBUF, - conformance::BINARY_TEST, *prototype, test_name, input_protobuf); - RunValidInputTest(setting1, equivalent_text_format); - - if (is_proto3) { - ConformanceRequestSetting setting2( - level, conformance::PROTOBUF, conformance::JSON, - conformance::BINARY_TEST, *prototype, test_name, input_protobuf); - // RunValidInputTest(setting2, equivalent_text_format); - } -} - -void BinaryAndJsonConformanceSuite::RunValidBinaryProtobufTest( - const string& test_name, ConformanceLevel level, - const string& input_protobuf, bool is_proto3) { - RunValidBinaryProtobufTest(test_name, level, input_protobuf, input_protobuf, - is_proto3); -} - -void BinaryAndJsonConformanceSuite::RunValidBinaryProtobufTest( - const string& test_name, ConformanceLevel level, - const string& input_protobuf, const string& expected_protobuf, - bool is_proto3) { - std::unique_ptr prototype = NewTestMessage(is_proto3); - ConformanceRequestSetting setting( - level, conformance::PROTOBUF, conformance::PROTOBUF, - conformance::BINARY_TEST, *prototype, test_name, input_protobuf); - RunValidBinaryInputTest(setting, expected_protobuf, true); -} - -void BinaryAndJsonConformanceSuite::RunBinaryPerformanceMergeMessageWithField( - const string& test_name, const string& field_proto, bool is_proto3) { - string message_tag = tag(27, WireFormatLite::WIRETYPE_LENGTH_DELIMITED); - string message_proto = cat(message_tag, delim(field_proto)); - - string proto; - for (size_t i = 0; i < kPerformanceRepeatCount; i++) { - proto.append(message_proto); - } - - string multiple_repeated_field_proto; - for (size_t i = 0; i < kPerformanceRepeatCount; i++) { - multiple_repeated_field_proto.append(field_proto); - } - string expected_proto = - cat(message_tag, delim(multiple_repeated_field_proto)); - - RunValidBinaryProtobufTest(test_name, RECOMMENDED, proto, expected_proto, - is_proto3); -} - -void BinaryAndJsonConformanceSuite::RunValidProtobufTestWithMessage( - const string& test_name, ConformanceLevel level, const Message* input, - const string& equivalent_text_format, bool is_proto3) { - RunValidProtobufTest(test_name, level, input->SerializeAsString(), - equivalent_text_format, is_proto3); -} - -void BinaryAndJsonConformanceSuite::ExpectParseFailureForJson( - const string& test_name, ConformanceLevel level, const string& input_json) { - TestAllTypesProto3 prototype; - // We don't expect output, but if the program erroneously accepts the protobuf - // we let it send its response as this. We must not leave it unspecified. - ConformanceRequestSetting setting(level, conformance::JSON, conformance::JSON, - conformance::JSON_TEST, prototype, - test_name, input_json); - const ConformanceRequest& request = setting.GetRequest(); - ConformanceResponse response; - string effective_test_name = absl::StrCat( - setting.ConformanceLevelToString(level), ".Proto3.JsonInput.", test_name); - - RunTest(effective_test_name, request, &response); - if (response.result_case() == ConformanceResponse::kParseError) { - ReportSuccess(effective_test_name); - } - else if (response.result_case() == ConformanceResponse::kSkipped) { - ReportSkip(effective_test_name, request, response); - } - else { - ReportFailure(effective_test_name, level, request, response, - "Should have failed to parse, but didn't."); - } -} - -void BinaryAndJsonConformanceSuite::ExpectSerializeFailureForJson( - const string& test_name, ConformanceLevel level, - const string& text_format) { - TestAllTypesProto3 payload_message; - GOOGLE_CHECK(TextFormat::ParseFromString(text_format, &payload_message)) - << "Failed to parse: " << text_format; - - TestAllTypesProto3 prototype; - ConformanceRequestSetting setting( - level, conformance::PROTOBUF, conformance::JSON, conformance::JSON_TEST, - prototype, test_name, payload_message.SerializeAsString()); - const ConformanceRequest& request = setting.GetRequest(); - ConformanceResponse response; - string effective_test_name = absl::StrCat( - setting.ConformanceLevelToString(level), ".", test_name, ".JsonOutput"); - - RunTest(effective_test_name, request, &response); - if (response.result_case() == ConformanceResponse::kSerializeError) { - ReportSuccess(effective_test_name); - } - else if (response.result_case() == ConformanceResponse::kSkipped) { - ReportSkip(effective_test_name, request, response); - } - else { - ReportFailure(effective_test_name, level, request, response, - "Should have failed to serialize, but didn't."); - } -} - -void BinaryAndJsonConformanceSuite::TestPrematureEOFForType( - FieldDescriptor::Type type) { - // Incomplete values for each wire type. - static const string incompletes[6] = { - string("\x80"), // VARINT - string("abcdefg"), // 64BIT - string("\x80"), // DELIMITED (partial length) - string(), // START_GROUP (no value required) - string(), // END_GROUP (no value required) - string("abc") // 32BIT - }; - - const FieldDescriptor* field = GetFieldForType(type, false, true); - const FieldDescriptor* rep_field = GetFieldForType(type, true, true); - WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType( - static_cast(type)); - const string& incomplete = incompletes[wire_type]; - const string type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(type)); - - ExpectParseFailureForProto( - tag(field->number(), wire_type), - "PrematureEofBeforeKnownNonRepeatedValue" + type_name, REQUIRED); - - ExpectParseFailureForProto(tag(rep_field->number(), wire_type), - "PrematureEofBeforeKnownRepeatedValue" + type_name, - REQUIRED); - - ExpectParseFailureForProto(tag(UNKNOWN_FIELD, wire_type), - "PrematureEofBeforeUnknownValue" + type_name, - REQUIRED); - - ExpectParseFailureForProto( - cat(tag(field->number(), wire_type), incomplete), - "PrematureEofInsideKnownNonRepeatedValue" + type_name, REQUIRED); - - ExpectParseFailureForProto( - cat(tag(rep_field->number(), wire_type), incomplete), - "PrematureEofInsideKnownRepeatedValue" + type_name, REQUIRED); - - ExpectParseFailureForProto(cat(tag(UNKNOWN_FIELD, wire_type), incomplete), - "PrematureEofInsideUnknownValue" + type_name, - REQUIRED); - - if (wire_type == WireFormatLite::WIRETYPE_LENGTH_DELIMITED) { - ExpectParseFailureForProto( - cat(tag(field->number(), wire_type), varint(1)), - "PrematureEofInDelimitedDataForKnownNonRepeatedValue" + type_name, - REQUIRED); - - ExpectParseFailureForProto( - cat(tag(rep_field->number(), wire_type), varint(1)), - "PrematureEofInDelimitedDataForKnownRepeatedValue" + type_name, - REQUIRED); - - // EOF in the middle of delimited data for unknown value. - ExpectParseFailureForProto( - cat(tag(UNKNOWN_FIELD, wire_type), varint(1)), - "PrematureEofInDelimitedDataForUnknownValue" + type_name, REQUIRED); - - if (type == FieldDescriptor::TYPE_MESSAGE) { - // Submessage ends in the middle of a value. - string incomplete_submsg = - cat(tag(WireFormatLite::TYPE_INT32, WireFormatLite::WIRETYPE_VARINT), - incompletes[WireFormatLite::WIRETYPE_VARINT]); - ExpectHardParseFailureForProto( - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - varint(incomplete_submsg.size()), incomplete_submsg), - "PrematureEofInSubmessageValue" + type_name, REQUIRED); - } - } - else if (type != FieldDescriptor::TYPE_GROUP) { - // Non-delimited, non-group: eligible for packing. - - // Packed region ends in the middle of a value. - ExpectHardParseFailureForProto( - cat(tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - varint(incomplete.size()), incomplete), - "PrematureEofInPackedFieldValue" + type_name, REQUIRED); - - // EOF in the middle of packed region. - ExpectParseFailureForProto( - cat(tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - varint(1)), - "PrematureEofInPackedField" + type_name, REQUIRED); - } -} - -void BinaryAndJsonConformanceSuite::TestValidDataForType( - FieldDescriptor::Type type, - std::vector> values) { - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - const string type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(type)); - WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType( - static_cast(type)); - const FieldDescriptor* field = GetFieldForType(type, false, is_proto3); - const FieldDescriptor* rep_field = GetFieldForType(type, true, is_proto3); - - // Test singular data for singular fields. - for (size_t i = 0; i < values.size(); i++) { - string proto = cat(tag(field->number(), wire_type), values[i].first); - // In proto3, default primitive fields should not be encoded. - string expected_proto = - is_proto3 && IsProto3Default(field->type(), values[i].second) - ? "" - : cat(tag(field->number(), wire_type), values[i].second); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(expected_proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest( - absl::StrCat("ValidDataScalar", type_name, "[", i, "]"), REQUIRED, - proto, text, is_proto3); - RunValidBinaryProtobufTest( - absl::StrCat("ValidDataScalarBinary", type_name, "[", i, "]"), - RECOMMENDED, proto, expected_proto, is_proto3); - } - - // Test repeated data for singular fields. - // For scalar message fields, repeated values are merged, which is tested - // separately. - if (type != FieldDescriptor::TYPE_MESSAGE) { - string proto; - for (size_t i = 0; i < values.size(); i++) { - proto += cat(tag(field->number(), wire_type), values[i].first); - } - string expected_proto = - cat(tag(field->number(), wire_type), values.back().second); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(expected_proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest("RepeatedScalarSelectsLast" + type_name, REQUIRED, - proto, text, is_proto3); - } - - // Test repeated fields. - if (FieldDescriptor::IsTypePackable(type)) { - const FieldDescriptor* packed_field = - GetFieldForType(type, true, is_proto3, Packed::kTrue); - const FieldDescriptor* unpacked_field = - GetFieldForType(type, true, is_proto3, Packed::kFalse); - - string default_proto_packed; - string default_proto_unpacked; - string default_proto_packed_expected; - string default_proto_unpacked_expected; - string packed_proto_packed; - string packed_proto_unpacked; - string packed_proto_expected; - string unpacked_proto_packed; - string unpacked_proto_unpacked; - string unpacked_proto_expected; - - for (size_t i = 0; i < values.size(); i++) { - default_proto_unpacked += - cat(tag(rep_field->number(), wire_type), values[i].first); - default_proto_unpacked_expected += - cat(tag(rep_field->number(), wire_type), values[i].second); - default_proto_packed += values[i].first; - default_proto_packed_expected += values[i].second; - packed_proto_unpacked += - cat(tag(packed_field->number(), wire_type), values[i].first); - packed_proto_packed += values[i].first; - packed_proto_expected += values[i].second; - unpacked_proto_unpacked += - cat(tag(unpacked_field->number(), wire_type), values[i].first); - unpacked_proto_packed += values[i].first; - unpacked_proto_expected += - cat(tag(unpacked_field->number(), wire_type), values[i].second); - } - default_proto_packed = cat( - tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(default_proto_packed)); - default_proto_packed_expected = cat( - tag(rep_field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(default_proto_packed_expected)); - packed_proto_packed = cat(tag(packed_field->number(), - WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(packed_proto_packed)); - packed_proto_expected = - cat(tag(packed_field->number(), - WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(packed_proto_expected)); - unpacked_proto_packed = - cat(tag(unpacked_field->number(), - WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(unpacked_proto_packed)); - - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(default_proto_packed_expected); - string text; - TextFormat::PrintToString(*test_message, &text); - - // Ensures both packed and unpacked data can be parsed. - RunValidProtobufTest( - absl::StrCat("ValidDataRepeated", type_name, ".UnpackedInput"), - REQUIRED, default_proto_unpacked, text, is_proto3); - RunValidProtobufTest( - absl::StrCat("ValidDataRepeated", type_name, ".PackedInput"), - REQUIRED, default_proto_packed, text, is_proto3); - - // proto2 should encode as unpacked by default and proto3 should encode as - // packed by default. - string expected_proto = rep_field->is_packed() - ? default_proto_packed_expected - : default_proto_unpacked_expected; - RunValidBinaryProtobufTest(absl::StrCat("ValidDataRepeated", type_name, - ".UnpackedInput.DefaultOutput"), - RECOMMENDED, default_proto_unpacked, - expected_proto, is_proto3); - RunValidBinaryProtobufTest(absl::StrCat("ValidDataRepeated", type_name, - ".PackedInput.DefaultOutput"), - RECOMMENDED, default_proto_packed, - expected_proto, is_proto3); - RunValidBinaryProtobufTest(absl::StrCat("ValidDataRepeated", type_name, - ".UnpackedInput.PackedOutput"), - RECOMMENDED, packed_proto_unpacked, - packed_proto_expected, is_proto3); - RunValidBinaryProtobufTest(absl::StrCat("ValidDataRepeated", type_name, - ".PackedInput.PackedOutput"), - RECOMMENDED, packed_proto_packed, - packed_proto_expected, is_proto3); - RunValidBinaryProtobufTest(absl::StrCat("ValidDataRepeated", type_name, - ".UnpackedInput.UnpackedOutput"), - RECOMMENDED, unpacked_proto_unpacked, - unpacked_proto_expected, is_proto3); - RunValidBinaryProtobufTest(absl::StrCat("ValidDataRepeated", type_name, - ".PackedInput.UnpackedOutput"), - RECOMMENDED, unpacked_proto_packed, - unpacked_proto_expected, is_proto3); - } - else { - string proto; - string expected_proto; - for (size_t i = 0; i < values.size(); i++) { - proto += cat(tag(rep_field->number(), wire_type), values[i].first); - expected_proto += - cat(tag(rep_field->number(), wire_type), values[i].second); - } - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(expected_proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest(absl::StrCat("ValidDataRepeated", type_name), - REQUIRED, proto, text, is_proto3); - } - } -} - -void BinaryAndJsonConformanceSuite::TestValidDataForRepeatedScalarMessage() { - std::vector values = { - delim(cat( - tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234), - tag(2, WireFormatLite::WIRETYPE_VARINT), varint(1234), - tag(31, WireFormatLite::WIRETYPE_VARINT), varint(1234))))), - delim(cat( - tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(4321), - tag(3, WireFormatLite::WIRETYPE_VARINT), varint(4321), - tag(31, WireFormatLite::WIRETYPE_VARINT), varint(4321))))), - }; - - const std::string expected = - R"({ - corecursive: { - optional_int32: 4321, - optional_int64: 1234, - optional_uint32: 4321, - repeated_int32: [1234, 4321], - } - })"; - - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - string proto; - const FieldDescriptor* field = - GetFieldForType(FieldDescriptor::TYPE_MESSAGE, false, is_proto3); - for (size_t i = 0; i < values.size(); i++) { - proto += - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - values[i]); - } - - RunValidProtobufTest("RepeatedScalarMessageMerge", REQUIRED, proto, - field->name() + ": " + expected, is_proto3); - } -} - -void BinaryAndJsonConformanceSuite::TestValidDataForMapType( - FieldDescriptor::Type key_type, FieldDescriptor::Type value_type) { - const string key_type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(key_type)); - const string value_type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(value_type)); - WireFormatLite::WireType key_wire_type = WireFormatLite::WireTypeForFieldType( - static_cast(key_type)); - WireFormatLite::WireType value_wire_type = - WireFormatLite::WireTypeForFieldType( - static_cast(value_type)); - - string key1_data = cat(tag(1, key_wire_type), GetDefaultValue(key_type)); - string value1_data = - cat(tag(2, value_wire_type), GetDefaultValue(value_type)); - string key2_data = cat(tag(1, key_wire_type), GetNonDefaultValue(key_type)); - string value2_data = - cat(tag(2, value_wire_type), GetNonDefaultValue(value_type)); - - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - const FieldDescriptor* field = - GetFieldForMapType(key_type, value_type, is_proto3); - - { - // Tests map with default key and value. - string proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key1_data, value1_data))); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest(absl::StrCat("ValidDataMap", key_type_name, - value_type_name, ".Default"), - REQUIRED, proto, text, is_proto3); - } - - { - // Tests map with missing default key and value. - string proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim("")); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest(absl::StrCat("ValidDataMap", key_type_name, - value_type_name, ".MissingDefault"), - REQUIRED, proto, text, is_proto3); - } - - { - // Tests map with non-default key and value. - string proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key2_data, value2_data))); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest(absl::StrCat("ValidDataMap", key_type_name, - value_type_name, ".NonDefault"), - REQUIRED, proto, text, is_proto3); - } - - { - // Tests map with unordered key and value. - string proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(value2_data, key2_data))); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest(absl::StrCat("ValidDataMap", key_type_name, - value_type_name, ".Unordered"), - REQUIRED, proto, text, is_proto3); - } - - { - // Tests map with duplicate key. - string proto1 = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key2_data, value1_data))); - string proto2 = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key2_data, value2_data))); - string proto = cat(proto1, proto2); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto2); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest(absl::StrCat("ValidDataMap", key_type_name, - value_type_name, ".DuplicateKey"), - REQUIRED, proto, text, is_proto3); - } - - { - // Tests map with duplicate key in map entry. - string proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key1_data, key2_data, value2_data))); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest( - absl::StrCat("ValidDataMap", key_type_name, value_type_name, - ".DuplicateKeyInMapEntry"), - REQUIRED, proto, text, is_proto3); - } - - { - // Tests map with duplicate value in map entry. - string proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key2_data, value1_data, value2_data))); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest( - absl::StrCat("ValidDataMap", key_type_name, value_type_name, - ".DuplicateValueInMapEntry"), - REQUIRED, proto, text, is_proto3); - } - } -} - -void BinaryAndJsonConformanceSuite::TestOverwriteMessageValueMap() { - string key_data = - cat(tag(1, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), delim("")); - string field1_data = cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string field2_data = cat(tag(2, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string field31_data = - cat(tag(31, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string submsg1_data = delim(cat(field1_data, field31_data)); - string submsg2_data = delim(cat(field2_data, field31_data)); - string value1_data = - cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - submsg1_data))); - string value2_data = - cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - submsg2_data))); - - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - const FieldDescriptor* field = GetFieldForMapType( - FieldDescriptor::TYPE_STRING, FieldDescriptor::TYPE_MESSAGE, is_proto3); - - string proto1 = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key_data, value1_data))); - string proto2 = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(key_data, value2_data))); - string proto = cat(proto1, proto2); - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto2); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest("ValidDataMap.STRING.MESSAGE.MergeValue", REQUIRED, - proto, text, is_proto3); - } -} - -void BinaryAndJsonConformanceSuite::TestValidDataForOneofType( - FieldDescriptor::Type type) { - const string type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(type)); - WireFormatLite::WireType wire_type = WireFormatLite::WireTypeForFieldType( - static_cast(type)); - - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - const FieldDescriptor* field = GetFieldForOneofType(type, is_proto3); - const string default_value = - cat(tag(field->number(), wire_type), GetDefaultValue(type)); - const string non_default_value = - cat(tag(field->number(), wire_type), GetNonDefaultValue(type)); - - { - // Tests oneof with default value. - const string proto = default_value; - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest( - absl::StrCat("ValidDataOneof", type_name, ".DefaultValue"), REQUIRED, - proto, text, is_proto3); - RunValidBinaryProtobufTest( - absl::StrCat("ValidDataOneofBinary", type_name, ".DefaultValue"), - RECOMMENDED, proto, proto, is_proto3); - } - - { - // Tests oneof with non-default value. - const string proto = non_default_value; - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest( - absl::StrCat("ValidDataOneof", type_name, ".NonDefaultValue"), - REQUIRED, proto, text, is_proto3); - RunValidBinaryProtobufTest( - absl::StrCat("ValidDataOneofBinary", type_name, ".NonDefaultValue"), - RECOMMENDED, proto, proto, is_proto3); - } - - { - // Tests oneof with multiple values of the same field. - const string proto = absl::StrCat(default_value, non_default_value); - const string expected_proto = non_default_value; - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(expected_proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest(absl::StrCat("ValidDataOneof", type_name, - ".MultipleValuesForSameField"), - REQUIRED, proto, text, is_proto3); - RunValidBinaryProtobufTest(absl::StrCat("ValidDataOneofBinary", type_name, - ".MultipleValuesForSameField"), - RECOMMENDED, proto, expected_proto, is_proto3); - } - - { - // Tests oneof with multiple values of the different fields. - const FieldDescriptor* other_field = - GetFieldForOneofType(type, is_proto3, true); - FieldDescriptor::Type other_type = other_field->type(); - WireFormatLite::WireType other_wire_type = - WireFormatLite::WireTypeForFieldType( - static_cast(other_type)); - const string other_value = - cat(tag(other_field->number(), other_wire_type), - GetDefaultValue(other_type)); - - const string proto = absl::StrCat(other_value, non_default_value); - const string expected_proto = non_default_value; - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(expected_proto); - string text; - TextFormat::PrintToString(*test_message, &text); - - RunValidProtobufTest(absl::StrCat("ValidDataOneof", type_name, - ".MultipleValuesForDifferentField"), - REQUIRED, proto, text, is_proto3); - RunValidBinaryProtobufTest( - absl::StrCat("ValidDataOneofBinary", type_name, - ".MultipleValuesForDifferentField"), - RECOMMENDED, proto, expected_proto, is_proto3); - } - } -} - -void BinaryAndJsonConformanceSuite::TestMergeOneofMessage() { - string field1_data = cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string field2a_data = cat(tag(2, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string field2b_data = cat(tag(2, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string field89_data = - cat(tag(89, WireFormatLite::WIRETYPE_VARINT), varint(1)); - string submsg1_data = - cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(field1_data, field2a_data, field89_data))); - string submsg2_data = cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(field2b_data, field89_data))); - string merged_data = - cat(tag(2, WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(cat(field1_data, field2b_data, field89_data, field89_data))); - - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - const FieldDescriptor* field = - GetFieldForOneofType(FieldDescriptor::TYPE_MESSAGE, is_proto3); - - string proto1 = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(submsg1_data)); - string proto2 = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(submsg2_data)); - string proto = cat(proto1, proto2); - string expected_proto = - cat(tag(field->number(), WireFormatLite::WIRETYPE_LENGTH_DELIMITED), - delim(merged_data)); - - std::unique_ptr test_message = NewTestMessage(is_proto3); - test_message->MergeFromString(expected_proto); - string text; - TextFormat::PrintToString(*test_message, &text); - RunValidProtobufTest("ValidDataOneof.MESSAGE.Merge", REQUIRED, proto, text, - is_proto3); - RunValidBinaryProtobufTest("ValidDataOneofBinary.MESSAGE.Merge", - RECOMMENDED, proto, expected_proto, is_proto3); - } -} - -void BinaryAndJsonConformanceSuite::TestIllegalTags() { - // field num 0 is illegal - string nullfield[] = {"\1DEADBEEF", "\2\1\1", "\3\4", "\5DEAD"}; - for (int i = 0; i < 4; i++) { - string name = "IllegalZeroFieldNum_Case_0"; - name.back() += i; - ExpectParseFailureForProto(nullfield[i], name, REQUIRED); - } -} -template -void BinaryAndJsonConformanceSuite::TestOneofMessage(MessageType& message, - bool is_proto3) { - message.set_oneof_uint32(0); - RunValidProtobufTestWithMessage("OneofZeroUint32", RECOMMENDED, &message, - "oneof_uint32: 0", is_proto3); - message.mutable_oneof_nested_message()->set_a(0); - RunValidProtobufTestWithMessage( - "OneofZeroMessage", RECOMMENDED, &message, - is_proto3 ? "oneof_nested_message: {}" : "oneof_nested_message: {a: 0}", - is_proto3); - message.mutable_oneof_nested_message()->set_a(1); - RunValidProtobufTestWithMessage("OneofZeroMessageSetTwice", RECOMMENDED, - &message, "oneof_nested_message: {a: 1}", - is_proto3); - message.set_oneof_string(""); - RunValidProtobufTestWithMessage("OneofZeroString", RECOMMENDED, &message, - "oneof_string: \"\"", is_proto3); - message.set_oneof_bytes(""); - RunValidProtobufTestWithMessage("OneofZeroBytes", RECOMMENDED, &message, - "oneof_bytes: \"\"", is_proto3); - message.set_oneof_bool(false); - RunValidProtobufTestWithMessage("OneofZeroBool", RECOMMENDED, &message, - "oneof_bool: false", is_proto3); - message.set_oneof_uint64(0); - RunValidProtobufTestWithMessage("OneofZeroUint64", RECOMMENDED, &message, - "oneof_uint64: 0", is_proto3); - message.set_oneof_float(0.0f); - RunValidProtobufTestWithMessage("OneofZeroFloat", RECOMMENDED, &message, - "oneof_float: 0", is_proto3); - message.set_oneof_double(0.0); - RunValidProtobufTestWithMessage("OneofZeroDouble", RECOMMENDED, &message, - "oneof_double: 0", is_proto3); - message.set_oneof_enum(MessageType::FOO); - RunValidProtobufTestWithMessage("OneofZeroEnum", RECOMMENDED, &message, - "oneof_enum: FOO", is_proto3); -} - -template -void BinaryAndJsonConformanceSuite::TestUnknownMessage(MessageType& message, - bool is_proto3) { - message.ParseFromString("\xA8\x1F\x01"); - RunValidBinaryProtobufTest("UnknownVarint", REQUIRED, - message.SerializeAsString(), is_proto3); -} - -void BinaryAndJsonConformanceSuite:: - TestBinaryPerformanceForAlternatingUnknownFields() { - string unknown_field_1 = - cat(tag(UNKNOWN_FIELD, WireFormatLite::WIRETYPE_VARINT), varint(1234)); - string unknown_field_2 = cat( - tag(UNKNOWN_FIELD + 1, WireFormatLite::WIRETYPE_VARINT), varint(5678)); - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - string proto; - for (size_t i = 0; i < kPerformanceRepeatCount; i++) { - proto.append(unknown_field_1); - proto.append(unknown_field_2); - } - - RunValidBinaryProtobufTest( - "TestBinaryPerformanceForAlternatingUnknownFields", RECOMMENDED, proto, - is_proto3); - } -} - -void BinaryAndJsonConformanceSuite:: - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::Type type) { - const string type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(type)); - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - int field_number = - GetFieldForType(type, true, is_proto3, Packed::kFalse)->number(); - string rep_field_proto = cat( - tag(field_number, WireFormatLite::WireTypeForFieldType( - static_cast(type))), - GetNonDefaultValue(type)); - - RunBinaryPerformanceMergeMessageWithField( - "TestBinaryPerformanceMergeMessageWithRepeatedFieldForType" + type_name, - rep_field_proto, is_proto3); - } -} - -void BinaryAndJsonConformanceSuite:: - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::Type type) { - const string type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(type)); - string unknown_field_proto = - cat(tag(UNKNOWN_FIELD, WireFormatLite::WireTypeForFieldType( - static_cast(type))), - GetNonDefaultValue(type)); - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - RunBinaryPerformanceMergeMessageWithField( - "TestBinaryPerformanceMergeMessageWithUnknownFieldForType" + type_name, - unknown_field_proto, is_proto3); - } -} - -void BinaryAndJsonConformanceSuite::RunSuiteImpl() { - // Hack to get the list of test failures based on whether - // GOOGLE_PROTOBUF_ENABLE_EXPERIMENTAL_PARSER is enabled or not. - conformance::FailureSet failure_set; - ConformanceRequest req; - ConformanceResponse res; - req.set_message_type(failure_set.GetTypeName()); - req.set_protobuf_payload(""); - req.set_requested_output_format(conformance::WireFormat::PROTOBUF); - RunTest("FindFailures", req, &res); - GOOGLE_CHECK(failure_set.MergeFromString(res.protobuf_payload())); - for (const string& failure : failure_set.failure()) { - AddExpectedFailedTest(failure); - } - - type_resolver_.reset(NewTypeResolverForDescriptorPool( - kTypeUrlPrefix, DescriptorPool::generated_pool())); - type_url_ = GetTypeUrl(TestAllTypesProto3::descriptor()); - - if (!performance_) { - for (int i = 1; i <= FieldDescriptor::MAX_TYPE; i++) { - if (i == FieldDescriptor::TYPE_GROUP) - continue; - TestPrematureEOFForType(static_cast(i)); - } - - TestIllegalTags(); - - int64 kInt64Min = -9223372036854775808ULL; - int64 kInt64Max = 9223372036854775807ULL; - uint64 kUint64Max = 18446744073709551615ULL; - int32 kInt32Max = 2147483647; - int32 kInt32Min = -2147483648; - uint32 kUint32Max = 4294967295UL; - - TestValidDataForType( - FieldDescriptor::TYPE_DOUBLE, - { - {dbl(0), dbl(0)}, - {dbl(0.1), dbl(0.1)}, - {dbl(1.7976931348623157e+308), dbl(1.7976931348623157e+308)}, - {dbl(2.22507385850720138309e-308), - dbl(2.22507385850720138309e-308)}, - }); - TestValidDataForType( - FieldDescriptor::TYPE_FLOAT, - { - {flt(0), flt(0)}, - {flt(0.1), flt(0.1)}, - {flt(1.00000075e-36), flt(1.00000075e-36)}, - {flt(3.402823e+38), flt(3.402823e+38)}, // 3.40282347e+38 - {flt(1.17549435e-38f), flt(1.17549435e-38)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_INT64, - { - {varint(0), varint(0)}, - {varint(12345), varint(12345)}, - {varint(kInt64Max), varint(kInt64Max)}, - {varint(kInt64Min), varint(kInt64Min)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_UINT64, - { - {varint(0), varint(0)}, - {varint(12345), varint(12345)}, - {varint(kUint64Max), varint(kUint64Max)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_INT32, - { - {varint(0), varint(0)}, - {varint(12345), varint(12345)}, - {longvarint(12345, 2), varint(12345)}, - {longvarint(12345, 7), varint(12345)}, - {varint(kInt32Max), varint(kInt32Max)}, - {varint(kInt32Min), varint(kInt32Min)}, - {varint(1LL << 33), varint(0)}, - {varint((1LL << 33) - 1), varint(-1)}, - {varint(kInt64Max), varint(-1)}, - {varint(kInt64Min + 1), varint(1)}, - }); - TestValidDataForType( - FieldDescriptor::TYPE_UINT32, - { - {varint(0), varint(0)}, - {varint(12345), varint(12345)}, - {longvarint(12345, 2), varint(12345)}, - {longvarint(12345, 7), varint(12345)}, - {varint(kUint32Max), varint(kUint32Max)}, // UINT32_MAX - {varint(1LL << 33), varint(0)}, - {varint((1LL << 33) + 1), varint(1)}, - {varint((1LL << 33) - 1), varint((1LL << 32) - 1)}, - {varint(kInt64Max), varint((1LL << 32) - 1)}, - {varint(kInt64Min + 1), varint(1)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_FIXED64, - { - {u64(0), u64(0)}, - {u64(12345), u64(12345)}, - {u64(kUint64Max), u64(kUint64Max)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_FIXED32, - { - {u32(0), u32(0)}, - {u32(12345), u32(12345)}, - {u32(kUint32Max), u32(kUint32Max)}, // UINT32_MAX - }); - TestValidDataForType(FieldDescriptor::TYPE_SFIXED64, - { - {u64(0), u64(0)}, - {u64(12345), u64(12345)}, - {u64(kInt64Max), u64(kInt64Max)}, - {u64(kInt64Min), u64(kInt64Min)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_SFIXED32, - { - {u32(0), u32(0)}, - {u32(12345), u32(12345)}, - {u32(kInt32Max), u32(kInt32Max)}, - {u32(kInt32Min), u32(kInt32Min)}, - }); - // Bools should be serialized as 0 for false and 1 for true. Parsers should - // also interpret any nonzero value as true. - TestValidDataForType(FieldDescriptor::TYPE_BOOL, - { - {varint(0), varint(0)}, - {varint(1), varint(1)}, - {varint(-1), varint(1)}, - {varint(12345678), varint(1)}, - {varint(1LL << 33), varint(1)}, - {varint(kInt64Max), varint(1)}, - {varint(kInt64Min), varint(1)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_SINT32, - { - {zz32(0), zz32(0)}, - {zz32(12345), zz32(12345)}, - {zz32(kInt32Max), zz32(kInt32Max)}, - {zz32(kInt32Min), zz32(kInt32Min)}, - {zz64(kInt32Max + 2LL), zz32(1)}, - }); - TestValidDataForType(FieldDescriptor::TYPE_SINT64, - { - {zz64(0), zz64(0)}, - {zz64(12345), zz64(12345)}, - {zz64(kInt64Max), zz64(kInt64Max)}, - {zz64(kInt64Min), zz64(kInt64Min)}, - }); - TestValidDataForType( - FieldDescriptor::TYPE_STRING, - { - {delim(""), delim("")}, - {delim("Hello world!"), delim("Hello world!")}, - {delim("\'\"\?\\\a\b\f\n\r\t\v"), - delim("\'\"\?\\\a\b\f\n\r\t\v")}, // escape - {delim("谷歌"), delim("谷歌")}, // Google in Chinese - {delim("\u8C37\u6B4C"), delim("谷歌")}, // unicode escape - {delim("\u8c37\u6b4c"), delim("谷歌")}, // lowercase unicode - {delim("\xF0\x9F\x98\x81"), delim("\xF0\x9F\x98\x81")}, // emoji: 😁 - }); - TestValidDataForType(FieldDescriptor::TYPE_BYTES, - { - {delim(""), delim("")}, - {delim("Hello world!"), delim("Hello world!")}, - {delim("\x01\x02"), delim("\x01\x02")}, - {delim("\xfb"), delim("\xfb")}, - }); - TestValidDataForType(FieldDescriptor::TYPE_ENUM, - { - {varint(0), varint(0)}, - {varint(1), varint(1)}, - {varint(2), varint(2)}, - {varint(-1), varint(-1)}, - {varint(kInt64Max), varint(-1)}, - {varint(kInt64Min + 1), varint(1)}, - }); - TestValidDataForRepeatedScalarMessage(); - TestValidDataForType( - FieldDescriptor::TYPE_MESSAGE, - { - {delim(""), delim("")}, - {delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234))), - delim(cat(tag(1, WireFormatLite::WIRETYPE_VARINT), varint(1234)))}, - }); - - TestValidDataForMapType(FieldDescriptor::TYPE_INT32, - FieldDescriptor::TYPE_INT32); - TestValidDataForMapType(FieldDescriptor::TYPE_INT64, - FieldDescriptor::TYPE_INT64); - TestValidDataForMapType(FieldDescriptor::TYPE_UINT32, - FieldDescriptor::TYPE_UINT32); - TestValidDataForMapType(FieldDescriptor::TYPE_UINT64, - FieldDescriptor::TYPE_UINT64); - TestValidDataForMapType(FieldDescriptor::TYPE_SINT32, - FieldDescriptor::TYPE_SINT32); - TestValidDataForMapType(FieldDescriptor::TYPE_SINT64, - FieldDescriptor::TYPE_SINT64); - TestValidDataForMapType(FieldDescriptor::TYPE_FIXED32, - FieldDescriptor::TYPE_FIXED32); - TestValidDataForMapType(FieldDescriptor::TYPE_FIXED64, - FieldDescriptor::TYPE_FIXED64); - TestValidDataForMapType(FieldDescriptor::TYPE_SFIXED32, - FieldDescriptor::TYPE_SFIXED32); - TestValidDataForMapType(FieldDescriptor::TYPE_SFIXED64, - FieldDescriptor::TYPE_SFIXED64); - TestValidDataForMapType(FieldDescriptor::TYPE_INT32, - FieldDescriptor::TYPE_FLOAT); - TestValidDataForMapType(FieldDescriptor::TYPE_INT32, - FieldDescriptor::TYPE_DOUBLE); - TestValidDataForMapType(FieldDescriptor::TYPE_BOOL, - FieldDescriptor::TYPE_BOOL); - TestValidDataForMapType(FieldDescriptor::TYPE_STRING, - FieldDescriptor::TYPE_STRING); - TestValidDataForMapType(FieldDescriptor::TYPE_STRING, - FieldDescriptor::TYPE_BYTES); - TestValidDataForMapType(FieldDescriptor::TYPE_STRING, - FieldDescriptor::TYPE_ENUM); - TestValidDataForMapType(FieldDescriptor::TYPE_STRING, - FieldDescriptor::TYPE_MESSAGE); - // Additional test to check overwriting message value map. - TestOverwriteMessageValueMap(); - - TestValidDataForOneofType(FieldDescriptor::TYPE_UINT32); - TestValidDataForOneofType(FieldDescriptor::TYPE_BOOL); - TestValidDataForOneofType(FieldDescriptor::TYPE_UINT64); - TestValidDataForOneofType(FieldDescriptor::TYPE_FLOAT); - TestValidDataForOneofType(FieldDescriptor::TYPE_DOUBLE); - TestValidDataForOneofType(FieldDescriptor::TYPE_STRING); - TestValidDataForOneofType(FieldDescriptor::TYPE_BYTES); - TestValidDataForOneofType(FieldDescriptor::TYPE_ENUM); - TestValidDataForOneofType(FieldDescriptor::TYPE_MESSAGE); - // Additional test to check merging oneof message. - TestMergeOneofMessage(); - - // TODO(haberman): - // TestValidDataForType(FieldDescriptor::TYPE_GROUP - - // Unknown fields. - { - TestAllTypesProto3 messageProto3; - TestAllTypesProto2 messageProto2; - // TODO(yilunchong): update this behavior when unknown field's behavior - // changed in open source. Also delete - // Required.Proto3.ProtobufInput.UnknownVarint.ProtobufOutput - // from failure list of python_cpp python java - TestUnknownMessage(messageProto3, true); - TestUnknownMessage(messageProto2, false); - } - - // RunJsonTests(); - } - // Flag control performance tests to keep them internal and opt-in only - if (performance_) { - RunBinaryPerformanceTests(); - // RunJsonPerformanceTests(); - } -} - -void BinaryAndJsonConformanceSuite::RunBinaryPerformanceTests() { - TestBinaryPerformanceForAlternatingUnknownFields(); - - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_BOOL); - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_DOUBLE); - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_FLOAT); - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_UINT32); - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_UINT64); - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_STRING); - TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::TYPE_BYTES); - - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_BOOL); - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_DOUBLE); - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_FLOAT); - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_UINT32); - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_UINT64); - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_STRING); - TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - FieldDescriptor::TYPE_BYTES); -} - -// This is currently considered valid input by some languages but not others -void BinaryAndJsonConformanceSuite:: - TestJsonPerformanceMergeMessageWithRepeatedFieldForType( - FieldDescriptor::Type type, string field_value) { - const string type_name = - UpperCase(string(".") + FieldDescriptor::TypeName(type)); - for (int is_proto3 = 0; is_proto3 < 2; is_proto3++) { - const FieldDescriptor* field = - GetFieldForType(type, true, is_proto3, Packed::kFalse); - string field_name = field->name(); - - string message_field = "\"" + field_name + "\": [" + field_value + "]"; - string recursive_message = - "\"recursive_message\": { " + message_field + "}"; - string input = "{"; - input.append(recursive_message); - for (size_t i = 1; i < kPerformanceRepeatCount; i++) { - input.append("," + recursive_message); - } - input.append("}"); - - string textproto_message_field = field_name + ": " + field_value; - string expected_textproto = "recursive_message { "; - for (size_t i = 0; i < kPerformanceRepeatCount; i++) { - expected_textproto.append(textproto_message_field + " "); - } - expected_textproto.append("}"); - RunValidJsonTest( - "TestJsonPerformanceMergeMessageWithRepeatedFieldForType" + type_name, - RECOMMENDED, input, expected_textproto, is_proto3); - } -} - -} // namespace protobuf -} // namespace google diff --git a/src/struct_pb/conformance/binary_json_conformance_suite.h b/src/struct_pb/conformance/binary_json_conformance_suite.h deleted file mode 100644 index 23670551c..000000000 --- a/src/struct_pb/conformance/binary_json_conformance_suite.h +++ /dev/null @@ -1,123 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#ifndef CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H -#define CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H - -#include "conformance_test.h" -#include "google/protobuf/descriptor.h" - -namespace google { -namespace protobuf { - -class BinaryAndJsonConformanceSuite : public ConformanceTestSuite { - public: - BinaryAndJsonConformanceSuite() {} - - private: - void RunSuiteImpl() override; - void RunBinaryPerformanceTests(); - void RunValidJsonTest(const std::string& test_name, ConformanceLevel level, - const std::string& input_json, - const std::string& equivalent_text_format, - bool is_proto3); - void RunValidProtobufTest(const std::string& test_name, - ConformanceLevel level, - const std::string& input_protobuf, - const std::string& equivalent_text_format, - bool is_proto3); - void RunValidBinaryProtobufTest(const std::string& test_name, - ConformanceLevel level, - const std::string& input_protobuf, - bool is_proto3); - void RunValidBinaryProtobufTest(const std::string& test_name, - ConformanceLevel level, - const std::string& input_protobuf, - const std::string& expected_protobuf, - bool is_proto3); - void RunBinaryPerformanceMergeMessageWithField(const std::string& test_name, - const std::string& field_proto, - bool is_proto3); - - void RunValidProtobufTestWithMessage( - const std::string& test_name, ConformanceLevel level, - const Message* input, const std::string& equivalent_text_format, - bool is_proto3); - - bool ParseResponse(const conformance::ConformanceResponse& response, - const ConformanceRequestSetting& setting, - Message* test_message) override; - void ExpectParseFailureForJson(const std::string& test_name, - ConformanceLevel level, - const std::string& input_json); - void ExpectSerializeFailureForJson(const std::string& test_name, - ConformanceLevel level, - const std::string& text_format); - void ExpectParseFailureForProtoWithProtoVersion(const std::string& proto, - const std::string& test_name, - ConformanceLevel level, - bool is_proto3); - void ExpectParseFailureForProto(const std::string& proto, - const std::string& test_name, - ConformanceLevel level); - void ExpectHardParseFailureForProto(const std::string& proto, - const std::string& test_name, - ConformanceLevel level); - void TestPrematureEOFForType(google::protobuf::FieldDescriptor::Type type); - void TestIllegalTags(); - template - void TestOneofMessage(MessageType& message, bool is_proto3); - template - void TestUnknownMessage(MessageType& message, bool is_proto3); - void TestValidDataForType( - google::protobuf::FieldDescriptor::Type, - std::vector> values); - void TestValidDataForRepeatedScalarMessage(); - void TestValidDataForMapType(google::protobuf::FieldDescriptor::Type, - google::protobuf::FieldDescriptor::Type); - void TestValidDataForOneofType(google::protobuf::FieldDescriptor::Type); - void TestMergeOneofMessage(); - void TestOverwriteMessageValueMap(); - void TestBinaryPerformanceForAlternatingUnknownFields(); - void TestBinaryPerformanceMergeMessageWithRepeatedFieldForType( - google::protobuf::FieldDescriptor::Type); - void TestBinaryPerformanceMergeMessageWithUnknownFieldForType( - google::protobuf::FieldDescriptor::Type); - void TestJsonPerformanceMergeMessageWithRepeatedFieldForType( - google::protobuf::FieldDescriptor::Type, std::string field_value); - - std::unique_ptr type_resolver_; - std::string type_url_; -}; - -} // namespace protobuf -} // namespace google - -#endif // CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H diff --git a/src/struct_pb/conformance/conformance/conformance.proto b/src/struct_pb/conformance/conformance/conformance.proto deleted file mode 100644 index bee04d160..000000000 --- a/src/struct_pb/conformance/conformance/conformance.proto +++ /dev/null @@ -1,180 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package conformance; - -option java_package = "com.google.protobuf.conformance"; -option objc_class_prefix = "Conformance"; - -// This defines the conformance testing protocol. This protocol exists between -// the conformance test suite itself and the code being tested. For each test, -// the suite will send a ConformanceRequest message and expect a -// ConformanceResponse message. -// -// You can either run the tests in two different ways: -// -// 1. in-process (using the interface in conformance_test.h). -// -// 2. as a sub-process communicating over a pipe. Information about how to -// do this is in conformance_test_runner.cc. -// -// Pros/cons of the two approaches: -// -// - running as a sub-process is much simpler for languages other than C/C++. -// -// - running as a sub-process may be more tricky in unusual environments like -// iOS apps, where fork/stdin/stdout are not available. - -enum WireFormat { - UNSPECIFIED = 0; - PROTOBUF = 1; - JSON = 2; - JSPB = 3; // Only used inside Google. Opensource testees just skip it. - TEXT_FORMAT = 4; -} - -enum TestCategory { - UNSPECIFIED_TEST = 0; - BINARY_TEST = 1; // Test binary wire format. - JSON_TEST = 2; // Test json wire format. - // Similar to JSON_TEST. However, during parsing json, testee should ignore - // unknown fields. This feature is optional. Each implementation can decide - // whether to support it. See - // https://developers.google.com/protocol-buffers/docs/proto3#json_options - // for more detail. - JSON_IGNORE_UNKNOWN_PARSING_TEST = 3; - // Test jspb wire format. Only used inside Google. Opensource testees just - // skip it. - JSPB_TEST = 4; - // Test text format. For cpp, java and python, testees can already deal with - // this type. Testees of other languages can simply skip it. - TEXT_FORMAT_TEST = 5; -} - -// The conformance runner will request a list of failures as the first request. -// This will be known by message_type == "conformance.FailureSet", a conformance -// test should return a serialized FailureSet in protobuf_payload. -message FailureSet { - repeated string failure = 1; -} - -// Represents a single test case's input. The testee should: -// -// 1. parse this proto (which should always succeed) -// 2. parse the protobuf or JSON payload in "payload" (which may fail) -// 3. if the parse succeeded, serialize the message in the requested format. -message ConformanceRequest { - // The payload (whether protobuf of JSON) is always for a - // protobuf_test_messages.proto3.TestAllTypes proto (as defined in - // src/google/protobuf/proto3_test_messages.proto). - oneof payload { - bytes protobuf_payload = 1; - string json_payload = 2; - // Only used inside Google. Opensource testees just skip it. - string jspb_payload = 7; - string text_payload = 8; - } - - // Which format should the testee serialize its message to? - WireFormat requested_output_format = 3; - - // The full name for the test message to use; for the moment, either: - // protobuf_test_messages.proto3.TestAllTypesProto3 or - // protobuf_test_messages.google.protobuf.TestAllTypesProto2. - string message_type = 4; - - // Each test is given a specific test category. Some category may need - // specific support in testee programs. Refer to the definition of - // TestCategory for more information. - TestCategory test_category = 5; - - // Specify details for how to encode jspb. - JspbEncodingConfig jspb_encoding_options = 6; - - // This can be used in json and text format. If true, testee should print - // unknown fields instead of ignore. This feature is optional. - bool print_unknown_fields = 9; -} - -// Represents a single test case's output. -message ConformanceResponse { - oneof result { - // This string should be set to indicate parsing failed. The string can - // provide more information about the parse error if it is available. - // - // Setting this string does not necessarily mean the testee failed the - // test. Some of the test cases are intentionally invalid input. - string parse_error = 1; - - // If the input was successfully parsed but errors occurred when - // serializing it to the requested output format, set the error message in - // this field. - string serialize_error = 6; - - // This should be set if the test program timed out. The string should - // provide more information about what the child process was doing when it - // was killed. - string timeout_error = 9; - - // This should be set if some other error occurred. This will always - // indicate that the test failed. The string can provide more information - // about the failure. - string runtime_error = 2; - - // If the input was successfully parsed and the requested output was - // protobuf, serialize it to protobuf and set it in this field. - bytes protobuf_payload = 3; - - // If the input was successfully parsed and the requested output was JSON, - // serialize to JSON and set it in this field. - string json_payload = 4; - - // For when the testee skipped the test, likely because a certain feature - // wasn't supported, like JSON input/output. - string skipped = 5; - - // If the input was successfully parsed and the requested output was JSPB, - // serialize to JSPB and set it in this field. JSPB is only used inside - // Google. Opensource testees can just skip it. - string jspb_payload = 7; - - // If the input was successfully parsed and the requested output was - // TEXT_FORMAT, serialize to TEXT_FORMAT and set it in this field. - string text_payload = 8; - } -} - -// Encoding options for jspb format. -message JspbEncodingConfig { - // Encode the value field of Any as jspb array if true, otherwise binary. - bool use_jspb_array_any_format = 1; -} diff --git a/src/struct_pb/conformance/conformance_cpp.cc b/src/struct_pb/conformance/conformance_cpp.cc deleted file mode 100644 index 09c3a3e8e..000000000 --- a/src/struct_pb/conformance/conformance_cpp.cc +++ /dev/null @@ -1,304 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "conformance/conformance.pb.h" -#include "google/protobuf/message.h" -#include "google/protobuf/stubs/logging.h" -#include "google/protobuf/test_messages_proto2.pb.h" -#include "google/protobuf/test_messages_proto3.pb.h" -#include "google/protobuf/text_format.h" -#include "google/protobuf/util/json_util.h" -#include "google/protobuf/util/type_resolver.h" -#include "google/protobuf/util/type_resolver_util.h" - -// Must be included last. -#include "google/protobuf/port_def.inc" - -#define RETURN_IF_ERROR(expr) \ - do { \ - /* Using _status below to avoid capture problems if expr is "status". */ \ - const absl::Status _status = (expr); \ - if (PROTOBUF_PREDICT_FALSE(!_status.ok())) \ - return _status; \ - } while (0) - -namespace google { -namespace protobuf { -namespace { -using ::conformance::ConformanceRequest; -using ::conformance::ConformanceResponse; -using ::google::protobuf::util::BinaryToJsonString; -using ::google::protobuf::util::JsonParseOptions; -using ::google::protobuf::util::JsonToBinaryString; -using ::google::protobuf::util::NewTypeResolverForDescriptorPool; -using ::google::protobuf::util::TypeResolver; -using ::protobuf_test_messages::proto2::TestAllTypesProto2; -using ::protobuf_test_messages::proto3::TestAllTypesProto3; - -absl::Status ReadFd(int fd, char* buf, size_t len) { - while (len > 0) { - ssize_t bytes_read = read(fd, buf, len); - - if (bytes_read == 0) { - return absl::DataLossError("unexpected EOF"); - } - - if (bytes_read < 0) { - return absl::ErrnoToStatus(errno, "error reading from test runner"); - } - - len -= bytes_read; - buf += bytes_read; - } - return absl::OkStatus(); -} - -absl::Status WriteFd(int fd, const void* buf, size_t len) { - if (static_cast(write(fd, buf, len)) != len) { - return absl::ErrnoToStatus(errno, "error reading to test runner"); - } - return absl::OkStatus(); -} -// define this macro when you want to debug struct_pb conformance test -// -#ifdef CONFORMANCE_CPP_DUMP_DATA -static int index = 0; -void write_to_file(const std::string& buffer, const std::string& tag, - const std::string& suffix) { - std::string filename = tag + "/" + std::to_string(index) + "." + suffix; - std::ofstream ofs; - ofs.open(filename, std::ios::out | std::ios::binary); - ofs.write(buffer.data(), buffer.size()); -} -#endif -class Harness { - public: - Harness() { - google::protobuf::LinkMessageReflection(); - google::protobuf::LinkMessageReflection(); - - resolver_.reset(NewTypeResolverForDescriptorPool( - "type.googleapis.com", DescriptorPool::generated_pool())); - type_url_ = absl::StrCat("type.googleapis.com/", - TestAllTypesProto3::GetDescriptor()->full_name()); - } - - absl::StatusOr RunTest( - const ConformanceRequest& request); - - // Returns Ok(true) if we're done processing requests. - absl::StatusOr ServeConformanceRequest(); - - private: - bool verbose_ = false; - std::unique_ptr resolver_; - std::string type_url_; -}; - -absl::StatusOr Harness::RunTest( - const ConformanceRequest& request) { - const Descriptor* descriptor = - DescriptorPool::generated_pool()->FindMessageTypeByName( - request.message_type()); - if (descriptor == nullptr) { - return absl::NotFoundError( - absl::StrCat("No such message type: ", request.message_type())); - } - - std::unique_ptr test_message( - MessageFactory::generated_factory()->GetPrototype(descriptor)->New()); - ConformanceResponse response; - - switch (request.payload_case()) { - case ConformanceRequest::kProtobufPayload: { - if (!test_message->ParseFromString(request.protobuf_payload())) { - response.set_parse_error("parse error (no more details available)"); - return response; - } - break; - } - - case ConformanceRequest::kJsonPayload: { - JsonParseOptions options; - options.ignore_unknown_fields = - (request.test_category() == - conformance::JSON_IGNORE_UNKNOWN_PARSING_TEST); - - std::string proto_binary; - auto status = - JsonToBinaryString(resolver_.get(), type_url_, request.json_payload(), - &proto_binary, options); - if (!status.ok()) { - response.set_parse_error( - absl::StrCat("parse error: ", status.message())); - return response; - } - - if (!test_message->ParseFromString(proto_binary)) { - response.set_runtime_error( - "parsing JSON generated invalid proto output"); - return response; - } - - break; - } - - case ConformanceRequest::kTextPayload: { - if (!TextFormat::ParseFromString(request.text_payload(), - test_message.get())) { - response.set_parse_error("parse error (no more details available)"); - return response; - } - break; - } - - case ConformanceRequest::PAYLOAD_NOT_SET: - return absl::InvalidArgumentError("request didn't have payload"); - - default: - return absl::InvalidArgumentError( - absl::StrCat("unknown payload type", request.payload_case())); - } -#ifdef CONFORMANCE_CPP_DUMP_DATA - write_to_file(test_message->DebugString(), "in", "msg.txt"); -#endif - switch (request.requested_output_format()) { - case conformance::UNSPECIFIED: - return absl::InvalidArgumentError("unspecified output format"); - - case conformance::PROTOBUF: { - GOOGLE_CHECK( - test_message->SerializeToString(response.mutable_protobuf_payload())); - break; - } - - case conformance::JSON: { - std::string proto_binary; - GOOGLE_CHECK(test_message->SerializeToString(&proto_binary)); - auto status = BinaryToJsonString(resolver_.get(), type_url_, proto_binary, - response.mutable_json_payload()); - if (!status.ok()) { - response.set_serialize_error(absl::StrCat( - "failed to serialize JSON output: ", status.message())); - } - break; - } - - case conformance::TEXT_FORMAT: { - TextFormat::Printer printer; - printer.SetHideUnknownFields(!request.print_unknown_fields()); - GOOGLE_CHECK(printer.PrintToString(*test_message, - response.mutable_text_payload())); - break; - } - - default: - return absl::InvalidArgumentError(absl::StrCat( - "unknown output format", request.requested_output_format())); - } - - return response; -} - -absl::StatusOr Harness::ServeConformanceRequest() { - uint32_t in_len; - if (!ReadFd(STDIN_FILENO, reinterpret_cast(&in_len), sizeof(in_len)) - .ok()) { - // EOF means we're done. - return true; - } - - std::string serialized_input; - serialized_input.resize(in_len); - RETURN_IF_ERROR(ReadFd(STDIN_FILENO, &serialized_input[0], in_len)); -#ifdef CONFORMANCE_CPP_DUMP_DATA - write_to_file(serialized_input, "in", "bin"); -#endif - ConformanceRequest request; - GOOGLE_CHECK(request.ParseFromString(serialized_input)); -#ifdef CONFORMANCE_CPP_DUMP_DATA - write_to_file( - std::to_string(serialized_input.size()) + "\n" + request.DebugString(), - "in", "txt"); -#endif - absl::StatusOr response = RunTest(request); - RETURN_IF_ERROR(response.status()); - - std::string serialized_output; - response->SerializeToString(&serialized_output); -#ifdef CONFORMANCE_CPP_DUMP_DATA - write_to_file(serialized_output, "out", "bin"); - write_to_file(response->DebugString(), "out", "txt"); - index++; -#endif - - uint32_t out_len = static_cast(serialized_output.size()); - RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, &out_len, sizeof(out_len))); - RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, serialized_output.data(), out_len)); - - if (verbose_) { - GOOGLE_LOG(INFO) << "conformance-cpp: request=" - << request.ShortDebugString() - << ", response=" << response->ShortDebugString(); - } - return false; -} -} // namespace -} // namespace protobuf -} // namespace google - -int main() { - google::protobuf::Harness harness; - int total_runs = 0; - while (true) { - auto is_done = harness.ServeConformanceRequest(); - if (!is_done.ok()) { - GOOGLE_LOG(FATAL) << is_done.status().message(); - } - if (*is_done) { - break; - } - total_runs++; - } - GOOGLE_LOG(INFO) << "conformance-cpp: received EOF from test runner after " - << total_runs << " tests"; -} diff --git a/src/struct_pb/conformance/conformance_struct_pb.cc b/src/struct_pb/conformance/conformance_struct_pb.cc deleted file mode 100644 index 5d7f2667c..000000000 --- a/src/struct_pb/conformance/conformance_struct_pb.cc +++ /dev/null @@ -1,242 +0,0 @@ -#include -#include -#include - -#include -#include -#include -#include -#include -namespace fs = std::filesystem; - -#include "absl/status/status.h" -#include "absl/status/statusor.h" -#include "conformance/conformance.struct_pb.h" -#include "google/protobuf/test_messages_proto2.struct_pb.h" -#include "google/protobuf/test_messages_proto3.struct_pb.h" - -#define RETURN_IF_ERROR(expr) \ - do { \ - /* Using _status below to avoid capture problems if expr is "status". */ \ - const absl::Status _status = (expr); \ - if (!_status.ok()) \ - return _status; \ - } while (0) - -using ::conformance::ConformanceRequest; -using ::conformance::ConformanceResponse; -using ::protobuf_test_messages::proto2::TestAllTypesProto2; -using ::protobuf_test_messages::proto3::TestAllTypesProto3; - -absl::Status ReadFd(int fd, char* buf, size_t len) { - while (len > 0) { - ssize_t bytes_read = read(fd, buf, len); - - if (bytes_read == 0) { - return absl::DataLossError("unexpected EOF"); - } - - if (bytes_read < 0) { - return absl::ErrnoToStatus(errno, "error reading from test runner"); - } - - len -= bytes_read; - buf += bytes_read; - } - return absl::OkStatus(); -} - -absl::Status WriteFd(int fd, const void* buf, size_t len) { - if (static_cast(write(fd, buf, len)) != len) { - return absl::ErrnoToStatus(errno, "error reading to test runner"); - } - return absl::OkStatus(); -} - -class Harness { - public: - Harness() {} - - absl::StatusOr RunTest( - const ConformanceRequest& request); - - // Returns Ok(true) if we're done processing requests. - absl::StatusOr ServeConformanceRequest(); - - private: - bool verbose_ = false; - std::string type_url_; -}; - -template -absl::StatusOr run_test( - const ConformanceRequest& request) { - ConformanceResponse response{}; - T data{}; - struct_pb::UnknownFields unknown_fields{}; - switch (request.payload_case()) { - case ConformanceRequest::PayloadCase::protobuf_payload: { - const auto& buffer = request.protobuf_payload(); - bool ok = struct_pb::internal::deserialize_to( - data, buffer.data(), buffer.size(), unknown_fields); - if (!ok) { - response.set_parse_error("parse error (no more details available)"); - return response; - } - break; - } - case ConformanceRequest::PayloadCase::none: - return absl::UnimplementedError("payload none"); - case ConformanceRequest::PayloadCase::json_payload: - return absl::UnimplementedError("payload json"); - case ConformanceRequest::PayloadCase::jspb_payload: - return absl::UnimplementedError("payload jspb"); - case ConformanceRequest::PayloadCase::text_payload: - return absl::UnimplementedError("payload text"); - default: { - int num = static_cast(request.payload_case()); - return absl::UnimplementedError("unknown payload type: " + - std::to_string(num)); - } - } - switch (request.requested_output_format) { - case conformance::WireFormat::PROTOBUF: { - response.set_protobuf_payload( - struct_pb::serialize(data, unknown_fields)); - break; - } - case conformance::WireFormat::UNSPECIFIED: - return absl::InvalidArgumentError("unspecified output format"); - case conformance::WireFormat::JSON: - return absl::UnimplementedError("output json"); - case conformance::WireFormat::JSPB: - return absl::UnimplementedError("output jspb"); - case conformance::WireFormat::TEXT_FORMAT: - return absl::UnimplementedError("output text"); - default: { - int num = static_cast(request.requested_output_format); - return absl::UnimplementedError("unknown output type: " + - std::to_string(num)); - } - } - return response; -} - -absl::StatusOr Harness::RunTest( - const ConformanceRequest& request) { - std::string pb2 = "protobuf_test_messages.proto2.TestAllTypesProto2"; - std::string pb3 = "protobuf_test_messages.proto3.TestAllTypesProto3"; - if (request.message_type == pb2) { - using Message = protobuf_test_messages::proto2::TestAllTypesProto2; - return run_test(request); - } - else if (request.message_type == pb3) { - using Message = protobuf_test_messages::proto3::TestAllTypesProto3; - return run_test(request); - } - else if (request.message_type == "conformance.FailureSet") { - return run_test(request); - } - else { - return absl::NotFoundError( - absl::StrCat("No such message type: ", request.message_type)); - } -} - -absl::StatusOr Harness::ServeConformanceRequest() { - uint32_t in_len; - if (!ReadFd(STDIN_FILENO, reinterpret_cast(&in_len), sizeof(in_len)) - .ok()) { - // EOF means we're done. - return true; - } - - std::string serialized_input; - serialized_input.resize(in_len); - RETURN_IF_ERROR(ReadFd(STDIN_FILENO, &serialized_input[0], in_len)); - - ConformanceRequest request{}; - const auto& buffer = serialized_input; - bool ok = struct_pb::internal::deserialize_to(request, buffer.data(), - buffer.size()); - if (!ok) { - return false; - } - - absl::StatusOr response = RunTest(request); - RETURN_IF_ERROR(response.status()); - - std::string serialized_output = struct_pb::serialize(*response); - - uint32_t out_len = static_cast(serialized_output.size()); - RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, &out_len, sizeof(out_len))); - RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, serialized_output.data(), out_len)); - if (verbose_) { - std::cerr << "conformance-cpp: request="; - std::cerr << request.message_type << std::endl; - } - return false; -} - -int main() { - Harness harness; - int total_runs = 0; - while (true) { - auto is_done = harness.ServeConformanceRequest(); - if (!is_done.ok()) { - std::cerr << is_done.status(); - } - if (*is_done) { - break; - } - total_runs++; - } - std::cerr << "conformance-struct_pb: received EOF from test runner after "; - std::cerr << total_runs << " tests" << std::endl; - return 0; -} - -// -// the following code is useful for debugging when struct_pb conformance test -// failed. -// - -std::string read_file(const std::string& tag, int index, - const std::string& suffix) { - std::string filename = tag + "/" + std::to_string(index) + "." + suffix; - std::ifstream ifs; - ifs.open(filename, std::ios::in | std::ios::binary); - std::size_t sz = fs::file_size(filename); - std::string buffer; - buffer.resize(sz); - ifs.read(buffer.data(), buffer.size()); - return buffer; -} -int debug_struct_pb() { - Harness harness; - int index = 0; - while (index < 1283) { - // use data generated by conformance_cpp - auto in_buf = read_file("in", index, "bin"); - auto out_buf = read_file("out", index, "bin"); - ConformanceRequest req{}; - bool ok = - struct_pb::internal::deserialize_to(req, in_buf.data(), in_buf.size()); - if (!ok) { - std::cout << "ERROR: " << index << " decode" << std::endl; - return 1; - } - auto ret = harness.RunTest(req); - if (!ret.ok()) { - std::cout << "ERROR: " << index << " run test" << std::endl; - return 2; - } - auto buf = struct_pb::serialize(*ret); - if (buf != out_buf) { - std::cout << "ERROR: " << index << " test fail" << std::endl; - return 3; - } - index++; - } - return 0; -} diff --git a/src/struct_pb/conformance/conformance_test.cc b/src/struct_pb/conformance/conformance_test.cc deleted file mode 100644 index 0f27ab2b7..000000000 --- a/src/struct_pb/conformance/conformance_test.cc +++ /dev/null @@ -1,526 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "conformance_test.h" - -#include - -#include -#include -#include - -#include "absl/strings/str_cat.h" -#include "absl/strings/str_format.h" -#include "conformance/conformance.pb.h" -#include "google/protobuf/message.h" -#include "google/protobuf/text_format.h" -#include "google/protobuf/util/field_comparator.h" -#include "google/protobuf/util/json_util.h" -#include "google/protobuf/util/message_differencer.h" - -using conformance::ConformanceRequest; -using conformance::ConformanceResponse; -using conformance::WireFormat; -using google::protobuf::TextFormat; -using google::protobuf::util::DefaultFieldComparator; -using google::protobuf::util::MessageDifferencer; -using std::string; - -namespace { - -static string ToOctString(const string& binary_string) { - string oct_string; - for (size_t i = 0; i < binary_string.size(); i++) { - uint8_t c = binary_string.at(i); - uint8_t high = c / 64; - uint8_t mid = (c % 64) / 8; - uint8_t low = c % 8; - oct_string.push_back('\\'); - oct_string.push_back('0' + high); - oct_string.push_back('0' + mid); - oct_string.push_back('0' + low); - } - return oct_string; -} - -} // namespace - -namespace google { -namespace protobuf { - -ConformanceTestSuite::ConformanceRequestSetting::ConformanceRequestSetting( - ConformanceLevel level, conformance::WireFormat input_format, - conformance::WireFormat output_format, - conformance::TestCategory test_category, const Message& prototype_message, - const string& test_name, const string& input) - : level_(level), - input_format_(input_format), - output_format_(output_format), - prototype_message_(prototype_message), - prototype_message_for_compare_(prototype_message.New()), - test_name_(test_name) { - switch (input_format) { - case conformance::PROTOBUF: { - request_.set_protobuf_payload(input); - break; - } - - case conformance::JSON: { - request_.set_json_payload(input); - break; - } - - case conformance::JSPB: { - request_.set_jspb_payload(input); - break; - } - - case conformance::TEXT_FORMAT: { - request_.set_text_payload(input); - break; - } - - default: - GOOGLE_LOG(FATAL) << "Unspecified input format"; - } - - request_.set_test_category(test_category); - - request_.set_message_type(prototype_message.GetDescriptor()->full_name()); - request_.set_requested_output_format(output_format); -} - -std::unique_ptr -ConformanceTestSuite::ConformanceRequestSetting::NewTestMessage() const { - return std::unique_ptr(prototype_message_for_compare_->New()); -} - -string ConformanceTestSuite::ConformanceRequestSetting::GetTestName() const { - string rname = prototype_message_.GetDescriptor()->file()->syntax() == - FileDescriptor::SYNTAX_PROTO3 - ? "Proto3" - : "Proto2"; - - return absl::StrCat(ConformanceLevelToString(level_), ".", rname, ".", - InputFormatString(input_format_), ".", test_name_, ".", - OutputFormatString(output_format_)); -} - -string -ConformanceTestSuite::ConformanceRequestSetting::ConformanceLevelToString( - ConformanceLevel level) const { - switch (level) { - case REQUIRED: - return "Required"; - case RECOMMENDED: - return "Recommended"; - } - GOOGLE_LOG(FATAL) << "Unknown value: " << level; - return ""; -} - -string ConformanceTestSuite::ConformanceRequestSetting::InputFormatString( - conformance::WireFormat format) const { - switch (format) { - case conformance::PROTOBUF: - return "ProtobufInput"; - case conformance::JSON: - return "JsonInput"; - case conformance::TEXT_FORMAT: - return "TextFormatInput"; - default: - GOOGLE_LOG(FATAL) << "Unspecified output format"; - } - return ""; -} - -string ConformanceTestSuite::ConformanceRequestSetting::OutputFormatString( - conformance::WireFormat format) const { - switch (format) { - case conformance::PROTOBUF: - return "ProtobufOutput"; - case conformance::JSON: - return "JsonOutput"; - case conformance::TEXT_FORMAT: - return "TextFormatOutput"; - default: - GOOGLE_LOG(FATAL) << "Unspecified output format"; - } - return ""; -} - -void ConformanceTestSuite::TruncateDebugPayload(string* payload) { - if (payload != nullptr && payload->size() > 200) { - payload->resize(200); - payload->append("...(truncated)"); - } -} - -const ConformanceRequest ConformanceTestSuite::TruncateRequest( - const ConformanceRequest& request) { - ConformanceRequest debug_request(request); - switch (debug_request.payload_case()) { - case ConformanceRequest::kProtobufPayload: - TruncateDebugPayload(debug_request.mutable_protobuf_payload()); - break; - case ConformanceRequest::kJsonPayload: - TruncateDebugPayload(debug_request.mutable_json_payload()); - break; - case ConformanceRequest::kTextPayload: - TruncateDebugPayload(debug_request.mutable_text_payload()); - break; - case ConformanceRequest::kJspbPayload: - TruncateDebugPayload(debug_request.mutable_jspb_payload()); - break; - default: - // Do nothing. - break; - } - return debug_request; -} - -const ConformanceResponse ConformanceTestSuite::TruncateResponse( - const ConformanceResponse& response) { - ConformanceResponse debug_response(response); - switch (debug_response.result_case()) { - case ConformanceResponse::kProtobufPayload: - TruncateDebugPayload(debug_response.mutable_protobuf_payload()); - break; - case ConformanceResponse::kJsonPayload: - TruncateDebugPayload(debug_response.mutable_json_payload()); - break; - case ConformanceResponse::kTextPayload: - TruncateDebugPayload(debug_response.mutable_text_payload()); - break; - case ConformanceResponse::kJspbPayload: - TruncateDebugPayload(debug_response.mutable_jspb_payload()); - break; - default: - // Do nothing. - break; - } - return debug_response; -} - -void ConformanceTestSuite::ReportSuccess(const string& test_name) { - if (expected_to_fail_.erase(test_name) != 0) { - absl::StrAppendFormat( - &output_, - "ERROR: test %s is in the failure list, but test succeeded. " - "Remove it from the failure list.\n", - test_name); - unexpected_succeeding_tests_.insert(test_name); - } - successes_++; -} - -void ConformanceTestSuite::ReportFailure(const string& test_name, - ConformanceLevel level, - const ConformanceRequest& request, - const ConformanceResponse& response, - std::string_view message) { - if (expected_to_fail_.erase(test_name) == 1) { - expected_failures_++; - if (!verbose_) - return; - } - else if (level == RECOMMENDED && !enforce_recommended_) { - absl::StrAppendFormat(&output_, "WARNING, test=%s: ", test_name); - } - else { - absl::StrAppendFormat(&output_, "ERROR, test=%s: ", test_name); - unexpected_failing_tests_.insert(test_name); - } - - absl::StrAppendFormat(&output_, "%s, request=%s, response=%s\n", message, - TruncateRequest(request).ShortDebugString(), - TruncateResponse(response).ShortDebugString()); -} - -void ConformanceTestSuite::ReportSkip(const string& test_name, - const ConformanceRequest& request, - const ConformanceResponse& response) { - if (verbose_) { - absl::StrAppendFormat( - &output_, "SKIPPED, test=%s request=%s, response=%s\n", test_name, - request.ShortDebugString(), response.ShortDebugString()); - } - skipped_.insert(test_name); -} - -void ConformanceTestSuite::RunValidInputTest( - const ConformanceRequestSetting& setting, - const string& equivalent_text_format) { - std::unique_ptr reference_message(setting.NewTestMessage()); - GOOGLE_CHECK(TextFormat::ParseFromString(equivalent_text_format, - reference_message.get())) - << "Failed to parse data for test case: " << setting.GetTestName() - << ", data: " << equivalent_text_format; - const string equivalent_wire_format = reference_message->SerializeAsString(); - RunValidBinaryInputTest(setting, equivalent_wire_format); -} - -void ConformanceTestSuite::RunValidBinaryInputTest( - const ConformanceRequestSetting& setting, - const string& equivalent_wire_format, bool require_same_wire_format) { - const ConformanceRequest& request = setting.GetRequest(); - ConformanceResponse response; - RunTest(setting.GetTestName(), request, &response); - VerifyResponse(setting, equivalent_wire_format, response, true, - require_same_wire_format); -} - -void ConformanceTestSuite::VerifyResponse( - const ConformanceRequestSetting& setting, - const string& equivalent_wire_format, const ConformanceResponse& response, - bool need_report_success, bool require_same_wire_format) { - std::unique_ptr test_message(setting.NewTestMessage()); - const ConformanceRequest& request = setting.GetRequest(); - const string& test_name = setting.GetTestName(); - ConformanceLevel level = setting.GetLevel(); - std::unique_ptr reference_message = setting.NewTestMessage(); - - GOOGLE_CHECK(reference_message->ParseFromString(equivalent_wire_format)) - << "Failed to parse wire data for test case: " << test_name; - - switch (response.result_case()) { - case ConformanceResponse::RESULT_NOT_SET: - ReportFailure(test_name, level, request, response, - "Response didn't have any field in the Response."); - return; - - case ConformanceResponse::kParseError: - case ConformanceResponse::kTimeoutError: - case ConformanceResponse::kRuntimeError: - case ConformanceResponse::kSerializeError: - ReportFailure(test_name, level, request, response, - "Failed to parse input or produce output."); - return; - - case ConformanceResponse::kSkipped: - ReportSkip(test_name, request, response); - return; - - default: - if (!ParseResponse(response, setting, test_message.get())) - return; - } - - MessageDifferencer differencer; - DefaultFieldComparator field_comparator; - field_comparator.set_treat_nan_as_equal(true); - differencer.set_field_comparator(&field_comparator); - string differences; - differencer.ReportDifferencesToString(&differences); - - bool check = false; - - if (require_same_wire_format) { - GOOGLE_DCHECK_EQ(response.result_case(), - ConformanceResponse::kProtobufPayload); - const string& protobuf_payload = response.protobuf_payload(); - check = equivalent_wire_format == protobuf_payload; - differences = absl::StrCat("Expect: ", ToOctString(equivalent_wire_format), - ", but got: ", ToOctString(protobuf_payload)); - } - else { - check = differencer.Compare(*reference_message, *test_message); - } - - if (check) { - if (need_report_success) { - ReportSuccess(test_name); - } - } - else { - ReportFailure( - test_name, level, request, response, - absl::StrCat("Output was not equivalent to reference message: ", - differences)); - } -} - -void ConformanceTestSuite::RunTest(const string& test_name, - const ConformanceRequest& request, - ConformanceResponse* response) { - if (test_names_.insert(test_name).second == false) { - GOOGLE_LOG(FATAL) << "Duplicated test name: " << test_name; - } - - string serialized_request; - string serialized_response; - request.SerializeToString(&serialized_request); - - runner_->RunTest(test_name, serialized_request, &serialized_response); - - if (!response->ParseFromString(serialized_response)) { - response->Clear(); - response->set_runtime_error("response proto could not be parsed."); - } - - if (verbose_) { - absl::StrAppendFormat( - &output_, "conformance test: name=%s, request=%s, response=%s\n", - test_name, TruncateRequest(request).ShortDebugString(), - TruncateResponse(*response).ShortDebugString()); - } -} - -bool ConformanceTestSuite::CheckSetEmpty(const std::set& set_to_check, - const std::string& write_to_file, - const std::string& msg) { - if (set_to_check.empty()) { - return true; - } - else { - absl::StrAppendFormat(&output_, "\n"); - absl::StrAppendFormat(&output_, "%s\n\n", msg); - for (std::string_view v : set_to_check) { - absl::StrAppendFormat(&output_, " %s\n", v); - } - absl::StrAppendFormat(&output_, "\n"); - - if (!write_to_file.empty()) { - std::string full_filename; - const std::string* filename = &write_to_file; - if (!output_dir_.empty()) { - full_filename = output_dir_; - if (*output_dir_.rbegin() != '/') { - full_filename.push_back('/'); - } - full_filename += write_to_file; - filename = &full_filename; - } - std::ofstream os(*filename); - if (os) { - for (std::string_view v : set_to_check) { - os << v << "\n"; - } - } - else { - absl::StrAppendFormat(&output_, "Failed to open file: %s\n", *filename); - } - } - - return false; - } -} - -string ConformanceTestSuite::WireFormatToString(WireFormat wire_format) { - switch (wire_format) { - case conformance::PROTOBUF: - return "PROTOBUF"; - case conformance::JSON: - return "JSON"; - case conformance::JSPB: - return "JSPB"; - case conformance::TEXT_FORMAT: - return "TEXT_FORMAT"; - case conformance::UNSPECIFIED: - return "UNSPECIFIED"; - default: - GOOGLE_LOG(FATAL) << "unknown wire type: " << wire_format; - } - return ""; -} - -void ConformanceTestSuite::AddExpectedFailedTest(const std::string& test_name) { - expected_to_fail_.insert(test_name); -} - -bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner, - std::string* output, const string& filename, - conformance::FailureSet* failure_list) { - runner_ = runner; - successes_ = 0; - expected_failures_ = 0; - skipped_.clear(); - test_names_.clear(); - unexpected_failing_tests_.clear(); - unexpected_succeeding_tests_.clear(); - - output_ = "\nCONFORMANCE TEST BEGIN ====================================\n\n"; - - failure_list_filename_ = filename; - expected_to_fail_.clear(); - for (const string& failure : failure_list->failure()) { - AddExpectedFailedTest(failure); - } - RunSuiteImpl(); - - bool ok = true; - if (!CheckSetEmpty(expected_to_fail_, "nonexistent_tests.txt", - "These tests were listed in the failure list, but they " - "don't exist. Remove them from the failure list by " - "running:\n" - " ./update_failure_list.py " + - failure_list_filename_ + - " --remove nonexistent_tests.txt")) { - ok = false; - } - if (!CheckSetEmpty(unexpected_failing_tests_, "failing_tests.txt", - "These tests failed. If they can't be fixed right now, " - "you can add them to the failure list so the overall " - "suite can succeed. Add them to the failure list by " - "running:\n" - " ./update_failure_list.py " + - failure_list_filename_ + " --add failing_tests.txt")) { - ok = false; - } - if (!CheckSetEmpty(unexpected_succeeding_tests_, "succeeding_tests.txt", - "These tests succeeded, even though they were listed in " - "the failure list. Remove them from the failure list " - "by running:\n" - " ./update_failure_list.py " + - failure_list_filename_ + - " --remove succeeding_tests.txt")) { - ok = false; - } - - if (verbose_) { - CheckSetEmpty(skipped_, "", - "These tests were skipped (probably because support for some " - "features is not implemented)"); - } - - absl::StrAppendFormat(&output_, - "CONFORMANCE SUITE %s: %d successes, %zu skipped, " - "%d expected failures, %zu unexpected failures.\n", - ok ? "PASSED" : "FAILED", successes_, skipped_.size(), - expected_failures_, unexpected_failing_tests_.size()); - absl::StrAppendFormat(&output_, "\n"); - - output->assign(output_); - - return ok; -} - -} // namespace protobuf -} // namespace google diff --git a/src/struct_pb/conformance/conformance_test.h b/src/struct_pb/conformance/conformance_test.h deleted file mode 100644 index cf09234aa..000000000 --- a/src/struct_pb/conformance/conformance_test.h +++ /dev/null @@ -1,331 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// This file defines a protocol for running the conformance test suite -// in-process. In other words, the suite itself will run in the same process as -// the code under test. -// -// For pros and cons of this approach, please see conformance.proto. - -#ifndef CONFORMANCE_CONFORMANCE_TEST_H -#define CONFORMANCE_CONFORMANCE_TEST_H - -#include -#include -#include - -#include "conformance/conformance.pb.h" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/util/type_resolver.h" -#include "google/protobuf/wire_format_lite.h" - -namespace conformance { -class ConformanceRequest; -class ConformanceResponse; -} // namespace conformance - -namespace protobuf_test_messages { -namespace proto3 { -class TestAllTypesProto3; -} // namespace proto3 -} // namespace protobuf_test_messages - -namespace google { -namespace protobuf { - -class ConformanceTestSuite; - -class ConformanceTestRunner { - public: - virtual ~ConformanceTestRunner() {} - - // Call to run a single conformance test. - // - // "input" is a serialized conformance.ConformanceRequest. - // "output" should be set to a serialized conformance.ConformanceResponse. - // - // If there is any error in running the test itself, set "runtime_error" in - // the response. - virtual void RunTest(const std::string& test_name, const std::string& input, - std::string* output) = 0; -}; - -// Test runner that spawns the process being tested and communicates with it -// over a pipe. -class ForkPipeRunner : public ConformanceTestRunner { - public: - // Note: Run() doesn't take ownership of the pointers inside suites. - static int Run(int argc, char* argv[], - const std::vector& suites); - - ForkPipeRunner(const std::string& executable, - const std::vector& executable_args, - bool performance) - : child_pid_(-1), - executable_(executable), - executable_args_(executable_args), - performance_(performance) {} - - explicit ForkPipeRunner(const std::string& executable) - : child_pid_(-1), executable_(executable) {} - - virtual ~ForkPipeRunner() {} - - void RunTest(const std::string& test_name, const std::string& request, - std::string* response); - - private: - void SpawnTestProgram(); - - void CheckedWrite(int fd, const void* buf, size_t len); - bool TryRead(int fd, void* buf, size_t len); - void CheckedRead(int fd, void* buf, size_t len); - - int write_fd_; - int read_fd_; - pid_t child_pid_; - std::string executable_; - const std::vector executable_args_; - bool performance_; - std::string current_test_name_; -}; - -// Class representing the test suite itself. To run it, implement your own -// class derived from ConformanceTestRunner, class derived from -// ConformanceTestSuite and then write code like: -// -// class MyConformanceTestSuite : public ConformanceTestSuite { -// public: -// void RunSuiteImpl() { -// // INSERT ACTUAL TESTS. -// } -// }; -// -// class MyConformanceTestRunner : public ConformanceTestRunner { -// public: -// static int Run(int argc, char *argv[], -// ConformanceTestSuite* suite); -// -// private: -// virtual void RunTest(...) { -// // INSERT YOUR FRAMEWORK-SPECIFIC CODE HERE. -// } -// }; -// -// int main() { -// MyConformanceTestSuite suite; -// MyConformanceTestRunner::Run(argc, argv, &suite); -// } -// -class ConformanceTestSuite { - public: - ConformanceTestSuite() - : verbose_(false), - performance_(false), - enforce_recommended_(false), - failure_list_flag_name_("--failure_list") {} - virtual ~ConformanceTestSuite() {} - - void SetPerformance(bool performance) { performance_ = performance; } - void SetVerbose(bool verbose) { verbose_ = verbose; } - - // Whether to require the testee to pass RECOMMENDED tests. By default failing - // a RECOMMENDED test case will not fail the entire suite but will only - // generated a warning. If this flag is set to true, RECOMMENDED tests will - // be treated the same way as REQUIRED tests and failing a RECOMMENDED test - // case will cause the entire test suite to fail as well. An implementation - // can enable this if it wants to be strictly conforming to protobuf spec. - // See the comments about ConformanceLevel below to learn more about the - // difference between REQUIRED and RECOMMENDED test cases. - void SetEnforceRecommended(bool value) { enforce_recommended_ = value; } - - // Gets the flag name to the failure list file. - // By default, this would return --failure_list - std::string GetFailureListFlagName() { return failure_list_flag_name_; } - - void SetFailureListFlagName(const std::string& failure_list_flag_name) { - failure_list_flag_name_ = failure_list_flag_name; - } - - // Sets the path of the output directory. - void SetOutputDir(const char* output_dir) { output_dir_ = output_dir; } - - // Run all the conformance tests against the given test runner. - // Test output will be stored in "output". - // - // Returns true if the set of failing tests was exactly the same as the - // failure list. - // The filename here is *only* used to create/format useful error messages for - // how to update the failure list. We do NOT read this file at all. - bool RunSuite(ConformanceTestRunner* runner, std::string* output, - const std::string& filename, - conformance::FailureSet* failure_list); - - protected: - // Test cases are classified into a few categories: - // REQUIRED: the test case must be passed for an implementation to be - // interoperable with other implementations. For example, a - // parser implementation must accept both packed and unpacked - // form of repeated primitive fields. - // RECOMMENDED: the test case is not required for the implementation to - // be interoperable with other implementations, but is - // recommended for best performance and compatibility. For - // example, a proto3 serializer should serialize repeated - // primitive fields in packed form, but an implementation - // failing to do so will still be able to communicate with - // other implementations. - enum ConformanceLevel { - REQUIRED = 0, - RECOMMENDED = 1, - }; - - class ConformanceRequestSetting { - public: - ConformanceRequestSetting(ConformanceLevel level, - conformance::WireFormat input_format, - conformance::WireFormat output_format, - conformance::TestCategory test_category, - const Message& prototype_message, - const std::string& test_name, - const std::string& input); - virtual ~ConformanceRequestSetting() {} - - std::unique_ptr NewTestMessage() const; - - std::string GetTestName() const; - - const conformance::ConformanceRequest& GetRequest() const { - return request_; - } - - const ConformanceLevel GetLevel() const { return level_; } - - std::string ConformanceLevelToString(ConformanceLevel level) const; - - void SetPrintUnknownFields(bool print_unknown_fields) { - request_.set_print_unknown_fields(true); - } - - void SetPrototypeMessageForCompare(const Message& message) { - prototype_message_for_compare_.reset(message.New()); - } - - protected: - virtual std::string InputFormatString(conformance::WireFormat format) const; - virtual std::string OutputFormatString( - conformance::WireFormat format) const; - conformance::ConformanceRequest request_; - - private: - ConformanceLevel level_; - ::conformance::WireFormat input_format_; - ::conformance::WireFormat output_format_; - const Message& prototype_message_; - std::unique_ptr prototype_message_for_compare_; - std::string test_name_; - }; - - bool CheckSetEmpty(const std::set& set_to_check, - const std::string& write_to_file, const std::string& msg); - std::string WireFormatToString(conformance::WireFormat wire_format); - - // Parse payload in the response to the given message. Returns true on - // success. - virtual bool ParseResponse(const conformance::ConformanceResponse& response, - const ConformanceRequestSetting& setting, - Message* test_message) = 0; - - void VerifyResponse(const ConformanceRequestSetting& setting, - const std::string& equivalent_wire_format, - const conformance::ConformanceResponse& response, - bool need_report_success, bool require_same_wire_format); - - void TruncateDebugPayload(std::string* payload); - const conformance::ConformanceRequest TruncateRequest( - const conformance::ConformanceRequest& request); - const conformance::ConformanceResponse TruncateResponse( - const conformance::ConformanceResponse& response); - - void ReportSuccess(const std::string& test_name); - void ReportFailure(const std::string& test_name, ConformanceLevel level, - const conformance::ConformanceRequest& request, - const conformance::ConformanceResponse& response, - std::string_view message); - void ReportSkip(const std::string& test_name, - const conformance::ConformanceRequest& request, - const conformance::ConformanceResponse& response); - - void RunValidInputTest(const ConformanceRequestSetting& setting, - const std::string& equivalent_text_format); - void RunValidBinaryInputTest(const ConformanceRequestSetting& setting, - const std::string& equivalent_wire_format, - bool require_same_wire_format = false); - - void RunTest(const std::string& test_name, - const conformance::ConformanceRequest& request, - conformance::ConformanceResponse* response); - - void AddExpectedFailedTest(const std::string& test_name); - - virtual void RunSuiteImpl() = 0; - - ConformanceTestRunner* runner_; - int successes_; - int expected_failures_; - bool verbose_; - bool performance_; - bool enforce_recommended_; - std::string output_; - std::string output_dir_; - std::string failure_list_flag_name_; - std::string failure_list_filename_; - - // The set of test names that are expected to fail in this run, but haven't - // failed yet. - std::set expected_to_fail_; - - // The set of test names that have been run. Used to ensure that there are no - // duplicate names in the suite. - std::set test_names_; - - // The set of tests that failed, but weren't expected to. - std::set unexpected_failing_tests_; - - // The set of tests that succeeded, but weren't expected to. - std::set unexpected_succeeding_tests_; - - // The set of tests that the testee opted out of; - std::set skipped_; -}; - -} // namespace protobuf -} // namespace google - -#endif // CONFORMANCE_CONFORMANCE_TEST_H diff --git a/src/struct_pb/conformance/conformance_test_main.cc b/src/struct_pb/conformance/conformance_test_main.cc deleted file mode 100644 index fe958f90a..000000000 --- a/src/struct_pb/conformance/conformance_test_main.cc +++ /dev/null @@ -1,38 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -#include "binary_json_conformance_suite.h" -#include "conformance_test.h" - -int main(int argc, char *argv[]) { - google::protobuf::BinaryAndJsonConformanceSuite binary_and_json_suite; - return google::protobuf::ForkPipeRunner::Run(argc, argv, - {&binary_and_json_suite}); -} diff --git a/src/struct_pb/conformance/conformance_test_runner.cc b/src/struct_pb/conformance/conformance_test_runner.cc deleted file mode 100644 index c52f650be..000000000 --- a/src/struct_pb/conformance/conformance_test_runner.cc +++ /dev/null @@ -1,407 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// This file contains a program for running the test suite in a separate -// process. The other alternative is to run the suite in-process. See -// conformance.proto for pros/cons of these two options. -// -// This program will fork the process under test and communicate with it over -// its stdin/stdout: -// -// +--------+ pipe +----------+ -// | tester | <------> | testee | -// | | | | -// | C++ | | any lang | -// +--------+ +----------+ -// -// The tester contains all of the test cases and their expected output. -// The testee is a simple program written in the target language that reads -// each test case and attempts to produce acceptable output for it. -// -// Every test consists of a ConformanceRequest/ConformanceResponse -// request/reply pair. The protocol on the pipe is simply: -// -// 1. tester sends 4-byte length N (little endian) -// 2. tester sends N bytes representing a ConformanceRequest proto -// 3. testee sends 4-byte length M (little endian) -// 4. testee sends M bytes representing a ConformanceResponse proto - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -// #include "absl/strings/str_format.h" -#include "conformance/conformance.pb.h" -#include "conformance_test.h" - -using conformance::ConformanceResponse; -using google::protobuf::ConformanceTestSuite; -using std::string; -using std::vector; - -#define STRINGIFY(x) #x -#define TOSTRING(x) STRINGIFY(x) -#define GOOGLE_CHECK_SYSCALL(call) \ - if (call < 0) { \ - perror(#call " " __FILE__ ":" TOSTRING(__LINE__)); \ - exit(1); \ - } - -namespace google { -namespace protobuf { - -void ParseFailureList(const char *filename, - conformance::FailureSet *failure_list) { - std::ifstream infile(filename); - - if (!infile.is_open()) { - fprintf(stderr, "Couldn't open failure list file: %s\n", filename); - exit(1); - } - - for (string line; getline(infile, line);) { - // Remove whitespace. - line.erase(std::remove_if(line.begin(), line.end(), ::isspace), line.end()); - - // Remove comments. - line = line.substr(0, line.find("#")); - - if (!line.empty()) { - failure_list->add_failure(line); - } - } -} - -void UsageError() { - fprintf(stderr, "Usage: conformance-test-runner [options] \n"); - fprintf(stderr, "\n"); - fprintf(stderr, "Options:\n"); - fprintf(stderr, - " --failure_list Use to specify list of tests\n"); - fprintf(stderr, - " that are expected to fail. File\n"); - fprintf(stderr, - " should contain one test name per\n"); - fprintf(stderr, - " line. Use '#' for comments.\n"); - fprintf(stderr, - " --text_format_failure_list Use to specify list \n"); - fprintf(stderr, - " of tests that are expected to \n"); - fprintf(stderr, " fail in the \n"); - fprintf(stderr, - " text_format_conformance_suite. \n"); - fprintf(stderr, - " File should contain one test name \n"); - fprintf(stderr, - " per line. Use '#' for comments.\n"); - - fprintf(stderr, - " --enforce_recommended Enforce that recommended test\n"); - fprintf(stderr, - " cases are also passing. Specify\n"); - fprintf(stderr, - " this flag if you want to be\n"); - fprintf(stderr, - " strictly conforming to protobuf\n"); - fprintf(stderr, " spec.\n"); - fprintf(stderr, - " --output_dir Directory to write\n" - " output files.\n"); - exit(1); -} - -void ForkPipeRunner::RunTest(const std::string &test_name, - const std::string &request, - std::string *response) { - if (child_pid_ < 0) { - SpawnTestProgram(); - } - current_test_name_ = test_name; - - uint32_t len = request.size(); - CheckedWrite(write_fd_, &len, sizeof(uint32_t)); - CheckedWrite(write_fd_, request.c_str(), request.size()); - - if (!TryRead(read_fd_, &len, sizeof(uint32_t))) { - // We failed to read from the child, assume a crash and try to reap. - GOOGLE_LOG(INFO) << "Trying to reap child, pid=" << child_pid_; - - int status = 0; - waitpid(child_pid_, &status, WEXITED); - - string error_msg; - conformance::ConformanceResponse response_obj; - if (WIFEXITED(status)) { - if (WEXITSTATUS(status) == 0) { - error_msg = "child timed out, killed by signal " + - std::to_string(WTERMSIG(status)); - response_obj.set_timeout_error(error_msg); - } - else { - error_msg = - "child exited, status=" + std::to_string(WEXITSTATUS(status)); - response_obj.set_runtime_error(error_msg); - } - } - else if (WIFSIGNALED(status)) { - error_msg = "child killed by signal " + std::to_string(WTERMSIG(status)); - } - GOOGLE_LOG(INFO) << error_msg; - child_pid_ = -1; - - response_obj.SerializeToString(response); - return; - } - - response->resize(len); - CheckedRead(read_fd_, (void *)response->c_str(), len); -} - -int ForkPipeRunner::Run(int argc, char *argv[], - const std::vector &suites) { - if (suites.empty()) { - fprintf(stderr, "No test suites found.\n"); - return EXIT_FAILURE; - } - bool all_ok = true; - for (ConformanceTestSuite *suite : suites) { - string program; - std::vector program_args; - string failure_list_filename; - conformance::FailureSet failure_list; - - bool performance = false; - for (int arg = 1; arg < argc; ++arg) { - if (strcmp(argv[arg], suite->GetFailureListFlagName().c_str()) == 0) { - if (++arg == argc) - UsageError(); - failure_list_filename = argv[arg]; - ParseFailureList(argv[arg], &failure_list); - } - else if (strcmp(argv[arg], "--performance") == 0) { - performance = true; - suite->SetPerformance(true); - } - else if (strcmp(argv[arg], "--verbose") == 0) { - suite->SetVerbose(true); - } - else if (strcmp(argv[arg], "--enforce_recommended") == 0) { - suite->SetEnforceRecommended(true); - } - else if (strcmp(argv[arg], "--output_dir") == 0) { - if (++arg == argc) - UsageError(); - suite->SetOutputDir(argv[arg]); - } - else if (argv[arg][0] == '-') { - bool recognized_flag = false; - for (ConformanceTestSuite *suite : suites) { - if (strcmp(argv[arg], suite->GetFailureListFlagName().c_str()) == 0) { - if (++arg == argc) - UsageError(); - recognized_flag = true; - } - } - if (!recognized_flag) { - fprintf(stderr, "Unknown option: %s\n", argv[arg]); - UsageError(); - } - } - else { - program += argv[arg++]; - while (arg < argc) { - program_args.push_back(argv[arg]); - arg++; - } - } - } - - ForkPipeRunner runner(program, program_args, performance); - - std::string output; - all_ok = all_ok && suite->RunSuite(&runner, &output, failure_list_filename, - &failure_list); - - fwrite(output.c_str(), 1, output.size(), stderr); - } - return all_ok ? EXIT_SUCCESS : EXIT_FAILURE; -} - -// TODO(haberman): make this work on Windows, instead of using these -// UNIX-specific APIs. -// -// There is a platform-agnostic API in -// src/google/protobuf/compiler/subprocess.h -// -// However that API only supports sending a single message to the subprocess. -// We really want to be able to send messages and receive responses one at a -// time: -// -// 1. Spawning a new process for each test would take way too long for thousands -// of tests and subprocesses like java that can take 100ms or more to start -// up. -// -// 2. Sending all the tests in one big message and receiving all results in one -// big message would take away our visibility about which test(s) caused a -// crash or other fatal error. It would also give us only a single failure -// instead of all of them. -void ForkPipeRunner::SpawnTestProgram() { - int toproc_pipe_fd[2]; - int fromproc_pipe_fd[2]; - if (pipe(toproc_pipe_fd) < 0 || pipe(fromproc_pipe_fd) < 0) { - perror("pipe"); - exit(1); - } - - pid_t pid = fork(); - if (pid < 0) { - perror("fork"); - exit(1); - } - - if (pid) { - // Parent. - GOOGLE_CHECK_SYSCALL(close(toproc_pipe_fd[0])); - GOOGLE_CHECK_SYSCALL(close(fromproc_pipe_fd[1])); - write_fd_ = toproc_pipe_fd[1]; - read_fd_ = fromproc_pipe_fd[0]; - child_pid_ = pid; - } - else { - // Child. - GOOGLE_CHECK_SYSCALL(close(STDIN_FILENO)); - GOOGLE_CHECK_SYSCALL(close(STDOUT_FILENO)); - GOOGLE_CHECK_SYSCALL(dup2(toproc_pipe_fd[0], STDIN_FILENO)); - GOOGLE_CHECK_SYSCALL(dup2(fromproc_pipe_fd[1], STDOUT_FILENO)); - - GOOGLE_CHECK_SYSCALL(close(toproc_pipe_fd[0])); - GOOGLE_CHECK_SYSCALL(close(fromproc_pipe_fd[1])); - GOOGLE_CHECK_SYSCALL(close(toproc_pipe_fd[1])); - GOOGLE_CHECK_SYSCALL(close(fromproc_pipe_fd[0])); - - std::unique_ptr executable(new char[executable_.size() + 1]); - memcpy(executable.get(), executable_.c_str(), executable_.size()); - executable[executable_.size()] = '\0'; - - std::vector argv; - argv.push_back(executable.get()); - GOOGLE_LOG(INFO) << argv[0]; - for (size_t i = 0; i < executable_args_.size(); ++i) { - argv.push_back(executable_args_[i].c_str()); - GOOGLE_LOG(INFO) << executable_args_[i]; - } - argv.push_back(nullptr); - // Never returns. - GOOGLE_CHECK_SYSCALL( - execv(executable.get(), const_cast(argv.data()))); - } -} - -void ForkPipeRunner::CheckedWrite(int fd, const void *buf, size_t len) { - if (static_cast(write(fd, buf, len)) != len) { - GOOGLE_LOG(FATAL) << current_test_name_ - << ": error writing to test program: " << strerror(errno); - } -} - -bool ForkPipeRunner::TryRead(int fd, void *buf, size_t len) { - size_t ofs = 0; - while (len > 0) { - std::future future = std::async( - std::launch::async, - [](int fd, void *buf, size_t ofs, size_t len) { - return read(fd, (char *)buf + ofs, len); - }, - fd, buf, ofs, len); - std::future_status status; - if (performance_) { - status = future.wait_for(std::chrono::seconds(5)); - if (status == std::future_status::timeout) { - GOOGLE_LOG(ERROR) << current_test_name_ - << ": timeout from test program"; - kill(child_pid_, SIGQUIT); - // TODO(sandyzhang): Only log in flag-guarded mode, since reading output - // from SIGQUIT is slow and verbose. - std::vector err; - err.resize(5000); - ssize_t err_bytes_read; - size_t err_ofs = 0; - do { - err_bytes_read = - read(fd, (void *)&err[err_ofs], err.size() - err_ofs); - err_ofs += err_bytes_read; - } while (err_bytes_read > 0 && err_ofs < err.size()); - GOOGLE_LOG(ERROR) << "child_pid_=" << child_pid_ << " SIGQUIT: \n" - << &err[0]; - return false; - } - } - else { - future.wait(); - } - ssize_t bytes_read = future.get(); - if (bytes_read == 0) { - GOOGLE_LOG(ERROR) << current_test_name_ - << ": unexpected EOF from test program"; - return false; - } - else if (bytes_read < 0) { - GOOGLE_LOG(ERROR) << current_test_name_ - << ": error reading from test program: " - << strerror(errno); - return false; - } - - len -= bytes_read; - ofs += bytes_read; - } - - return true; -} - -void ForkPipeRunner::CheckedRead(int fd, void *buf, size_t len) { - if (!TryRead(fd, buf, len)) { - GOOGLE_LOG(FATAL) << current_test_name_ - << ": error reading from test program: " - << strerror(errno); - } -} - -} // namespace protobuf -} // namespace google diff --git a/src/struct_pb/conformance/failure_list_cpp.txt b/src/struct_pb/conformance/failure_list_cpp.txt deleted file mode 100644 index 9974dbf67..000000000 --- a/src/struct_pb/conformance/failure_list_cpp.txt +++ /dev/null @@ -1,9 +0,0 @@ -# This is the list of conformance tests that are known to fail for the C++ -# implementation right now. These should be fixed. -# -# By listing them here we can keep tabs on which ones are failing and be sure -# that we don't introduce regressions in other tests. -# -# TODO(haberman): insert links to corresponding bugs tracking the issue. -# Should we use GitHub issues or the Google-internal bug tracker? - diff --git a/src/struct_pb/conformance/google/protobuf/any.proto b/src/struct_pb/conformance/google/protobuf/any.proto deleted file mode 100644 index 561da0cb1..000000000 --- a/src/struct_pb/conformance/google/protobuf/any.proto +++ /dev/null @@ -1,161 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option go_package = "google.golang.org/protobuf/types/known/anypb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "AnyProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// `Any` contains an arbitrary serialized protocol buffer message along with a -// URL that describes the type of the serialized message. -// -// Protobuf library provides support to pack/unpack Any values in the form -// of utility functions or additional generated methods of the Any type. -// -// Example 1: Pack and unpack a message in C++. -// -// Foo foo = ...; -// Any any; -// any.PackFrom(foo); -// ... -// if (any.UnpackTo(&foo)) { -// ... -// } -// -// Example 2: Pack and unpack a message in Java. -// -// Foo foo = ...; -// Any any = Any.pack(foo); -// ... -// if (any.is(Foo.class)) { -// foo = any.unpack(Foo.class); -// } -// // or ... -// if (any.isSameTypeAs(Foo.getDefaultInstance())) { -// foo = any.unpack(Foo.getDefaultInstance()); -// } -// -// Example 3: Pack and unpack a message in Python. -// -// foo = Foo(...) -// any = Any() -// any.Pack(foo) -// ... -// if any.Is(Foo.DESCRIPTOR): -// any.Unpack(foo) -// ... -// -// Example 4: Pack and unpack a message in Go -// -// foo := &pb.Foo{...} -// any, err := anypb.New(foo) -// if err != nil { -// ... -// } -// ... -// foo := &pb.Foo{} -// if err := any.UnmarshalTo(foo); err != nil { -// ... -// } -// -// The pack methods provided by protobuf library will by default use -// 'type.googleapis.com/full.type.name' as the type URL and the unpack -// methods only use the fully qualified type name after the last '/' -// in the type URL, for example "foo.bar.com/x/y.z" will yield type -// name "y.z". -// -// JSON -// -// The JSON representation of an `Any` value uses the regular -// representation of the deserialized, embedded message, with an -// additional field `@type` which contains the type URL. Example: -// -// package google.profile; -// message Person { -// string first_name = 1; -// string last_name = 2; -// } -// -// { -// "@type": "type.googleapis.com/google.profile.Person", -// "firstName": , -// "lastName": -// } -// -// If the embedded message type is well-known and has a custom JSON -// representation, that representation will be embedded adding a field -// `value` which holds the custom JSON in addition to the `@type` -// field. Example (for message [google.protobuf.Duration][]): -// -// { -// "@type": "type.googleapis.com/google.protobuf.Duration", -// "value": "1.212s" -// } -// -message Any { - // A URL/resource name that uniquely identifies the type of the serialized - // protocol buffer message. This string must contain at least - // one "/" character. The last segment of the URL's path must represent - // the fully qualified name of the type (as in - // `path/google.protobuf.Duration`). The name should be in a canonical form - // (e.g., leading "." is not accepted). - // - // In practice, teams usually precompile into the binary all types that they - // expect it to use in the context of Any. However, for URLs which use the - // scheme `http`, `https`, or no scheme, one can optionally set up a type - // server that maps type URLs to message definitions as follows: - // - // * If no scheme is provided, `https` is assumed. - // * An HTTP GET on the URL must yield a [google.protobuf.Type][] - // value in binary format, or produce an error. - // * Applications are allowed to cache lookup results based on the - // URL, or have them precompiled into a binary to avoid any - // lookup. Therefore, binary compatibility needs to be preserved - // on changes to types. (Use versioned type names to manage - // breaking changes.) - // - // Note: this functionality is not currently available in the official - // protobuf release, and it is not used for type URLs beginning with - // type.googleapis.com. - // - // Schemes other than `http`, `https` (or the empty scheme) might be - // used with implementation specific semantics. - // - string type_url = 1; - - // Must be a valid serialized protocol buffer of the above specified type. - bytes value = 2; -} diff --git a/src/struct_pb/conformance/google/protobuf/descriptor.proto b/src/struct_pb/conformance/google/protobuf/descriptor.proto deleted file mode 100644 index b65c0ea83..000000000 --- a/src/struct_pb/conformance/google/protobuf/descriptor.proto +++ /dev/null @@ -1,921 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. -// -// The messages in this file describe the definitions found in .proto files. -// A valid .proto file can be translated directly to a FileDescriptorProto -// without any other information (e.g. without reading its imports). - -syntax = "proto2"; - -package google.protobuf; - -option go_package = "google.golang.org/protobuf/types/descriptorpb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "DescriptorProtos"; -option csharp_namespace = "Google.Protobuf.Reflection"; -option objc_class_prefix = "GPB"; -option cc_enable_arenas = true; - -// descriptor.proto must be optimized for speed because reflection-based -// algorithms don't work during bootstrapping. -option optimize_for = SPEED; - -// The protocol compiler can output a FileDescriptorSet containing the .proto -// files it parses. -message FileDescriptorSet { - repeated FileDescriptorProto file = 1; -} - -// Describes a complete .proto file. -message FileDescriptorProto { - optional string name = 1; // file name, relative to root of source tree - optional string package = 2; // e.g. "foo", "foo.bar", etc. - - // Names of files imported by this file. - repeated string dependency = 3; - // Indexes of the public imported files in the dependency list above. - repeated int32 public_dependency = 10; - // Indexes of the weak imported files in the dependency list. - // For Google-internal migration only. Do not use. - repeated int32 weak_dependency = 11; - - // All top-level definitions in this file. - repeated DescriptorProto message_type = 4; - repeated EnumDescriptorProto enum_type = 5; - repeated ServiceDescriptorProto service = 6; - repeated FieldDescriptorProto extension = 7; - - optional FileOptions options = 8; - - // This field contains optional information about the original source code. - // You may safely remove this entire field without harming runtime - // functionality of the descriptors -- the information is needed only by - // development tools. - optional SourceCodeInfo source_code_info = 9; - - // The syntax of the proto file. - // The supported values are "proto2", "proto3", and "editions". - // - // If `edition` is present, this value must be "editions". - optional string syntax = 12; - - // The edition of the proto file, which is an opaque string. - optional string edition = 13; -} - -// Describes a message type. -message DescriptorProto { - optional string name = 1; - - repeated FieldDescriptorProto field = 2; - repeated FieldDescriptorProto extension = 6; - - repeated DescriptorProto nested_type = 3; - repeated EnumDescriptorProto enum_type = 4; - - message ExtensionRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Exclusive. - - optional ExtensionRangeOptions options = 3; - } - repeated ExtensionRange extension_range = 5; - - repeated OneofDescriptorProto oneof_decl = 8; - - optional MessageOptions options = 7; - - // Range of reserved tag numbers. Reserved tag numbers may not be used by - // fields or extension ranges in the same message. Reserved ranges may - // not overlap. - message ReservedRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Exclusive. - } - repeated ReservedRange reserved_range = 9; - // Reserved field names, which may not be used by fields in the same message. - // A given name may only be reserved once. - repeated string reserved_name = 10; -} - -message ExtensionRangeOptions { - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -// Describes a field within a message. -message FieldDescriptorProto { - enum Type { - // 0 is reserved for errors. - // Order is weird for historical reasons. - TYPE_DOUBLE = 1; - TYPE_FLOAT = 2; - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if - // negative values are likely. - TYPE_INT64 = 3; - TYPE_UINT64 = 4; - // Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if - // negative values are likely. - TYPE_INT32 = 5; - TYPE_FIXED64 = 6; - TYPE_FIXED32 = 7; - TYPE_BOOL = 8; - TYPE_STRING = 9; - // Tag-delimited aggregate. - // Group type is deprecated and not supported in proto3. However, Proto3 - // implementations should still be able to parse the group wire format and - // treat group fields as unknown fields. - TYPE_GROUP = 10; - TYPE_MESSAGE = 11; // Length-delimited aggregate. - - // New in version 2. - TYPE_BYTES = 12; - TYPE_UINT32 = 13; - TYPE_ENUM = 14; - TYPE_SFIXED32 = 15; - TYPE_SFIXED64 = 16; - TYPE_SINT32 = 17; // Uses ZigZag encoding. - TYPE_SINT64 = 18; // Uses ZigZag encoding. - } - - enum Label { - // 0 is reserved for errors - LABEL_OPTIONAL = 1; - LABEL_REQUIRED = 2; - LABEL_REPEATED = 3; - } - - optional string name = 1; - optional int32 number = 3; - optional Label label = 4; - - // If type_name is set, this need not be set. If both this and type_name - // are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP. - optional Type type = 5; - - // For message and enum types, this is the name of the type. If the name - // starts with a '.', it is fully-qualified. Otherwise, C++-like scoping - // rules are used to find the type (i.e. first the nested types within this - // message are searched, then within the parent, on up to the root - // namespace). - optional string type_name = 6; - - // For extensions, this is the name of the type being extended. It is - // resolved in the same manner as type_name. - optional string extendee = 2; - - // For numeric types, contains the original text representation of the value. - // For booleans, "true" or "false". - // For strings, contains the default text contents (not escaped in any way). - // For bytes, contains the C escaped value. All bytes >= 128 are escaped. - optional string default_value = 7; - - // If set, gives the index of a oneof in the containing type's oneof_decl - // list. This field is a member of that oneof. - optional int32 oneof_index = 9; - - // JSON name of this field. The value is set by protocol compiler. If the - // user has set a "json_name" option on this field, that option's value - // will be used. Otherwise, it's deduced from the field's name by converting - // it to camelCase. - optional string json_name = 10; - - optional FieldOptions options = 8; - - // If true, this is a proto3 "optional". When a proto3 field is optional, it - // tracks presence regardless of field type. - // - // When proto3_optional is true, this field must be belong to a oneof to - // signal to old proto3 clients that presence is tracked for this field. This - // oneof is known as a "synthetic" oneof, and this field must be its sole - // member (each proto3 optional field gets its own synthetic oneof). Synthetic - // oneofs exist in the descriptor only, and do not generate any API. Synthetic - // oneofs must be ordered after all "real" oneofs. - // - // For message fields, proto3_optional doesn't create any semantic change, - // since non-repeated message fields always track presence. However it still - // indicates the semantic detail of whether the user wrote "optional" or not. - // This can be useful for round-tripping the .proto file. For consistency we - // give message fields a synthetic oneof also, even though it is not required - // to track presence. This is especially important because the parser can't - // tell if a field is a message or an enum, so it must always create a - // synthetic oneof. - // - // Proto2 optional fields do not set this flag, because they already indicate - // optional with `LABEL_OPTIONAL`. - optional bool proto3_optional = 17; -} - -// Describes a oneof. -message OneofDescriptorProto { - optional string name = 1; - optional OneofOptions options = 2; -} - -// Describes an enum type. -message EnumDescriptorProto { - optional string name = 1; - - repeated EnumValueDescriptorProto value = 2; - - optional EnumOptions options = 3; - - // Range of reserved numeric values. Reserved values may not be used by - // entries in the same enum. Reserved ranges may not overlap. - // - // Note that this is distinct from DescriptorProto.ReservedRange in that it - // is inclusive such that it can appropriately represent the entire int32 - // domain. - message EnumReservedRange { - optional int32 start = 1; // Inclusive. - optional int32 end = 2; // Inclusive. - } - - // Range of reserved numeric values. Reserved numeric values may not be used - // by enum values in the same enum declaration. Reserved ranges may not - // overlap. - repeated EnumReservedRange reserved_range = 4; - - // Reserved enum value names, which may not be reused. A given name may only - // be reserved once. - repeated string reserved_name = 5; -} - -// Describes a value within an enum. -message EnumValueDescriptorProto { - optional string name = 1; - optional int32 number = 2; - - optional EnumValueOptions options = 3; -} - -// Describes a service. -message ServiceDescriptorProto { - optional string name = 1; - repeated MethodDescriptorProto method = 2; - - optional ServiceOptions options = 3; -} - -// Describes a method of a service. -message MethodDescriptorProto { - optional string name = 1; - - // Input and output type names. These are resolved in the same way as - // FieldDescriptorProto.type_name, but must refer to a message type. - optional string input_type = 2; - optional string output_type = 3; - - optional MethodOptions options = 4; - - // Identifies if client streams multiple client messages - optional bool client_streaming = 5 [default = false]; - // Identifies if server streams multiple server messages - optional bool server_streaming = 6 [default = false]; -} - -// =================================================================== -// Options - -// Each of the definitions above may have "options" attached. These are -// just annotations which may cause code to be generated slightly differently -// or may contain hints for code that manipulates protocol messages. -// -// Clients may define custom options as extensions of the *Options messages. -// These extensions may not yet be known at parsing time, so the parser cannot -// store the values in them. Instead it stores them in a field in the *Options -// message called uninterpreted_option. This field must have the same name -// across all *Options messages. We then use this field to populate the -// extensions when we build a descriptor, at which point all protos have been -// parsed and so all extensions are known. -// -// Extension numbers for custom options may be chosen as follows: -// * For options which will only be used within a single application or -// organization, or for experimental options, use field numbers 50000 -// through 99999. It is up to you to ensure that you do not use the -// same number for multiple options. -// * For options which will be published and used publicly by multiple -// independent entities, e-mail protobuf-global-extension-registry@google.com -// to reserve extension numbers. Simply provide your project name (e.g. -// Objective-C plugin) and your project website (if available) -- there's no -// need to explain how you intend to use them. Usually you only need one -// extension number. You can declare multiple options with only one extension -// number by putting them in a sub-message. See the Custom Options section of -// the docs for examples: -// https://developers.google.com/protocol-buffers/docs/proto#options -// If this turns out to be popular, a web service will be set up -// to automatically assign option numbers. - -message FileOptions { - - // Sets the Java package where classes generated from this .proto will be - // placed. By default, the proto package is used, but this is often - // inappropriate because proto packages do not normally start with backwards - // domain names. - optional string java_package = 1; - - // Controls the name of the wrapper Java class generated for the .proto file. - // That class will always contain the .proto file's getDescriptor() method as - // well as any top-level extensions defined in the .proto file. - // If java_multiple_files is disabled, then all the other classes from the - // .proto file will be nested inside the single wrapper outer class. - optional string java_outer_classname = 8; - - // If enabled, then the Java code generator will generate a separate .java - // file for each top-level message, enum, and service defined in the .proto - // file. Thus, these types will *not* be nested inside the wrapper class - // named by java_outer_classname. However, the wrapper class will still be - // generated to contain the file's getDescriptor() method as well as any - // top-level extensions defined in the file. - optional bool java_multiple_files = 10 [default = false]; - - // This option does nothing. - optional bool java_generate_equals_and_hash = 20 [deprecated = true]; - - // If set true, then the Java2 code generator will generate code that - // throws an exception whenever an attempt is made to assign a non-UTF-8 - // byte sequence to a string field. - // Message reflection will do the same. - // However, an extension field still accepts non-UTF-8 byte sequences. - // This option has no effect on when used with the lite runtime. - optional bool java_string_check_utf8 = 27 [default = false]; - - // Generated classes can be optimized for speed or code size. - enum OptimizeMode { - SPEED = 1; // Generate complete code for parsing, serialization, - // etc. - CODE_SIZE = 2; // Use ReflectionOps to implement these methods. - LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime. - } - optional OptimizeMode optimize_for = 9 [default = SPEED]; - - // Sets the Go package where structs generated from this .proto will be - // placed. If omitted, the Go package will be derived from the following: - // - The basename of the package import path, if provided. - // - Otherwise, the package statement in the .proto file, if present. - // - Otherwise, the basename of the .proto file, without extension. - optional string go_package = 11; - - // Should generic services be generated in each language? "Generic" services - // are not specific to any particular RPC system. They are generated by the - // main code generators in each language (without additional plugins). - // Generic services were the only kind of service generation supported by - // early versions of google.protobuf. - // - // Generic services are now considered deprecated in favor of using plugins - // that generate code specific to your particular RPC system. Therefore, - // these default to false. Old code which depends on generic services should - // explicitly set them to true. - optional bool cc_generic_services = 16 [default = false]; - optional bool java_generic_services = 17 [default = false]; - optional bool py_generic_services = 18 [default = false]; - optional bool php_generic_services = 42 [default = false]; - - // Is this file deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for everything in the file, or it will be completely ignored; in the very - // least, this is a formalization for deprecating files. - optional bool deprecated = 23 [default = false]; - - // Enables the use of arenas for the proto messages in this file. This applies - // only to generated classes for C++. - optional bool cc_enable_arenas = 31 [default = true]; - - // Sets the objective c class prefix which is prepended to all objective c - // generated classes from this .proto. There is no default. - optional string objc_class_prefix = 36; - - // Namespace for generated classes; defaults to the package. - optional string csharp_namespace = 37; - - // By default Swift generators will take the proto package and CamelCase it - // replacing '.' with underscore and use that to prefix the types/symbols - // defined. When this options is provided, they will use this value instead - // to prefix the types/symbols defined. - optional string swift_prefix = 39; - - // Sets the php class prefix which is prepended to all php generated classes - // from this .proto. Default is empty. - optional string php_class_prefix = 40; - - // Use this option to change the namespace of php generated classes. Default - // is empty. When this option is empty, the package name will be used for - // determining the namespace. - optional string php_namespace = 41; - - // Use this option to change the namespace of php generated metadata classes. - // Default is empty. When this option is empty, the proto file name will be - // used for determining the namespace. - optional string php_metadata_namespace = 44; - - // Use this option to change the package of ruby generated classes. Default - // is empty. When this option is not set, the package name will be used for - // determining the ruby package. - optional string ruby_package = 45; - - // The parser stores options it doesn't recognize here. - // See the documentation for the "Options" section above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. - // See the documentation for the "Options" section above. - extensions 1000 to max; - - reserved 38; -} - -message MessageOptions { - // Set true to use the old proto1 MessageSet wire format for extensions. - // This is provided for backwards-compatibility with the MessageSet wire - // format. You should not use this for any other reason: It's less - // efficient, has fewer features, and is more complicated. - // - // The message must be defined exactly as follows: - // message Foo { - // option message_set_wire_format = true; - // extensions 4 to max; - // } - // Note that the message cannot have any defined fields; MessageSets only - // have extensions. - // - // All extensions of your type must be singular messages; e.g. they cannot - // be int32s, enums, or repeated messages. - // - // Because this is an option, the above two restrictions are not enforced by - // the protocol compiler. - optional bool message_set_wire_format = 1 [default = false]; - - // Disables the generation of the standard "descriptor()" accessor, which can - // conflict with a field of the same name. This is meant to make migration - // from proto1 easier; new code should avoid fields named "descriptor". - optional bool no_standard_descriptor_accessor = 2 [default = false]; - - // Is this message deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the message, or it will be completely ignored; in the very least, - // this is a formalization for deprecating messages. - optional bool deprecated = 3 [default = false]; - - reserved 4, 5, 6; - - // NOTE: Do not set the option in .proto files. Always use the maps syntax - // instead. The option should only be implicitly set by the proto compiler - // parser. - // - // Whether the message is an automatically generated map entry type for the - // maps field. - // - // For maps fields: - // map map_field = 1; - // The parsed descriptor looks like: - // message MapFieldEntry { - // option map_entry = true; - // optional KeyType key = 1; - // optional ValueType value = 2; - // } - // repeated MapFieldEntry map_field = 1; - // - // Implementations may choose not to generate the map_entry=true message, but - // use a native map in the target language to hold the keys and values. - // The reflection APIs in such implementations still need to work as - // if the field is a repeated message field. - optional bool map_entry = 7; - - reserved 8; // javalite_serializable - reserved 9; // javanano_as_lite - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message FieldOptions { - // The ctype option instructs the C++ code generator to use a different - // representation of the field than it normally would. See the specific - // options below. This option is not yet implemented in the open source - // release -- sorry, we'll try to include it in a future version! - optional CType ctype = 1 [default = STRING]; - enum CType { - // Default mode. - STRING = 0; - - CORD = 1; - - STRING_PIECE = 2; - } - // The packed option can be enabled for repeated primitive fields to enable - // a more efficient representation on the wire. Rather than repeatedly - // writing the tag and type for each element, the entire array is encoded as - // a single length-delimited blob. In proto3, only explicit setting it to - // false will avoid using packed encoding. - optional bool packed = 2; - - // The jstype option determines the JavaScript type used for values of the - // field. The option is permitted only for 64 bit integral and fixed types - // (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING - // is represented as JavaScript string, which avoids loss of precision that - // can happen when a large value is converted to a floating point JavaScript. - // Specifying JS_NUMBER for the jstype causes the generated JavaScript code to - // use the JavaScript "number" type. The behavior of the default option - // JS_NORMAL is implementation dependent. - // - // This option is an enum to permit additional types to be added, e.g. - // goog.math.Integer. - optional JSType jstype = 6 [default = JS_NORMAL]; - enum JSType { - // Use the default type. - JS_NORMAL = 0; - - // Use JavaScript strings. - JS_STRING = 1; - - // Use JavaScript numbers. - JS_NUMBER = 2; - } - - // Should this field be parsed lazily? Lazy applies only to message-type - // fields. It means that when the outer message is initially parsed, the - // inner message's contents will not be parsed but instead stored in encoded - // form. The inner message will actually be parsed when it is first accessed. - // - // This is only a hint. Implementations are free to choose whether to use - // eager or lazy parsing regardless of the value of this option. However, - // setting this option true suggests that the protocol author believes that - // using lazy parsing on this field is worth the additional bookkeeping - // overhead typically needed to implement it. - // - // This option does not affect the public interface of any generated code; - // all method signatures remain the same. Furthermore, thread-safety of the - // interface is not affected by this option; const methods remain safe to - // call from multiple threads concurrently, while non-const methods continue - // to require exclusive access. - // - // Note that implementations may choose not to check required fields within - // a lazy sub-message. That is, calling IsInitialized() on the outer message - // may return true even if the inner message has missing required fields. - // This is necessary because otherwise the inner message would have to be - // parsed in order to perform the check, defeating the purpose of lazy - // parsing. An implementation which chooses not to check required fields - // must be consistent about it. That is, for any particular sub-message, the - // implementation must either *always* check its required fields, or *never* - // check its required fields, regardless of whether or not the message has - // been parsed. - // - // As of May 2022, lazy verifies the contents of the byte stream during - // parsing. An invalid byte stream will cause the overall parsing to fail. - optional bool lazy = 5 [default = false]; - - // unverified_lazy does no correctness checks on the byte stream. This should - // only be used where lazy with verification is prohibitive for performance - // reasons. - optional bool unverified_lazy = 15 [default = false]; - - // Is this field deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for accessors, or it will be completely ignored; in the very least, this - // is a formalization for deprecating fields. - optional bool deprecated = 3 [default = false]; - - // For Google-internal migration only. Do not use. - optional bool weak = 10 [default = false]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; - - reserved 4; // removed jtype -} - -message OneofOptions { - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message EnumOptions { - - // Set this option to true to allow mapping different tag names to the same - // value. - optional bool allow_alias = 2; - - // Is this enum deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum, or it will be completely ignored; in the very least, this - // is a formalization for deprecating enums. - optional bool deprecated = 3 [default = false]; - - reserved 5; // javanano_as_lite - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message EnumValueOptions { - // Is this enum value deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the enum value, or it will be completely ignored; in the very least, - // this is a formalization for deprecating enum values. - optional bool deprecated = 1 [default = false]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message ServiceOptions { - - // Note: Field numbers 1 through 32 are reserved for Google's internal RPC - // framework. We apologize for hoarding these numbers to ourselves, but - // we were already using them long before we decided to release Protocol - // Buffers. - - // Is this service deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the service, or it will be completely ignored; in the very least, - // this is a formalization for deprecating services. - optional bool deprecated = 33 [default = false]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -message MethodOptions { - - // Note: Field numbers 1 through 32 are reserved for Google's internal RPC - // framework. We apologize for hoarding these numbers to ourselves, but - // we were already using them long before we decided to release Protocol - // Buffers. - - // Is this method deprecated? - // Depending on the target platform, this can emit Deprecated annotations - // for the method, or it will be completely ignored; in the very least, - // this is a formalization for deprecating methods. - optional bool deprecated = 33 [default = false]; - - // Is this method side-effect-free (or safe in HTTP parlance), or idempotent, - // or neither? HTTP based RPC implementation may choose GET verb for safe - // methods, and PUT verb for idempotent methods instead of the default POST. - enum IdempotencyLevel { - IDEMPOTENCY_UNKNOWN = 0; - NO_SIDE_EFFECTS = 1; // implies idempotent - IDEMPOTENT = 2; // idempotent, but may have side effects - } - optional IdempotencyLevel idempotency_level = 34 - [default = IDEMPOTENCY_UNKNOWN]; - - // The parser stores options it doesn't recognize here. See above. - repeated UninterpretedOption uninterpreted_option = 999; - - // Clients can define custom options in extensions of this message. See above. - extensions 1000 to max; -} - -// A message representing a option the parser does not recognize. This only -// appears in options protos created by the compiler::Parser class. -// DescriptorPool resolves these when building Descriptor objects. Therefore, -// options protos in descriptor objects (e.g. returned by Descriptor::options(), -// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions -// in them. -message UninterpretedOption { - // The name of the uninterpreted option. Each string represents a segment in - // a dot-separated name. is_extension is true iff a segment represents an - // extension (denoted with parentheses in options specs in .proto files). - // E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents - // "foo.(bar.baz).moo". - message NamePart { - required string name_part = 1; - required bool is_extension = 2; - } - repeated NamePart name = 2; - - // The value of the uninterpreted option, in whatever type the tokenizer - // identified it as during parsing. Exactly one of these should be set. - optional string identifier_value = 3; - optional uint64 positive_int_value = 4; - optional int64 negative_int_value = 5; - optional double double_value = 6; - optional bytes string_value = 7; - optional string aggregate_value = 8; -} - -// =================================================================== -// Optional source code info - -// Encapsulates information about the original source file from which a -// FileDescriptorProto was generated. -message SourceCodeInfo { - // A Location identifies a piece of source code in a .proto file which - // corresponds to a particular definition. This information is intended - // to be useful to IDEs, code indexers, documentation generators, and similar - // tools. - // - // For example, say we have a file like: - // message Foo { - // optional string foo = 1; - // } - // Let's look at just the field definition: - // optional string foo = 1; - // ^ ^^ ^^ ^ ^^^ - // a bc de f ghi - // We have the following locations: - // span path represents - // [a,i) [ 4, 0, 2, 0 ] The whole field definition. - // [a,b) [ 4, 0, 2, 0, 4 ] The label (optional). - // [c,d) [ 4, 0, 2, 0, 5 ] The type (string). - // [e,f) [ 4, 0, 2, 0, 1 ] The name (foo). - // [g,h) [ 4, 0, 2, 0, 3 ] The number (1). - // - // Notes: - // - A location may refer to a repeated field itself (i.e. not to any - // particular index within it). This is used whenever a set of elements are - // logically enclosed in a single code segment. For example, an entire - // extend block (possibly containing multiple extension definitions) will - // have an outer location whose path refers to the "extensions" repeated - // field without an index. - // - Multiple locations may have the same path. This happens when a single - // logical declaration is spread out across multiple places. The most - // obvious example is the "extend" block again -- there may be multiple - // extend blocks in the same scope, each of which will have the same path. - // - A location's span is not always a subset of its parent's span. For - // example, the "extendee" of an extension declaration appears at the - // beginning of the "extend" block and is shared by all extensions within - // the block. - // - Just because a location's span is a subset of some other location's span - // does not mean that it is a descendant. For example, a "group" defines - // both a type and a field in a single declaration. Thus, the locations - // corresponding to the type and field and their components will overlap. - // - Code which tries to interpret locations should probably be designed to - // ignore those that it doesn't understand, as more types of locations could - // be recorded in the future. - repeated Location location = 1; - message Location { - // Identifies which part of the FileDescriptorProto was defined at this - // location. - // - // Each element is a field number or an index. They form a path from - // the root FileDescriptorProto to the place where the definition occurs. - // For example, this path: - // [ 4, 3, 2, 7, 1 ] - // refers to: - // file.message_type(3) // 4, 3 - // .field(7) // 2, 7 - // .name() // 1 - // This is because FileDescriptorProto.message_type has field number 4: - // repeated DescriptorProto message_type = 4; - // and DescriptorProto.field has field number 2: - // repeated FieldDescriptorProto field = 2; - // and FieldDescriptorProto.name has field number 1: - // optional string name = 1; - // - // Thus, the above path gives the location of a field name. If we removed - // the last element: - // [ 4, 3, 2, 7 ] - // this path refers to the whole field declaration (from the beginning - // of the label to the terminating semicolon). - repeated int32 path = 1 [packed = true]; - - // Always has exactly three or four elements: start line, start column, - // end line (optional, otherwise assumed same as start line), end column. - // These are packed into a single field for efficiency. Note that line - // and column numbers are zero-based -- typically you will want to add - // 1 to each before displaying to a user. - repeated int32 span = 2 [packed = true]; - - // If this SourceCodeInfo represents a complete declaration, these are any - // comments appearing before and after the declaration which appear to be - // attached to the declaration. - // - // A series of line comments appearing on consecutive lines, with no other - // tokens appearing on those lines, will be treated as a single comment. - // - // leading_detached_comments will keep paragraphs of comments that appear - // before (but not connected to) the current element. Each paragraph, - // separated by empty lines, will be one comment element in the repeated - // field. - // - // Only the comment content is provided; comment markers (e.g. //) are - // stripped out. For block comments, leading whitespace and an asterisk - // will be stripped from the beginning of each line other than the first. - // Newlines are included in the output. - // - // Examples: - // - // optional int32 foo = 1; // Comment attached to foo. - // // Comment attached to bar. - // optional int32 bar = 2; - // - // optional string baz = 3; - // // Comment attached to baz. - // // Another line attached to baz. - // - // // Comment attached to moo. - // // - // // Another line attached to moo. - // optional double moo = 4; - // - // // Detached comment for corge. This is not leading or trailing comments - // // to moo or corge because there are blank lines separating it from - // // both. - // - // // Detached comment for corge paragraph 2. - // - // optional string corge = 5; - // /* Block comment attached - // * to corge. Leading asterisks - // * will be removed. */ - // /* Block comment attached to - // * grault. */ - // optional int32 grault = 6; - // - // // ignored detached comments. - optional string leading_comments = 3; - optional string trailing_comments = 4; - repeated string leading_detached_comments = 6; - } -} - -// Describes the relationship between generated code and its original source -// file. A GeneratedCodeInfo message is associated with only one generated -// source file, but may contain references to different source .proto files. -message GeneratedCodeInfo { - // An Annotation connects some span of text in generated code to an element - // of its generating .proto file. - repeated Annotation annotation = 1; - message Annotation { - // Identifies the element in the original source .proto file. This field - // is formatted the same as SourceCodeInfo.Location.path. - repeated int32 path = 1 [packed = true]; - - // Identifies the filesystem path to the original source .proto. - optional string source_file = 2; - - // Identifies the starting offset in bytes in the generated code - // that relates to the identified object. - optional int32 begin = 3; - - // Identifies the ending offset in bytes in the generated code that - // relates to the identified object. The end offset should be one past - // the last relevant byte (so the length of the text = end - begin). - optional int32 end = 4; - - // Represents the identified object's effect on the element in the original - // .proto file. - enum Semantic { - // There is no effect or the effect is indescribable. - NONE = 0; - // The element is set or otherwise mutated. - SET = 1; - // An alias to the element is returned. - ALIAS = 2; - } - optional Semantic semantic = 5; - } -} diff --git a/src/struct_pb/conformance/google/protobuf/duration.proto b/src/struct_pb/conformance/google/protobuf/duration.proto deleted file mode 100644 index 41f40c222..000000000 --- a/src/struct_pb/conformance/google/protobuf/duration.proto +++ /dev/null @@ -1,115 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/durationpb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "DurationProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// A Duration represents a signed, fixed-length span of time represented -// as a count of seconds and fractions of seconds at nanosecond -// resolution. It is independent of any calendar and concepts like "day" -// or "month". It is related to Timestamp in that the difference between -// two Timestamp values is a Duration and it can be added or subtracted -// from a Timestamp. Range is approximately +-10,000 years. -// -// # Examples -// -// Example 1: Compute Duration from two Timestamps in pseudo code. -// -// Timestamp start = ...; -// Timestamp end = ...; -// Duration duration = ...; -// -// duration.seconds = end.seconds - start.seconds; -// duration.nanos = end.nanos - start.nanos; -// -// if (duration.seconds < 0 && duration.nanos > 0) { -// duration.seconds += 1; -// duration.nanos -= 1000000000; -// } else if (duration.seconds > 0 && duration.nanos < 0) { -// duration.seconds -= 1; -// duration.nanos += 1000000000; -// } -// -// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code. -// -// Timestamp start = ...; -// Duration duration = ...; -// Timestamp end = ...; -// -// end.seconds = start.seconds + duration.seconds; -// end.nanos = start.nanos + duration.nanos; -// -// if (end.nanos < 0) { -// end.seconds -= 1; -// end.nanos += 1000000000; -// } else if (end.nanos >= 1000000000) { -// end.seconds += 1; -// end.nanos -= 1000000000; -// } -// -// Example 3: Compute Duration from datetime.timedelta in Python. -// -// td = datetime.timedelta(days=3, minutes=10) -// duration = Duration() -// duration.FromTimedelta(td) -// -// # JSON Mapping -// -// In JSON format, the Duration type is encoded as a string rather than an -// object, where the string ends in the suffix "s" (indicating seconds) and -// is preceded by the number of seconds, with nanoseconds expressed as -// fractional seconds. For example, 3 seconds with 0 nanoseconds should be -// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should -// be expressed in JSON format as "3.000000001s", and 3 seconds and 1 -// microsecond should be expressed in JSON format as "3.000001s". -// -message Duration { - // Signed seconds of the span of time. Must be from -315,576,000,000 - // to +315,576,000,000 inclusive. Note: these bounds are computed from: - // 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years - int64 seconds = 1; - - // Signed fractions of a second at nanosecond resolution of the span - // of time. Durations less than one second are represented with a 0 - // `seconds` field and a positive or negative `nanos` field. For durations - // of one second or more, a non-zero value for the `nanos` field must be - // of the same sign as the `seconds` field. Must be from -999,999,999 - // to +999,999,999 inclusive. - int32 nanos = 2; -} diff --git a/src/struct_pb/conformance/google/protobuf/field_mask.proto b/src/struct_pb/conformance/google/protobuf/field_mask.proto deleted file mode 100644 index b28334b94..000000000 --- a/src/struct_pb/conformance/google/protobuf/field_mask.proto +++ /dev/null @@ -1,245 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "FieldMaskProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb"; -option cc_enable_arenas = true; - -// `FieldMask` represents a set of symbolic field paths, for example: -// -// paths: "f.a" -// paths: "f.b.d" -// -// Here `f` represents a field in some root message, `a` and `b` -// fields in the message found in `f`, and `d` a field found in the -// message in `f.b`. -// -// Field masks are used to specify a subset of fields that should be -// returned by a get operation or modified by an update operation. -// Field masks also have a custom JSON encoding (see below). -// -// # Field Masks in Projections -// -// When used in the context of a projection, a response message or -// sub-message is filtered by the API to only contain those fields as -// specified in the mask. For example, if the mask in the previous -// example is applied to a response message as follows: -// -// f { -// a : 22 -// b { -// d : 1 -// x : 2 -// } -// y : 13 -// } -// z: 8 -// -// The result will not contain specific values for fields x,y and z -// (their value will be set to the default, and omitted in proto text -// output): -// -// -// f { -// a : 22 -// b { -// d : 1 -// } -// } -// -// A repeated field is not allowed except at the last position of a -// paths string. -// -// If a FieldMask object is not present in a get operation, the -// operation applies to all fields (as if a FieldMask of all fields -// had been specified). -// -// Note that a field mask does not necessarily apply to the -// top-level response message. In case of a REST get operation, the -// field mask applies directly to the response, but in case of a REST -// list operation, the mask instead applies to each individual message -// in the returned resource list. In case of a REST custom method, -// other definitions may be used. Where the mask applies will be -// clearly documented together with its declaration in the API. In -// any case, the effect on the returned resource/resources is required -// behavior for APIs. -// -// # Field Masks in Update Operations -// -// A field mask in update operations specifies which fields of the -// targeted resource are going to be updated. The API is required -// to only change the values of the fields as specified in the mask -// and leave the others untouched. If a resource is passed in to -// describe the updated values, the API ignores the values of all -// fields not covered by the mask. -// -// If a repeated field is specified for an update operation, new values will -// be appended to the existing repeated field in the target resource. Note that -// a repeated field is only allowed in the last position of a `paths` string. -// -// If a sub-message is specified in the last position of the field mask for an -// update operation, then new value will be merged into the existing sub-message -// in the target resource. -// -// For example, given the target message: -// -// f { -// b { -// d: 1 -// x: 2 -// } -// c: [1] -// } -// -// And an update message: -// -// f { -// b { -// d: 10 -// } -// c: [2] -// } -// -// then if the field mask is: -// -// paths: ["f.b", "f.c"] -// -// then the result will be: -// -// f { -// b { -// d: 10 -// x: 2 -// } -// c: [1, 2] -// } -// -// An implementation may provide options to override this default behavior for -// repeated and message fields. -// -// In order to reset a field's value to the default, the field must -// be in the mask and set to the default value in the provided resource. -// Hence, in order to reset all fields of a resource, provide a default -// instance of the resource and set all fields in the mask, or do -// not provide a mask as described below. -// -// If a field mask is not present on update, the operation applies to -// all fields (as if a field mask of all fields has been specified). -// Note that in the presence of schema evolution, this may mean that -// fields the client does not know and has therefore not filled into -// the request will be reset to their default. If this is unwanted -// behavior, a specific service may require a client to always specify -// a field mask, producing an error if not. -// -// As with get operations, the location of the resource which -// describes the updated values in the request message depends on the -// operation kind. In any case, the effect of the field mask is -// required to be honored by the API. -// -// ## Considerations for HTTP REST -// -// The HTTP kind of an update operation which uses a field mask must -// be set to PATCH instead of PUT in order to satisfy HTTP semantics -// (PUT must only be used for full updates). -// -// # JSON Encoding of Field Masks -// -// In JSON, a field mask is encoded as a single string where paths are -// separated by a comma. Fields name in each path are converted -// to/from lower-camel naming conventions. -// -// As an example, consider the following message declarations: -// -// message Profile { -// User user = 1; -// Photo photo = 2; -// } -// message User { -// string display_name = 1; -// string address = 2; -// } -// -// In proto a field mask for `Profile` may look as such: -// -// mask { -// paths: "user.display_name" -// paths: "photo" -// } -// -// In JSON, the same mask is represented as below: -// -// { -// mask: "user.displayName,photo" -// } -// -// # Field Masks and Oneof Fields -// -// Field masks treat fields in oneofs just as regular fields. Consider the -// following message: -// -// message SampleMessage { -// oneof test_oneof { -// string name = 4; -// SubMessage sub_message = 9; -// } -// } -// -// The field mask can be: -// -// mask { -// paths: "name" -// } -// -// Or: -// -// mask { -// paths: "sub_message" -// } -// -// Note that oneof type names ("test_oneof" in this case) cannot be used in -// paths. -// -// ## Field Mask Verification -// -// The implementation of any API method which has a FieldMask type field in the -// request should verify the included field paths, and return an -// `INVALID_ARGUMENT` error if any path is unmappable. -message FieldMask { - // The set of field mask paths. - repeated string paths = 1; -} diff --git a/src/struct_pb/conformance/google/protobuf/source_context.proto b/src/struct_pb/conformance/google/protobuf/source_context.proto deleted file mode 100644 index 135f50fea..000000000 --- a/src/struct_pb/conformance/google/protobuf/source_context.proto +++ /dev/null @@ -1,48 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option java_package = "com.google.protobuf"; -option java_outer_classname = "SourceContextProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb"; - -// `SourceContext` represents information about the source of a -// protobuf element, like the file in which it is defined. -message SourceContext { - // The path-qualified name of the .proto file that contained the associated - // protobuf element. For example: `"google/protobuf/source_context.proto"`. - string file_name = 1; -} diff --git a/src/struct_pb/conformance/google/protobuf/struct.proto b/src/struct_pb/conformance/google/protobuf/struct.proto deleted file mode 100644 index c4ea6453e..000000000 --- a/src/struct_pb/conformance/google/protobuf/struct.proto +++ /dev/null @@ -1,95 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/structpb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "StructProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// `Struct` represents a structured data value, consisting of fields -// which map to dynamically typed values. In some languages, `Struct` -// might be supported by a native representation. For example, in -// scripting languages like JS a struct is represented as an -// object. The details of that representation are described together -// with the proto support for the language. -// -// The JSON representation for `Struct` is JSON object. -message Struct { - // Unordered map of dynamically typed values. - map fields = 1; -} - -// `Value` represents a dynamically typed value which can be either -// null, a number, a string, a boolean, a recursive struct value, or a -// list of values. A producer of value is expected to set one of these -// variants. Absence of any variant indicates an error. -// -// The JSON representation for `Value` is JSON value. -message Value { - // The kind of value. - oneof kind { - // Represents a null value. - NullValue null_value = 1; - // Represents a double value. - double number_value = 2; - // Represents a string value. - string string_value = 3; - // Represents a boolean value. - bool bool_value = 4; - // Represents a structured value. - Struct struct_value = 5; - // Represents a repeated `Value`. - ListValue list_value = 6; - } -} - -// `NullValue` is a singleton enumeration to represent the null value for the -// `Value` type union. -// -// The JSON representation for `NullValue` is JSON `null`. -enum NullValue { - // Null value. - NULL_VALUE = 0; -} - -// `ListValue` is a wrapper around a repeated field of values. -// -// The JSON representation for `ListValue` is JSON array. -message ListValue { - // Repeated field of dynamically typed values. - repeated Value values = 1; -} diff --git a/src/struct_pb/conformance/google/protobuf/test_messages_proto2.proto b/src/struct_pb/conformance/google/protobuf/test_messages_proto2.proto deleted file mode 100644 index bd0324eb7..000000000 --- a/src/struct_pb/conformance/google/protobuf/test_messages_proto2.proto +++ /dev/null @@ -1,303 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Test schema for proto2 messages. This test schema is used by: -// -// - conformance tests -// - -// LINT: ALLOW_GROUPS - -syntax = "proto2"; - -package protobuf_test_messages.proto2; - -option java_package = "com.google.protobuf_test_messages.proto2"; -option objc_class_prefix = "Proto2"; - -// This is the default, but we specify it here explicitly. -option optimize_for = SPEED; - -option cc_enable_arenas = true; - -// This proto includes every type of field in both singular and repeated -// forms. -// -// Also, crucially, all messages and enums in this file are eventually -// submessages of this message. So for example, a fuzz test of TestAllTypes -// could trigger bugs that occur in any message type in this file. We verify -// this stays true in a unit test. -message TestAllTypesProto2 { - message NestedMessage { - optional int32 a = 1; - optional TestAllTypesProto2 corecursive = 2; - } - - enum NestedEnum { - FOO = 0; - BAR = 1; - BAZ = 2; - NEG = -1; // Intentionally negative. - } - - // Singular - optional int32 optional_int32 = 1; - optional int64 optional_int64 = 2; - optional uint32 optional_uint32 = 3; - optional uint64 optional_uint64 = 4; - optional sint32 optional_sint32 = 5; - optional sint64 optional_sint64 = 6; - optional fixed32 optional_fixed32 = 7; - optional fixed64 optional_fixed64 = 8; - optional sfixed32 optional_sfixed32 = 9; - optional sfixed64 optional_sfixed64 = 10; - optional float optional_float = 11; - optional double optional_double = 12; - optional bool optional_bool = 13; - optional string optional_string = 14; - optional bytes optional_bytes = 15; - - optional NestedMessage optional_nested_message = 18; - optional ForeignMessageProto2 optional_foreign_message = 19; - - optional NestedEnum optional_nested_enum = 21; - optional ForeignEnumProto2 optional_foreign_enum = 22; - - optional string optional_string_piece = 24 [ctype = STRING_PIECE]; - optional string optional_cord = 25 [ctype = CORD]; - - optional TestAllTypesProto2 recursive_message = 27; - - // Repeated - repeated int32 repeated_int32 = 31; - repeated int64 repeated_int64 = 32; - repeated uint32 repeated_uint32 = 33; - repeated uint64 repeated_uint64 = 34; - repeated sint32 repeated_sint32 = 35; - repeated sint64 repeated_sint64 = 36; - repeated fixed32 repeated_fixed32 = 37; - repeated fixed64 repeated_fixed64 = 38; - repeated sfixed32 repeated_sfixed32 = 39; - repeated sfixed64 repeated_sfixed64 = 40; - repeated float repeated_float = 41; - repeated double repeated_double = 42; - repeated bool repeated_bool = 43; - repeated string repeated_string = 44; - repeated bytes repeated_bytes = 45; - - repeated NestedMessage repeated_nested_message = 48; - repeated ForeignMessageProto2 repeated_foreign_message = 49; - - repeated NestedEnum repeated_nested_enum = 51; - repeated ForeignEnumProto2 repeated_foreign_enum = 52; - - repeated string repeated_string_piece = 54 [ctype = STRING_PIECE]; - repeated string repeated_cord = 55 [ctype = CORD]; - - // Packed - repeated int32 packed_int32 = 75 [packed = true]; - repeated int64 packed_int64 = 76 [packed = true]; - repeated uint32 packed_uint32 = 77 [packed = true]; - repeated uint64 packed_uint64 = 78 [packed = true]; - repeated sint32 packed_sint32 = 79 [packed = true]; - repeated sint64 packed_sint64 = 80 [packed = true]; - repeated fixed32 packed_fixed32 = 81 [packed = true]; - repeated fixed64 packed_fixed64 = 82 [packed = true]; - repeated sfixed32 packed_sfixed32 = 83 [packed = true]; - repeated sfixed64 packed_sfixed64 = 84 [packed = true]; - repeated float packed_float = 85 [packed = true]; - repeated double packed_double = 86 [packed = true]; - repeated bool packed_bool = 87 [packed = true]; - repeated NestedEnum packed_nested_enum = 88 [packed = true]; - - // Unpacked - repeated int32 unpacked_int32 = 89 [packed = false]; - repeated int64 unpacked_int64 = 90 [packed = false]; - repeated uint32 unpacked_uint32 = 91 [packed = false]; - repeated uint64 unpacked_uint64 = 92 [packed = false]; - repeated sint32 unpacked_sint32 = 93 [packed = false]; - repeated sint64 unpacked_sint64 = 94 [packed = false]; - repeated fixed32 unpacked_fixed32 = 95 [packed = false]; - repeated fixed64 unpacked_fixed64 = 96 [packed = false]; - repeated sfixed32 unpacked_sfixed32 = 97 [packed = false]; - repeated sfixed64 unpacked_sfixed64 = 98 [packed = false]; - repeated float unpacked_float = 99 [packed = false]; - repeated double unpacked_double = 100 [packed = false]; - repeated bool unpacked_bool = 101 [packed = false]; - repeated NestedEnum unpacked_nested_enum = 102 [packed = false]; - - // Map - map map_int32_int32 = 56; - map map_int64_int64 = 57; - map map_uint32_uint32 = 58; - map map_uint64_uint64 = 59; - map map_sint32_sint32 = 60; - map map_sint64_sint64 = 61; - map map_fixed32_fixed32 = 62; - map map_fixed64_fixed64 = 63; - map map_sfixed32_sfixed32 = 64; - map map_sfixed64_sfixed64 = 65; - map map_int32_float = 66; - map map_int32_double = 67; - map map_bool_bool = 68; - map map_string_string = 69; - map map_string_bytes = 70; - map map_string_nested_message = 71; - map map_string_foreign_message = 72; - map map_string_nested_enum = 73; - map map_string_foreign_enum = 74; - - oneof oneof_field { - uint32 oneof_uint32 = 111; - NestedMessage oneof_nested_message = 112; - string oneof_string = 113; - bytes oneof_bytes = 114; - bool oneof_bool = 115; - uint64 oneof_uint64 = 116; - float oneof_float = 117; - double oneof_double = 118; - NestedEnum oneof_enum = 119; - } - - // extensions - extensions 120 to 200; - - // groups - optional group Data = 201 { - optional int32 group_int32 = 202; - optional uint32 group_uint32 = 203; - } - - // default values - optional int32 default_int32 = 241 [default = -123456789]; - optional int64 default_int64 = 242 [default = -9123456789123456789]; - optional uint32 default_uint32 = 243 [default = 2123456789]; - optional uint64 default_uint64 = 244 [default = 10123456789123456789]; - optional sint32 default_sint32 = 245 [default = -123456789]; - optional sint64 default_sint64 = 246 [default = -9123456789123456789]; - optional fixed32 default_fixed32 = 247 [default = 2123456789]; - optional fixed64 default_fixed64 = 248 [default = 10123456789123456789]; - optional sfixed32 default_sfixed32 = 249 [default = -123456789]; - optional sfixed64 default_sfixed64 = 250 [default = -9123456789123456789]; - optional float default_float = 251 [default = 9e9]; - optional double default_double = 252 [default = 7e22]; - optional bool default_bool = 253 [default = true]; - optional string default_string = 254 [default = "Rosebud"]; - optional bytes default_bytes = 255 [default = "joshua"]; - - // Test field-name-to-JSON-name convention. - // (protobuf says names can be any valid C/C++ identifier.) - optional int32 fieldname1 = 401; - optional int32 field_name2 = 402; - optional int32 _field_name3 = 403; - optional int32 field__name4_ = 404; - optional int32 field0name5 = 405; - optional int32 field_0_name6 = 406; - optional int32 fieldName7 = 407; - optional int32 FieldName8 = 408; - optional int32 field_Name9 = 409; - optional int32 Field_Name10 = 410; - optional int32 FIELD_NAME11 = 411; - optional int32 FIELD_name12 = 412; - optional int32 __field_name13 = 413; - optional int32 __Field_name14 = 414; - optional int32 field__name15 = 415; - optional int32 field__Name16 = 416; - optional int32 field_name17__ = 417; - optional int32 Field_name18__ = 418; - - // Reserved for unknown fields test. - reserved 1000 to 9999; - - // message_set test case. - message MessageSetCorrect { - option message_set_wire_format = true; - - extensions 4 to max; - } - - message MessageSetCorrectExtension1 { - extend MessageSetCorrect { - optional MessageSetCorrectExtension1 message_set_extension = 1547769; - } - optional string str = 25; - } - - message MessageSetCorrectExtension2 { - extend MessageSetCorrect { - optional MessageSetCorrectExtension2 message_set_extension = 4135312; - } - optional int32 i = 9; - } -} - -message ForeignMessageProto2 { - optional int32 c = 1; -} - -enum ForeignEnumProto2 { - FOREIGN_FOO = 0; - FOREIGN_BAR = 1; - FOREIGN_BAZ = 2; -} - -extend TestAllTypesProto2 { - optional int32 extension_int32 = 120; -} - -message UnknownToTestAllTypes { - optional int32 optional_int32 = 1001; - optional string optional_string = 1002; - optional ForeignMessageProto2 nested_message = 1003; - optional group OptionalGroup = 1004 { - optional int32 a = 1; - } - optional bool optional_bool = 1006; - repeated int32 repeated_int32 = 1011; -} - -message NullHypothesisProto2 {} - -message EnumOnlyProto2 { - enum Bool { - kFalse = 0; - kTrue = 1; - } -} - -message OneStringProto2 { - optional string data = 1; -} - -message ProtoWithKeywords { - optional int32 inline = 1; - // optional string concept = 2; - // repeated string requires = 3; -} diff --git a/src/struct_pb/conformance/google/protobuf/test_messages_proto3.proto b/src/struct_pb/conformance/google/protobuf/test_messages_proto3.proto deleted file mode 100644 index 1e1285eab..000000000 --- a/src/struct_pb/conformance/google/protobuf/test_messages_proto3.proto +++ /dev/null @@ -1,288 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Test schema for proto3 messages. This test schema is used by: -// -// - benchmarks -// - fuzz tests -// - conformance tests -// - -syntax = "proto3"; - -package protobuf_test_messages.proto3; - -option java_package = "com.google.protobuf_test_messages.proto3"; -option objc_class_prefix = "Proto3"; - -// This is the default, but we specify it here explicitly. -option optimize_for = SPEED; - -import "google/protobuf/any.proto"; -import "google/protobuf/duration.proto"; -import "google/protobuf/field_mask.proto"; -import "google/protobuf/struct.proto"; -import "google/protobuf/timestamp.proto"; -import "google/protobuf/wrappers.proto"; - -option cc_enable_arenas = true; - -// This proto includes every type of field in both singular and repeated -// forms. -// -// Also, crucially, all messages and enums in this file are eventually -// submessages of this message. So for example, a fuzz test of TestAllTypes -// could trigger bugs that occur in any message type in this file. We verify -// this stays true in a unit test. -message TestAllTypesProto3 { - message NestedMessage { - int32 a = 1; - TestAllTypesProto3 corecursive = 2; - } - - enum NestedEnum { - FOO = 0; - BAR = 1; - BAZ = 2; - NEG = -1; // Intentionally negative. - } - - enum AliasedEnum { - option allow_alias = true; - - ALIAS_FOO = 0; - ALIAS_BAR = 1; - ALIAS_BAZ = 2; - MOO = 2; - moo = 2; - bAz = 2; - } - - // Singular - int32 optional_int32 = 1; - int64 optional_int64 = 2; - uint32 optional_uint32 = 3; - uint64 optional_uint64 = 4; - sint32 optional_sint32 = 5; - sint64 optional_sint64 = 6; - fixed32 optional_fixed32 = 7; - fixed64 optional_fixed64 = 8; - sfixed32 optional_sfixed32 = 9; - sfixed64 optional_sfixed64 = 10; - float optional_float = 11; - double optional_double = 12; - bool optional_bool = 13; - string optional_string = 14; - bytes optional_bytes = 15; - - NestedMessage optional_nested_message = 18; - ForeignMessage optional_foreign_message = 19; - - NestedEnum optional_nested_enum = 21; - ForeignEnum optional_foreign_enum = 22; - AliasedEnum optional_aliased_enum = 23; - - string optional_string_piece = 24 [ctype = STRING_PIECE]; - string optional_cord = 25 [ctype = CORD]; - - TestAllTypesProto3 recursive_message = 27; - - // Repeated - repeated int32 repeated_int32 = 31; - repeated int64 repeated_int64 = 32; - repeated uint32 repeated_uint32 = 33; - repeated uint64 repeated_uint64 = 34; - repeated sint32 repeated_sint32 = 35; - repeated sint64 repeated_sint64 = 36; - repeated fixed32 repeated_fixed32 = 37; - repeated fixed64 repeated_fixed64 = 38; - repeated sfixed32 repeated_sfixed32 = 39; - repeated sfixed64 repeated_sfixed64 = 40; - repeated float repeated_float = 41; - repeated double repeated_double = 42; - repeated bool repeated_bool = 43; - repeated string repeated_string = 44; - repeated bytes repeated_bytes = 45; - - repeated NestedMessage repeated_nested_message = 48; - repeated ForeignMessage repeated_foreign_message = 49; - - repeated NestedEnum repeated_nested_enum = 51; - repeated ForeignEnum repeated_foreign_enum = 52; - - repeated string repeated_string_piece = 54 [ctype = STRING_PIECE]; - repeated string repeated_cord = 55 [ctype = CORD]; - - // Packed - repeated int32 packed_int32 = 75 [packed = true]; - repeated int64 packed_int64 = 76 [packed = true]; - repeated uint32 packed_uint32 = 77 [packed = true]; - repeated uint64 packed_uint64 = 78 [packed = true]; - repeated sint32 packed_sint32 = 79 [packed = true]; - repeated sint64 packed_sint64 = 80 [packed = true]; - repeated fixed32 packed_fixed32 = 81 [packed = true]; - repeated fixed64 packed_fixed64 = 82 [packed = true]; - repeated sfixed32 packed_sfixed32 = 83 [packed = true]; - repeated sfixed64 packed_sfixed64 = 84 [packed = true]; - repeated float packed_float = 85 [packed = true]; - repeated double packed_double = 86 [packed = true]; - repeated bool packed_bool = 87 [packed = true]; - repeated NestedEnum packed_nested_enum = 88 [packed = true]; - - // Unpacked - repeated int32 unpacked_int32 = 89 [packed = false]; - repeated int64 unpacked_int64 = 90 [packed = false]; - repeated uint32 unpacked_uint32 = 91 [packed = false]; - repeated uint64 unpacked_uint64 = 92 [packed = false]; - repeated sint32 unpacked_sint32 = 93 [packed = false]; - repeated sint64 unpacked_sint64 = 94 [packed = false]; - repeated fixed32 unpacked_fixed32 = 95 [packed = false]; - repeated fixed64 unpacked_fixed64 = 96 [packed = false]; - repeated sfixed32 unpacked_sfixed32 = 97 [packed = false]; - repeated sfixed64 unpacked_sfixed64 = 98 [packed = false]; - repeated float unpacked_float = 99 [packed = false]; - repeated double unpacked_double = 100 [packed = false]; - repeated bool unpacked_bool = 101 [packed = false]; - repeated NestedEnum unpacked_nested_enum = 102 [packed = false]; - - // Map - map map_int32_int32 = 56; - map map_int64_int64 = 57; - map map_uint32_uint32 = 58; - map map_uint64_uint64 = 59; - map map_sint32_sint32 = 60; - map map_sint64_sint64 = 61; - map map_fixed32_fixed32 = 62; - map map_fixed64_fixed64 = 63; - map map_sfixed32_sfixed32 = 64; - map map_sfixed64_sfixed64 = 65; - map map_int32_float = 66; - map map_int32_double = 67; - map map_bool_bool = 68; - map map_string_string = 69; - map map_string_bytes = 70; - map map_string_nested_message = 71; - map map_string_foreign_message = 72; - map map_string_nested_enum = 73; - map map_string_foreign_enum = 74; - - oneof oneof_field { - uint32 oneof_uint32 = 111; - NestedMessage oneof_nested_message = 112; - string oneof_string = 113; - bytes oneof_bytes = 114; - bool oneof_bool = 115; - uint64 oneof_uint64 = 116; - float oneof_float = 117; - double oneof_double = 118; - NestedEnum oneof_enum = 119; - google.protobuf.NullValue oneof_null_value = 120; - } - - // Well-known types - google.protobuf.BoolValue optional_bool_wrapper = 201; - google.protobuf.Int32Value optional_int32_wrapper = 202; - google.protobuf.Int64Value optional_int64_wrapper = 203; - google.protobuf.UInt32Value optional_uint32_wrapper = 204; - google.protobuf.UInt64Value optional_uint64_wrapper = 205; - google.protobuf.FloatValue optional_float_wrapper = 206; - google.protobuf.DoubleValue optional_double_wrapper = 207; - google.protobuf.StringValue optional_string_wrapper = 208; - google.protobuf.BytesValue optional_bytes_wrapper = 209; - - repeated google.protobuf.BoolValue repeated_bool_wrapper = 211; - repeated google.protobuf.Int32Value repeated_int32_wrapper = 212; - repeated google.protobuf.Int64Value repeated_int64_wrapper = 213; - repeated google.protobuf.UInt32Value repeated_uint32_wrapper = 214; - repeated google.protobuf.UInt64Value repeated_uint64_wrapper = 215; - repeated google.protobuf.FloatValue repeated_float_wrapper = 216; - repeated google.protobuf.DoubleValue repeated_double_wrapper = 217; - repeated google.protobuf.StringValue repeated_string_wrapper = 218; - repeated google.protobuf.BytesValue repeated_bytes_wrapper = 219; - - google.protobuf.Duration optional_duration = 301; - google.protobuf.Timestamp optional_timestamp = 302; - google.protobuf.FieldMask optional_field_mask = 303; - google.protobuf.Struct optional_struct = 304; - google.protobuf.Any optional_any = 305; - google.protobuf.Value optional_value = 306; - google.protobuf.NullValue optional_null_value = 307; - - repeated google.protobuf.Duration repeated_duration = 311; - repeated google.protobuf.Timestamp repeated_timestamp = 312; - repeated google.protobuf.FieldMask repeated_fieldmask = 313; - repeated google.protobuf.Struct repeated_struct = 324; - repeated google.protobuf.Any repeated_any = 315; - repeated google.protobuf.Value repeated_value = 316; - repeated google.protobuf.ListValue repeated_list_value = 317; - - // Test field-name-to-JSON-name convention. - // (protobuf says names can be any valid C/C++ identifier.) - int32 fieldname1 = 401; - int32 field_name2 = 402; - int32 _field_name3 = 403; - int32 field__name4_ = 404; - int32 field0name5 = 405; - int32 field_0_name6 = 406; - int32 fieldName7 = 407; - int32 FieldName8 = 408; - int32 field_Name9 = 409; - int32 Field_Name10 = 410; - int32 FIELD_NAME11 = 411; - int32 FIELD_name12 = 412; - int32 __field_name13 = 413; - int32 __Field_name14 = 414; - int32 field__name15 = 415; - int32 field__Name16 = 416; - int32 field_name17__ = 417; - int32 Field_name18__ = 418; - - // Reserved for testing unknown fields - reserved 501 to 510; -} - -message ForeignMessage { - int32 c = 1; -} - -enum ForeignEnum { - FOREIGN_FOO = 0; - FOREIGN_BAR = 1; - FOREIGN_BAZ = 2; -} - -message NullHypothesisProto3 {} - -message EnumOnlyProto3 { - enum Bool { - kFalse = 0; - kTrue = 1; - } -} diff --git a/src/struct_pb/conformance/google/protobuf/timestamp.proto b/src/struct_pb/conformance/google/protobuf/timestamp.proto deleted file mode 100644 index 2fb527c0c..000000000 --- a/src/struct_pb/conformance/google/protobuf/timestamp.proto +++ /dev/null @@ -1,144 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/timestamppb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "TimestampProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// A Timestamp represents a point in time independent of any time zone or local -// calendar, encoded as a count of seconds and fractions of seconds at -// nanosecond resolution. The count is relative to an epoch at UTC midnight on -// January 1, 1970, in the proleptic Gregorian calendar which extends the -// Gregorian calendar backwards to year one. -// -// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap -// second table is needed for interpretation, using a [24-hour linear -// smear](https://developers.google.com/time/smear). -// -// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By -// restricting to that range, we ensure that we can convert to and from [RFC -// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings. -// -// # Examples -// -// Example 1: Compute Timestamp from POSIX `time()`. -// -// Timestamp timestamp; -// timestamp.set_seconds(time(NULL)); -// timestamp.set_nanos(0); -// -// Example 2: Compute Timestamp from POSIX `gettimeofday()`. -// -// struct timeval tv; -// gettimeofday(&tv, NULL); -// -// Timestamp timestamp; -// timestamp.set_seconds(tv.tv_sec); -// timestamp.set_nanos(tv.tv_usec * 1000); -// -// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`. -// -// FILETIME ft; -// GetSystemTimeAsFileTime(&ft); -// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime; -// -// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z -// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z. -// Timestamp timestamp; -// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL)); -// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100)); -// -// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`. -// -// long millis = System.currentTimeMillis(); -// -// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000) -// .setNanos((int) ((millis % 1000) * 1000000)).build(); -// -// Example 5: Compute Timestamp from Java `Instant.now()`. -// -// Instant now = Instant.now(); -// -// Timestamp timestamp = -// Timestamp.newBuilder().setSeconds(now.getEpochSecond()) -// .setNanos(now.getNano()).build(); -// -// Example 6: Compute Timestamp from current time in Python. -// -// timestamp = Timestamp() -// timestamp.GetCurrentTime() -// -// # JSON Mapping -// -// In JSON format, the Timestamp type is encoded as a string in the -// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the -// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z" -// where {year} is always expressed using four digits while {month}, {day}, -// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional -// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution), -// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone -// is required. A proto3 JSON serializer should always use UTC (as indicated by -// "Z") when printing the Timestamp type and a proto3 JSON parser should be -// able to accept both UTC and other timezones (as indicated by an offset). -// -// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past -// 01:30 UTC on January 15, 2017. -// -// In JavaScript, one can convert a Date object to this format using the -// standard -// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString) -// method. In Python, a standard `datetime.datetime` object can be converted -// to this format using -// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with -// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use -// the Joda Time's [`ISODateTimeFormat.dateTime()`]( -// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D -// ) to obtain a formatter capable of generating timestamps in this format. -// -message Timestamp { - // Represents seconds of UTC time since Unix epoch - // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to - // 9999-12-31T23:59:59Z inclusive. - int64 seconds = 1; - - // Non-negative fractions of a second at nanosecond resolution. Negative - // second values with fractions must still have non-negative nanos values - // that count forward in time. Must be from 0 to 999,999,999 - // inclusive. - int32 nanos = 2; -} diff --git a/src/struct_pb/conformance/google/protobuf/type.proto b/src/struct_pb/conformance/google/protobuf/type.proto deleted file mode 100644 index fd25a4193..000000000 --- a/src/struct_pb/conformance/google/protobuf/type.proto +++ /dev/null @@ -1,187 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -syntax = "proto3"; - -package google.protobuf; - -import "google/protobuf/any.proto"; -import "google/protobuf/source_context.proto"; - -option cc_enable_arenas = true; -option java_package = "com.google.protobuf"; -option java_outer_classname = "TypeProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; -option go_package = "google.golang.org/protobuf/types/known/typepb"; - -// A protocol buffer message type. -message Type { - // The fully qualified message name. - string name = 1; - // The list of fields. - repeated Field fields = 2; - // The list of types appearing in `oneof` definitions in this type. - repeated string oneofs = 3; - // The protocol buffer options. - repeated Option options = 4; - // The source context. - SourceContext source_context = 5; - // The source syntax. - Syntax syntax = 6; -} - -// A single field of a message type. -message Field { - // Basic field types. - enum Kind { - // Field type unknown. - TYPE_UNKNOWN = 0; - // Field type double. - TYPE_DOUBLE = 1; - // Field type float. - TYPE_FLOAT = 2; - // Field type int64. - TYPE_INT64 = 3; - // Field type uint64. - TYPE_UINT64 = 4; - // Field type int32. - TYPE_INT32 = 5; - // Field type fixed64. - TYPE_FIXED64 = 6; - // Field type fixed32. - TYPE_FIXED32 = 7; - // Field type bool. - TYPE_BOOL = 8; - // Field type string. - TYPE_STRING = 9; - // Field type group. Proto2 syntax only, and deprecated. - TYPE_GROUP = 10; - // Field type message. - TYPE_MESSAGE = 11; - // Field type bytes. - TYPE_BYTES = 12; - // Field type uint32. - TYPE_UINT32 = 13; - // Field type enum. - TYPE_ENUM = 14; - // Field type sfixed32. - TYPE_SFIXED32 = 15; - // Field type sfixed64. - TYPE_SFIXED64 = 16; - // Field type sint32. - TYPE_SINT32 = 17; - // Field type sint64. - TYPE_SINT64 = 18; - } - - // Whether a field is optional, required, or repeated. - enum Cardinality { - // For fields with unknown cardinality. - CARDINALITY_UNKNOWN = 0; - // For optional fields. - CARDINALITY_OPTIONAL = 1; - // For required fields. Proto2 syntax only. - CARDINALITY_REQUIRED = 2; - // For repeated fields. - CARDINALITY_REPEATED = 3; - } - - // The field type. - Kind kind = 1; - // The field cardinality. - Cardinality cardinality = 2; - // The field number. - int32 number = 3; - // The field name. - string name = 4; - // The field type URL, without the scheme, for message or enumeration - // types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`. - string type_url = 6; - // The index of the field type in `Type.oneofs`, for message or enumeration - // types. The first type has index 1; zero means the type is not in the list. - int32 oneof_index = 7; - // Whether to use alternative packed wire representation. - bool packed = 8; - // The protocol buffer options. - repeated Option options = 9; - // The field JSON name. - string json_name = 10; - // The string value of the default value of this field. Proto2 syntax only. - string default_value = 11; -} - -// Enum type definition. -message Enum { - // Enum type name. - string name = 1; - // Enum value definitions. - repeated EnumValue enumvalue = 2; - // Protocol buffer options. - repeated Option options = 3; - // The source context. - SourceContext source_context = 4; - // The source syntax. - Syntax syntax = 5; -} - -// Enum value definition. -message EnumValue { - // Enum value name. - string name = 1; - // Enum value number. - int32 number = 2; - // Protocol buffer options. - repeated Option options = 3; -} - -// A protocol buffer option, which can be attached to a message, field, -// enumeration, etc. -message Option { - // The option's name. For protobuf built-in options (options defined in - // descriptor.proto), this is the short name. For example, `"map_entry"`. - // For custom options, it should be the fully-qualified name. For example, - // `"google.api.http"`. - string name = 1; - // The option's value packed in an Any message. If the value is a primitive, - // the corresponding wrapper type defined in google/protobuf/wrappers.proto - // should be used. If the value is an enum, it should be stored as an int32 - // value using the google.protobuf.Int32Value type. - Any value = 2; -} - -// The syntax in which a protocol buffer element is defined. -enum Syntax { - // Syntax `proto2`. - SYNTAX_PROTO2 = 0; - // Syntax `proto3`. - SYNTAX_PROTO3 = 1; -} diff --git a/src/struct_pb/conformance/google/protobuf/wrappers.proto b/src/struct_pb/conformance/google/protobuf/wrappers.proto deleted file mode 100644 index 1959fa55a..000000000 --- a/src/struct_pb/conformance/google/protobuf/wrappers.proto +++ /dev/null @@ -1,123 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -// -// Wrappers for primitive (non-message) types. These types are useful -// for embedding primitives in the `google.protobuf.Any` type and for places -// where we need to distinguish between the absence of a primitive -// typed field and its default value. -// -// These wrappers have no meaningful use within repeated fields as they lack -// the ability to detect presence on individual elements. -// These wrappers have no meaningful use within a map or a oneof since -// individual entries of a map or fields of a oneof can already detect presence. - -syntax = "proto3"; - -package google.protobuf; - -option cc_enable_arenas = true; -option go_package = "google.golang.org/protobuf/types/known/wrapperspb"; -option java_package = "com.google.protobuf"; -option java_outer_classname = "WrappersProto"; -option java_multiple_files = true; -option objc_class_prefix = "GPB"; -option csharp_namespace = "Google.Protobuf.WellKnownTypes"; - -// Wrapper message for `double`. -// -// The JSON representation for `DoubleValue` is JSON number. -message DoubleValue { - // The double value. - double value = 1; -} - -// Wrapper message for `float`. -// -// The JSON representation for `FloatValue` is JSON number. -message FloatValue { - // The float value. - float value = 1; -} - -// Wrapper message for `int64`. -// -// The JSON representation for `Int64Value` is JSON string. -message Int64Value { - // The int64 value. - int64 value = 1; -} - -// Wrapper message for `uint64`. -// -// The JSON representation for `UInt64Value` is JSON string. -message UInt64Value { - // The uint64 value. - uint64 value = 1; -} - -// Wrapper message for `int32`. -// -// The JSON representation for `Int32Value` is JSON number. -message Int32Value { - // The int32 value. - int32 value = 1; -} - -// Wrapper message for `uint32`. -// -// The JSON representation for `UInt32Value` is JSON number. -message UInt32Value { - // The uint32 value. - uint32 value = 1; -} - -// Wrapper message for `bool`. -// -// The JSON representation for `BoolValue` is JSON `true` and `false`. -message BoolValue { - // The bool value. - bool value = 1; -} - -// Wrapper message for `string`. -// -// The JSON representation for `StringValue` is JSON string. -message StringValue { - // The string value. - string value = 1; -} - -// Wrapper message for `bytes`. -// -// The JSON representation for `BytesValue` is JSON string. -message BytesValue { - // The bytes value. - bytes value = 1; -} diff --git a/src/struct_pb/examples/CMakeLists.txt b/src/struct_pb/examples/CMakeLists.txt deleted file mode 100644 index 3c0d658fa..000000000 --- a/src/struct_pb/examples/CMakeLists.txt +++ /dev/null @@ -1,27 +0,0 @@ -if("${yaLanTingLibs_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") - # If this is a subproject in ylt - set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/examples) -else() - # else find installed yalantinglibs - cmake_minimum_required(VERSION 3.15) - project(coro_rpc_examples) - if(NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE "Release") - endif() - set(CMAKE_CXX_STANDARD 20) - set(CMAKE_CXX_STANDARD_REQUIRED ON) - set(CMAKE_INCLUDE_CURRENT_DIR ON) - # if you have install ylt - find_package(yalantinglibs REQUIRED) - link_libraries(yalantinglibs::yalantinglibs) - # else - # include_directories(include) - # include_directories(include/ylt/thirdparty) - include(struct_pb_helper.cmake) -endif() - -find_package(Protobuf QUIET) -if (Protobuf_FOUND) - add_executable(struct_pb_tutorial tutorial.cpp) - target_protos_struct_pb(struct_pb_tutorial PRIVATE addressbook.proto) -endif() diff --git a/src/struct_pb/examples/addressbook.proto b/src/struct_pb/examples/addressbook.proto deleted file mode 100644 index 8c33fe2af..000000000 --- a/src/struct_pb/examples/addressbook.proto +++ /dev/null @@ -1,26 +0,0 @@ -syntax = "proto3"; - -package tutorial; - -message Person { - string name = 1; - int32 id = 2; - string email = 3; - - enum PhoneType { - MOBILE = 0; - HOME = 1; - WORK = 2; - } - - message PhoneNumber { - string number = 1; - PhoneType type = 2; - } - - repeated PhoneNumber phones = 4; -} - -message AddressBook { - repeated Person people = 1; -} diff --git a/src/struct_pb/examples/demo.proto b/src/struct_pb/examples/demo.proto deleted file mode 100644 index 49fdc6a6e..000000000 --- a/src/struct_pb/examples/demo.proto +++ /dev/null @@ -1,50 +0,0 @@ -syntax = "proto3"; - -message SearchRequest { - string query = 1; - int32 page_number = 2; - int32 result_per_page = 3; -} - -enum Corpus { - CORPUS_UNSPECIFIED = 0; - CORPUS_UNIVERSAL = 1; - CORPUS_WEB = 2; - CORPUS_IMAGES = 3; - CORPUS_LOCAL = 4; - CORPUS_NEWS = 5; - CORPUS_PRODUCTS = 6; - CORPUS_VIDEO = 7; -} - -message Outer { // Level 0 - message MiddleAA { // Level 1 - message Inner { // Level 2 - int64 ival = 1; - bool booly = 2; - } - } - message MiddleBB { // Level 1 - message Inner { // Level 2 - int32 ival = 1; - bool booly = 2; - } - } -} - -message SampleMessage { - oneof test_oneof { - string name = 4; - SubMessage sub_message = 9; - } -} -message SubMessage { - int32 val = 1; -} - -message SampleMap { - map projects = 3; -} -message Project { - string name = 1; -} \ No newline at end of file diff --git a/src/struct_pb/examples/tutorial.cpp b/src/struct_pb/examples/tutorial.cpp deleted file mode 100644 index ddf310ce5..000000000 --- a/src/struct_pb/examples/tutorial.cpp +++ /dev/null @@ -1,104 +0,0 @@ -#include -#include -#include - -#include "addressbook.struct_pb.h" -void prompt_for_address(tutorial::Person& person) { - std::cout << "==================================" << std::endl; - std::cout << " Add People " << std::endl; - std::cout << "==================================" << std::endl; - std::cout << "Enter person ID number: "; - std::cin >> person.id; - std::cin.ignore(256, '\n'); - std::cout << "Enter name: "; - std::getline(std::cin, person.name); - std::cout << "Enter email address (blank for none): "; - std::getline(std::cin, person.email); - while (true) { - std::cout << "Enter a phone number (or leave blank to finish): "; - tutorial::Person::PhoneNumber phone_number; - std::getline(std::cin, phone_number.number); - if (phone_number.number.empty()) { - break; - } - std::cout << "Is this a mobile, home, or work phone? "; - std::string type; - std::getline(std::cin, type); - if (type == "mobile") { - phone_number.type = tutorial::Person::PhoneType::MOBILE; - } - else if (type == "home") { - phone_number.type = tutorial::Person::PhoneType::HOME; - } - else if (type == "work") { - phone_number.type = tutorial::Person::PhoneType::WORK; - } - else { - std::cout << "Unknown phone type: Using default." << std::endl; - } - person.phones.push_back(phone_number); - } -} -void list_people(const tutorial::AddressBook& address_book) { - std::cout << "==================================" << std::endl; - std::cout << " List People " << std::endl; - std::cout << "==================================" << std::endl; - for (const auto& person : address_book.people) { - std::cout << " Person ID: " << person.id << std::endl; - std::cout << " Name: " << person.name << std::endl; - if (!person.email.empty()) { - std::cout << "E-mail address: " << person.email << std::endl; - } - for (const auto& phone : person.phones) { - switch (phone.type) { - case tutorial::Person::PhoneType::MOBILE: - std::cout << "Mobile phone #: "; - break; - case tutorial::Person::PhoneType::HOME: - std::cout << " Home phone #: "; - break; - case tutorial::Person::PhoneType::WORK: - std::cout << " Work phone #: "; - break; - } - std::cout << phone.number << std::endl; - } - } -} -int main(int argc, char* argv[]) { - if (argc != 2) { - std::cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << std::endl; - return -1; - } - tutorial::AddressBook address_book; - std::fstream input(argv[1], std::ios::in | std::ios::binary); - if (!input) { - std::cout << argv[1] << ": File not found. Creating a new file." - << std::endl; - } - else { - input.seekg(0, input.end); - int length = input.tellg(); - input.seekg(0, input.beg); - std::string buffer; - buffer.resize(length); - input.read(buffer.data(), buffer.size()); - input.close(); - bool ok = struct_pb::deserialize_to(address_book, buffer); - if (!ok) { - std::cerr << "Failed to parse address book." << std::endl; - return -1; - } - } - list_people(address_book); - address_book.people.emplace_back(); - prompt_for_address(address_book.people.back()); - std::fstream output(argv[1], - std::ios::out | std::ios::trunc | std::ios::binary); - std::string buffer = struct_pb::serialize(address_book); - output.write(buffer.data(), buffer.size()); - output.close(); - list_people(address_book); - std::cout << "Done!!!" << std::endl; - return 0; -} \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/CMakeLists.txt b/src/struct_pb/protoc-plugin/CMakeLists.txt deleted file mode 100644 index 368d25d33..000000000 --- a/src/struct_pb/protoc-plugin/CMakeLists.txt +++ /dev/null @@ -1,18 +0,0 @@ -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/bin) -find_package(Protobuf QUIET) -if (Protobuf_FOUND) - file(GLOB SRCS "*.cpp" "*.h") - add_executable(protoc-gen-struct_pb ${SRCS}) - target_link_libraries(protoc-gen-struct_pb PUBLIC protobuf::libprotoc protobuf::libprotobuf) - install( - TARGETS protoc-gen-struct_pb - LIBRARY DESTINATION lib - ARCHIVE DESTINATION lib - RUNTIME DESTINATION bin - ) -else () - message(STATUS "struct_pb is skipped. To build struct_pb protoc plugin, you must install libprotoc first\n" - - "see https://alibaba.github.io/yalantinglibs/en/struct_pb/struct_pb_generating_your_struct.html" - ) -endif () diff --git a/src/struct_pb/protoc-plugin/EnumFieldGenerator.cpp b/src/struct_pb/protoc-plugin/EnumFieldGenerator.cpp deleted file mode 100644 index 333d86db7..000000000 --- a/src/struct_pb/protoc-plugin/EnumFieldGenerator.cpp +++ /dev/null @@ -1,328 +0,0 @@ -#include "EnumFieldGenerator.h" - -#include "helpers.hpp" -namespace struct_pb { -namespace compiler { -EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor *descriptor, - const Options &options) - : FieldGenerator(descriptor, options) {} -std::string EnumFieldGenerator::cpp_type_name() const { - auto name = qualified_enum_name(d_->enum_type(), options_); - if (is_optional()) { - return "std::optional<" + name + ">"; - } - return name; -} -void EnumFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (is_optional()) { - format("if ($1$.has_value()) {\n", value); - format.indent(); - format("total += $1$ + ", calculate_tag_size(d_)); - generate_calculate_size_only(p, value + ".value()"); - format(";\n"); - format.outdent(); - format("}\n"); - } - else { - if (can_ignore_default_value) { - p->Print( - { - {"tag_sz", calculate_tag_size(d_)}, - {"value", value}, - {"default_value", default_value()}, - }, - R"( -if ($value$ != $default_value$) { - total += $tag_sz$ + )"); - generate_calculate_size_only(p, value); - p->Print(R"(; -} -)"); - } - else { - p->Print( - { - {"tag_sz", calculate_tag_size(d_)}, - }, - R"( -total += $tag_sz$ + )"); - generate_calculate_size_only(p, value); - p->Print(R"(; -} -)"); - } - } -} -void EnumFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - // auto v = p->WithVars({{"tag", calculate_tag(d_)}, {"value", value}}); - if (is_optional()) { - p->Print({{"tag", calculate_tag_str(d_)}, {"value", value}}, R"( -if ($value$.has_value()) { -)"); - generate_serialization_only(p, value + ".value()"); - p->Print(R"( -} -)"); - } - else { - if (can_ignore_default_value) { - p->Print({{"tag", calculate_tag_str(d_)}, - {"value", value}, - {"default_value", default_value()}}, - R"( -if ($value$ != $default_value$) { -)"); - generate_serialization_only(p, value); - p->Print(R"( -} -)"); - } - else { - generate_serialization_only(p, value); - } - } -} -void EnumFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"tag", calculate_tag_str(d_)}, {"value", value}}, R"( -serialize_varint(data, pos, size, $tag$); -serialize_varint(data, pos, size, static_cast($value$)); -)"); -} -void EnumFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print( - { - {"tag", calculate_tag_str(d_)}, - {"value", value}, - }, - R"( -case $tag$: { -)"); - generate_deserialization_only(p, value); - p->Print(R"( - break; -} -)"); -} -void EnumFieldGenerator::generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &output, - const std::string &max_size) const { - auto enum_name = qualified_enum_name(d_->enum_type(), options_); - p->Print( - {{"enum_name", enum_name}, {"output", output}, {"max_size", max_size}}, - R"( -uint64_t enum_val_tmp{}; -ok = deserialize_varint(data, pos, $max_size$, enum_val_tmp); -if (!ok) { - return false; -} -$output$ = static_cast<$enum_name$>(enum_val_tmp); -)"); -} -RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : FieldGenerator(descriptor, options) {} -std::string RepeatedEnumFieldGenerator::cpp_type_name() const { - return "std::vector<" + qualified_enum_name(d_->enum_type(), options_) + ">"; -} - -void RepeatedEnumFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - if (can_ignore_default_value) { - if (is_packed()) { - p->Print({{"value", value}}, R"( -if (!$value$.empty()) { // packed -)"); - generate_calculate_size_only(p, value, "sz"); - p->Print( - { - {"tag_sz", calculate_tag_size(d_)}, - }, - R"( -total += $tag_sz$ + calculate_varint_size(sz) + sz; -} -)"); - } - else { - p->Print({{"value", value}}, R"( -if (!$value$.empty()) { // unpacked -)"); - generate_calculate_size_only(p, value, "sz"); - p->Print( - { - {"tag_sz", calculate_tag_size(d_)}, - }, - R"( - total += sz; -} -)"); - } - } - else { - if (is_packed()) { - generate_calculate_size_only(p, value, "sz"); - p->Print( - { - {"tag_sz", calculate_tag_size(d_)}, - }, - R"( -// packed -total += $tag_sz$ + calculate_varint_size(sz) + sz; -)"); - } - else { - generate_calculate_size_only(p, value, "sz"); - p->Print( - R"( -// unpacked -total += sz; -)"); - } - } -} -void RepeatedEnumFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value, - const std::string &output) const { - if (is_packed()) { - p->Print({{"value", value}, - {"output", output}, - {"tag_sz", calculate_tag_size(d_)}}, - R"( -std::size_t $output$ = 0; -for(const auto& v: $value$) { - $output$ += calculate_varint_size(static_cast(v)); -} -)"); - } - else { - p->Print({{"value", value}, - {"output", output}, - {"tag_sz", calculate_tag_size(d_, true)}}, - R"( -std::size_t $output$ = 0; -for(const auto& v: $value$) { - $output$ += $tag_sz$; - $output$ += calculate_varint_size(static_cast(v)); -} -)"); - } -} - -void RepeatedEnumFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - if (can_ignore_default_value) { - p->Print({{"value", value}}, R"( -if (!$value$.empty()) { -)"); - generate_serialization_only(p, value); - p->Print("}\n"); - } - else { - generate_serialization_only(p, value); - } -} -void RepeatedEnumFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - if (is_packed()) { - p->Print({{"tag", std::to_string(calculate_tag(d_))}}, R"( -serialize_varint(data, pos, size, $tag$); -)"); - generate_calculate_size_only(p, value, "sz"); - p->Print({{"value", value}}, - R"( -serialize_varint(data, pos, size, sz); -for(const auto& v: $value$) { - serialize_varint(data, pos, size, static_cast(v)); -} -)"); - } - else { - p->Print( - {{"tag", std::to_string(calculate_tag(d_, true))}, {"value", value}}, - R"( -for(const auto& v: $value$) { - serialize_varint(data, pos, size, $tag$); - serialize_varint(data, pos, size, static_cast(v)); -} -)"); - } -} -void RepeatedEnumFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - // generate packed - p->Print({{"tag", packed_tag()}, - {"value", value}, - {"enum_name", qualified_enum_name(d_->enum_type(), options_)} - - }, - R"( -case $tag$: { - uint64_t sz = 0; - ok = deserialize_varint(data, pos, size, sz); - if (!ok) { - return false; - } - std::size_t cur_max_sz = pos + sz; - if (cur_max_sz > size) { - return false; - } - while (pos < cur_max_sz) { - uint64_t enum_val_tmp{}; - ok = deserialize_varint(data, pos, cur_max_sz, enum_val_tmp); - if (!ok) { - return false; - } - $value$.push_back(static_cast<$enum_name$>(enum_val_tmp)); - } - break; -} -)"); - p->Print({{"tag", unpacked_tag()}, - {"value", value}, - {"enum_name", qualified_enum_name(d_->enum_type(), options_)}}, - R"( -case $tag$: { - uint64_t enum_val_tmp{}; - ok = deserialize_varint(data, pos, size, enum_val_tmp); - if (!ok) { - return false; - } - $value$.push_back(static_cast<$enum_name$>(enum_val_tmp)); - break; -} -)"); -} -bool RepeatedEnumFieldGenerator::is_packed() const { - return d_->is_packable() && d_->is_packed(); -} -std::string RepeatedEnumFieldGenerator::packed_tag() const { - uint32_t number = d_->number(); - uint32_t wire_type = 2; - auto tag = number << 3 | wire_type; - return std::to_string(tag); -} -std::string RepeatedEnumFieldGenerator::unpacked_tag() const { - uint32_t number = d_->number(); - uint32_t wire_type = 0; - auto tag = number << 3 | wire_type; - return std::to_string(tag); -} -std::string EnumFieldGenerator::default_value() const { - return qualified_enum_name(d_->enum_type(), options_) + - "::" + d_->default_value_enum()->name(); -} -void EnumFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"value", value}}, - "calculate_varint_size(static_cast($value$))"); -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/EnumFieldGenerator.h b/src/struct_pb/protoc-plugin/EnumFieldGenerator.h deleted file mode 100644 index beb60e9c8..000000000 --- a/src/struct_pb/protoc-plugin/EnumFieldGenerator.h +++ /dev/null @@ -1,56 +0,0 @@ -#pragma once -#include "FieldGenerator.h" - -namespace struct_pb { -namespace compiler { - -class EnumFieldGenerator : public FieldGenerator { - public: - EnumFieldGenerator(const FieldDescriptor *descriptor, const Options &options); - std::string cpp_type_name() const override; - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - void generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &output, - const std::string &max_size = "size") const; - - private: - std::string default_value() const; -}; -class RepeatedEnumFieldGenerator : public FieldGenerator { - public: - RepeatedEnumFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - - std::string cpp_type_name() const override; - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value, - const std::string &output) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - - private: - bool is_packed() const; - std::string packed_tag() const; - std::string unpacked_tag() const; -}; -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/EnumGenerator.cpp b/src/struct_pb/protoc-plugin/EnumGenerator.cpp deleted file mode 100644 index a67c0aa8a..000000000 --- a/src/struct_pb/protoc-plugin/EnumGenerator.cpp +++ /dev/null @@ -1,37 +0,0 @@ -#include "EnumGenerator.h" - -#include "helpers.hpp" -namespace struct_pb { -namespace compiler { -void EnumGenerator::generate(google::protobuf::io::Printer *p) { - std::string enum_name = resolve_keyword(d_->name()); - p->Print({{"enum_name", enum_name}}, R"( -enum class $enum_name$ { -)"); - for (int j = 0; j < d_->value_count(); ++j) { - auto v = d_->value(j); - p->Print({{"name", resolve_keyword(v->name())}, - {"value", std::to_string(v->number())}}, - R"( -$name$ = $value$, -)"); - } - p->Print( - R"( -}; -)"); -} -void EnumGenerator::generate_definition(google::protobuf::io::Printer *p) { - Formatter format(p); - format("enum class $1$: int {\n", resolve_keyword(d_->name())); - format.indent(); - for (int i = 0; i < d_->value_count(); ++i) { - auto value = resolve_keyword(d_->value(i)->name()); - auto number = d_->value(i)->number(); - format("$1$ = $2$,\n", value, number); - } - format.outdent(); - format("};\n"); -} -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/EnumGenerator.h b/src/struct_pb/protoc-plugin/EnumGenerator.h deleted file mode 100644 index b39d80501..000000000 --- a/src/struct_pb/protoc-plugin/EnumGenerator.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once -#include -#include - -#include "GeneratorBase.h" -#include "google/protobuf/io/printer.h" -namespace struct_pb { -namespace compiler { -class EnumGenerator : public GeneratorBase { - public: - EnumGenerator(const google::protobuf::EnumDescriptor *d, Options options) - : GeneratorBase(options), d_(d) {} - void generate(google::protobuf::io::Printer *p); - void generate_definition(google::protobuf::io::Printer *p); - - private: - const google::protobuf::EnumDescriptor *d_; -}; -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/FieldGenerator.cpp b/src/struct_pb/protoc-plugin/FieldGenerator.cpp deleted file mode 100644 index 4965e5e7e..000000000 --- a/src/struct_pb/protoc-plugin/FieldGenerator.cpp +++ /dev/null @@ -1,557 +0,0 @@ -#include "FieldGenerator.h" - -#include "EnumFieldGenerator.h" -#include "MapFieldGenerator.h" -#include "MessageFieldGenerator.h" -#include "OneofFieldGenerator.h" -#include "PrimitiveFieldGenerator.h" -#include "StringFieldGenerator.h" -#include "google/protobuf/io/printer.h" -#include "helpers.hpp" - -using namespace google::protobuf; -namespace struct_pb { -namespace compiler { - -bool is_varint(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_BOOL: - case FieldDescriptor::TYPE_ENUM: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_SINT64: - return true; - default: - return false; - } -} -bool is_sint(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_SINT64: - return true; - default: - return false; - } -} -bool is_sint32(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_SINT32: - return true; - default: - return false; - } -} -bool is_enum(const FieldDescriptor *f) { - return f->type() == FieldDescriptor::TYPE_ENUM; -} -bool is_bool(const FieldDescriptor *f) { - return f->type() == FieldDescriptor::TYPE_BOOL; -} -bool is_i64(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_SFIXED64: - case FieldDescriptor::TYPE_DOUBLE: - return true; - default: - return false; - } -} -bool is_i32(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_SFIXED32: - case FieldDescriptor::TYPE_FLOAT: - return true; - default: - return false; - } -} -bool is_string(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_STRING: - case FieldDescriptor::TYPE_BYTES: - return true; - default: - return false; - } -} -bool is_message(const FieldDescriptor *f) { - return f->type() == FieldDescriptor::TYPE_MESSAGE; -} - -bool is_group(const FieldDescriptor *f) { - return f->type() == FieldDescriptor::TYPE_GROUP; -} - -bool is_number(const FieldDescriptor *f) { - switch (f->type()) { - case FieldDescriptor::TYPE_DOUBLE: - case FieldDescriptor::TYPE_FLOAT: - case FieldDescriptor::TYPE_INT64: - case FieldDescriptor::TYPE_UINT64: - case FieldDescriptor::TYPE_INT32: - case FieldDescriptor::TYPE_FIXED64: - case FieldDescriptor::TYPE_FIXED32: - case FieldDescriptor::TYPE_BOOL: - case FieldDescriptor::TYPE_UINT32: - case FieldDescriptor::TYPE_ENUM: - case FieldDescriptor::TYPE_SFIXED32: - case FieldDescriptor::TYPE_SFIXED64: - case FieldDescriptor::TYPE_SINT32: - case FieldDescriptor::TYPE_SINT64: - return true; - default: - return false; - } -} - -uint32_t calculate_tag(const FieldDescriptor *f, bool ignore_repeated) { - uint32_t number = f->number(); - uint32_t wire_type; - if (f->is_repeated() && !ignore_repeated) { - wire_type = 2; - } - else if (is_varint(f)) { - wire_type = 0; - } - else if (is_i64(f)) { - wire_type = 1; - } - else if (is_i32(f)) { - wire_type = 5; - } - else { - wire_type = 2; - } - return (number << 3) | wire_type; -} - -std::string calculate_tag_str(const FieldDescriptor *f, bool ignore_repeated) { - return std::to_string(calculate_tag(f, ignore_repeated)); -} - -std::size_t calculate_varint_size(uint64_t t) { - std::size_t ret = 0; - do { - ret++; - t >>= 7; - } while (t != 0); - return ret; -} - -std::string calculate_tag_size(const FieldDescriptor *f, bool ignore_repeated) { - auto tag = calculate_tag(f, ignore_repeated); - auto tag_size = calculate_varint_size(tag); - return std::to_string(tag_size); -} - -std::string get_comment(const FieldDescriptor *d_) { - std::string comment; - if (d_->has_optional_keyword()) { - comment += "optional "; - } - if (d_->is_repeated()) { - comment += "repeated "; - } - if (is_message(d_)) { - comment += class_name(d_->message_type()); - } - else { - comment += d_->type_name(); - } - comment += " "; - comment += d_->name(); - comment += " = "; - comment += std::to_string(d_->number()); - comment += ", tag = "; - comment += std::to_string(calculate_tag(d_)); - return comment; -} - -void FieldGenerator::generate_definition( - google::protobuf::io::Printer *p) const { - p->Print( - { - {"type", cpp_type_name()}, - {"name", name()}, - {"pb_type", pb_type_name()}, - {"number", std::to_string(d_->number())}, - }, - R"($type$ $name$; // $pb_type$, field number = $number$ -)"); -} - -std::string FieldGenerator::get_type_name() const { - switch (d_->type()) { - case google::protobuf::FieldDescriptor::TYPE_DOUBLE: - return "double"; - case google::protobuf::FieldDescriptor::TYPE_FLOAT: - return "float"; - case google::protobuf::FieldDescriptor::TYPE_INT64: - case google::protobuf::FieldDescriptor::TYPE_SFIXED64: - case google::protobuf::FieldDescriptor::TYPE_SINT64: - return "int64_t"; - case google::protobuf::FieldDescriptor::TYPE_UINT64: - case google::protobuf::FieldDescriptor::TYPE_FIXED64: - return "uint64_t"; - case google::protobuf::FieldDescriptor::TYPE_UINT32: - case google::protobuf::FieldDescriptor::TYPE_FIXED32: - return "uint32_t"; - case google::protobuf::FieldDescriptor::TYPE_INT32: - case google::protobuf::FieldDescriptor::TYPE_SFIXED32: - case google::protobuf::FieldDescriptor::TYPE_SINT32: - return "int32_t"; - case google::protobuf::FieldDescriptor::TYPE_BOOL: - return "bool"; - case google::protobuf::FieldDescriptor::TYPE_STRING: - case google::protobuf::FieldDescriptor::TYPE_BYTES: - return "std::string"; - case google::protobuf::FieldDescriptor::TYPE_MESSAGE: { - auto m = d_->message_type(); - if (d_->is_map()) { - auto key = m->field(0); - auto value = m->field(1); - std::string type_name = "std::map<"; - type_name += FieldGenerator(key, options_).get_type_name(); - type_name += ", "; - type_name += FieldGenerator(value, options_).get_type_name(); - type_name += ">"; - return type_name; - } - else if (d_->is_repeated()) { - if (is_message(d_)) { - return qualified_class_name(d_->message_type(), options_); - } - else { - return m->name(); - } - } - else { - auto p = d_->containing_type(); - if (is_map_entry(p)) { - return m->name(); - } - else { - return "std::unique_ptr<" + - qualified_class_name(d_->message_type(), options_) + ">"; - } - } - } - case google::protobuf::FieldDescriptor::TYPE_ENUM: - return d_->enum_type()->name(); - case google::protobuf::FieldDescriptor::TYPE_GROUP: - // workaround for group - return "std::string"; - default: { - return "not support now"; - } - } -} - -void FieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - // auto name = value.empty() ? "t." + this->name() : value; - // auto tag = calculate_tag(d_); - // auto v = - // p->WithVars({{"name", name}, {"tag_size", - // calculate_varint_size(tag)}}); - // std::string comment = get_comment(d_); - // p->Print({{"comment", comment}}, R"( - //// $comment$ - //)"); - // if (d_->has_optional_keyword() && !is_message(d_)) { - // p->Print(R"( - // if ($name$.has_value()) { - //)"); - // generate_calculate_one(p, name + ".value()", false); - // p->Print("}\n"); - // } else if (d_->is_repeated()) { - // generate_calculate_vector(p); - // } else { - // generate_calculate_one(p, name, can_ignore_default_value); - // } -} - -void FieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - // auto name = value.empty() ? "t." + this->name() : value; - // auto tag = calculate_tag(d_); - // auto v = - // p->WithVars({{"name", name}, {"tag_size", - // calculate_varint_size(tag)}}); - // auto comment = get_comment(d_); - // p->Print({{"comment", comment}}, R"( - //// $comment$ - //)"); - // if (is_optional()) { - // p->Print(R"( - // if ($name$.has_value()) { - //)"); - // generate_serialize_one(p, name + ".value()", false); - // p->Print("}\n"); - // } else if (d_->is_repeated()) { - // generate_serialize_vector(p); - // } else { - // generate_serialize_one(p, name, can_ignore_default_value); - // } -} -void FieldGenerator::generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const {} -bool FieldGenerator::is_ptr() const { - auto p = d_->containing_type(); - if (p && is_map_entry(p)) { - return false; - } - return true; -} -std::string FieldGenerator::name() const { return resolve_keyword(d_->name()); } -bool FieldGenerator::is_optional() const { - auto p = d_->containing_type(); - if (p && is_map_entry(p)) { - return false; - } - // return d_->is_optional(); - // return d_->has_optional_keyword() && !is_message(d_); - return d_->has_presence(); -} -std::string FieldGenerator::qualified_name() const { - if (is_message(d_)) { - return qualified_class_name(d_->message_type(), options_); - } - else if (is_enum(d_)) { - return qualified_enum_name(d_->enum_type(), options_); - } - else { - return get_type_name(); - } -} -std::string FieldGenerator::pb_type_name() const { return d_->type_name(); } -void FieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, bool can_ignore_default_value) const { - auto oneof = d_->real_containing_oneof(); - if (oneof) { - generate_calculate_size(p, "t." + resolve_keyword(oneof->name()), - can_ignore_default_value); - } - else { - generate_calculate_size(p, "t." + name(), can_ignore_default_value); - } -} -void FieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, bool can_ignore_default_value) const { - auto oneof = d_->real_containing_oneof(); - if (oneof) { - generate_serialization(p, "t." + resolve_keyword(oneof->name()), - can_ignore_default_value); - } - else { - Formatter format(p); - format("// "); - generate_definition(p); - generate_serialization(p, "t." + name(), can_ignore_default_value); - } -} -void FieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p) const { - auto oneof = d_->real_containing_oneof(); - if (oneof) { - generate_deserialization(p, "t." + resolve_keyword(oneof->name())); - } - else { - Formatter format(p); - format("// "); - generate_definition(p); - generate_deserialization(p, "t." + name()); - } -} -std::string FieldGenerator::cpp_type_name() const { - assert(false && "why?"); - return "???"; -} -void OneofGenerator::generate_definition(google::protobuf::io::Printer *p) { - p->Print(R"(std::variantfield_count(); ++i) { - auto f = d_->field(i); - FieldGenerator fg(f, options_); - std::string type_name = fg.get_type_name(); - if (is_message(f)) { - type_name = qualified_class_name(f->message_type(), options_); - type_name = "std::unique_ptr<" + type_name + ">"; - } - else if (is_enum(f)) { - type_name = qualified_enum_name(f->enum_type(), options_); - } - p->Print( - { - {"type", type_name}, - {"name", f->name()}, - {"pb_type", f->type_name()}, - {"number", std::to_string(f->number())}, - }, - R"(, $type$ // $pb_type$, field number = $number$ -)"); - } - p->Print({{"name", name()}}, R"(> $name$; -)"); - for (int i = 0; i < d_->field_count(); ++i) { - auto f = d_->field(i); - if (is_message(f)) { - MessageOneofFieldGenerator(f, options_).generate_setter_and_getter(p); - } - else if (is_string(f)) { - StringOneofFieldGenerator(f, options_).generate_setter_and_getter(p); - } - else if (is_enum(f)) { - EnumOneofFieldGenerator(f, options_).generate_setter_and_getter(p); - } - else { - PrimitiveOneofFieldGenerator(f, options_).generate_setter_and_getter(p); - } - } -} -void OneofGenerator::generate_calculate_size(google::protobuf::io::Printer *p) { - Formatter format(p); - format("{\n"); - format.indent(); - format("switch (t.$1$.index()) {\n", name()); - p->Print(R"( -case 0: { - // empty, do nothing - break; -} -)"); - for (int i = 0; i < d_->field_count(); ++i) { - auto f = d_->field(i); - format("case $1$: {\n", i + 1); - format.indent(); - std::string value = - "std::get<" + std::to_string(i + 1) + ">(t." + name() + ")"; - FieldGenerator(f, options_).generate_calculate_size(p, value, false); - format("break;\n"); - format.outdent(); - format("}\n"); - } - format("}\n"); - format.outdent(); - format("}\n"); -} -void OneofGenerator::generate_serialization( - google::protobuf::io::Printer *p, - const google::protobuf::FieldDescriptor *f) { - // auto index = get_index(f); - // assert(index != 0); - // auto v = p->WithVars({{"name", "t." + name()}, {"index", index}}); - // Formatter format(p); - // format("if ($name$.index() == $index$) {\n"); - // format.indent(); - // std::string name = "std::get<"; - // name += std::to_string(index); - // name += ">"; - // name += "("; - // name += "t." + this->name(); - // name += ")"; - // FieldGenerator(f, options_).generate_serialization(p, name, false); - // format.outdent(); - // format("}\n"); -} -void OneofGenerator::generate_deserialization( - google::protobuf::io::Printer *p, - const google::protobuf::FieldDescriptor *f) { - // auto index = get_index(f); - // assert(index != 0); - // auto v = p->WithVars({{"name", "t." + name()}, {"index", index}}); - // Formatter format(p); - // FieldGenerator fg(f, options_); - // std::string end = - // "t." + name() + ".emplace<" + std::to_string(index) + ">(tmp);"; - // if (is_message(f)) { - // auto type_name = qualified_class_name(f->message_type(), options_); - // fg.generate_deserialization( - // p, "tmp", type_name + "* tmp = new " + type_name + "();", end); - // } else if (is_enum(f)) { - // auto type_name = qualified_enum_name(f->enum_type(), options_); - // fg.generate_deserialization(p, "tmp", type_name + " tmp{};", end); - // } else { - // fg.generate_deserialization(p, "tmp", fg.get_type_name() + " tmp{};", - // end); - // } -} -int OneofGenerator::get_index( - const google::protobuf::FieldDescriptor *f) const { - auto index = 0; - for (int i = 0; i < d_->field_count(); ++i) { - auto fd = d_->field(i); - if (fd == f) { - index = i + 1; - } - } - return index; -} -std::string OneofGenerator::name() const { return resolve_keyword(d_->name()); } -FieldGenerator *FieldGeneratorMap::MakeGenerator(const FieldDescriptor *field, - const Options &options) { - if (field->is_repeated()) { - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: - if (field->is_map()) { - return new MapFieldGenerator(field, options); - } - else { - return new RepeatedMessageFieldGenerator(field, options); - } - case FieldDescriptor::CPPTYPE_STRING: - return new RepeatedStringFieldGenerator(field, options); - case FieldDescriptor::CPPTYPE_ENUM: - return new RepeatedEnumFieldGenerator(field, options); - default: - return new RepeatedPrimitiveFieldGenerator(field, options); - } - } - else if (field->real_containing_oneof()) { - return new OneofFieldGenerator(field, options); - // switch (field->cpp_type()) { - // case FieldDescriptor::CPPTYPE_MESSAGE: - // return new MessageOneofFieldGenerator(field, options, scc_analyzer); - // case FieldDescriptor::CPPTYPE_STRING: - // return new StringOneofFieldGenerator(field, options); - // case FieldDescriptor::CPPTYPE_ENUM: - // return new EnumOneofFieldGenerator(field, options); - // default: - // return new PrimitiveOneofFieldGenerator(field, options); - // } - } - else { - switch (field->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: - return new MessageFieldGenerator(field, options); - case FieldDescriptor::CPPTYPE_STRING: - return new StringFieldGenerator(field, options); - case FieldDescriptor::CPPTYPE_ENUM: - return new EnumFieldGenerator(field, options); - default: - return new PrimitiveFieldGenerator(field, options); - } - } -} -FieldGeneratorMap::FieldGeneratorMap(const Descriptor *descriptor, - const Options &options) - : descriptor_(descriptor), field_generators_(descriptor->field_count()) { - // Construct all the FieldGenerators. - for (int i = 0; i < descriptor->field_count(); i++) { - field_generators_[i].reset(MakeGenerator(descriptor->field(i), options)); - } -} -const FieldGenerator &FieldGeneratorMap::get( - const FieldDescriptor *field) const { - return *field_generators_[field->index()]; -} -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/FieldGenerator.h b/src/struct_pb/protoc-plugin/FieldGenerator.h deleted file mode 100644 index 8fba31b5a..000000000 --- a/src/struct_pb/protoc-plugin/FieldGenerator.h +++ /dev/null @@ -1,90 +0,0 @@ -#pragma once -#include "GeneratorBase.h" -#include "helpers.hpp" -namespace struct_pb { -namespace compiler { -class OneofGenerator; -bool is_varint(const FieldDescriptor *f); -bool is_sint(const FieldDescriptor *f); -bool is_sint32(const FieldDescriptor *f); -bool is_bool(const FieldDescriptor *f); -bool is_i64(const FieldDescriptor *f); -bool is_i32(const FieldDescriptor *f); -uint32_t calculate_tag(const FieldDescriptor *f, bool ignore_repeated = false); -std::string calculate_tag_str(const FieldDescriptor *f, - bool ignore_repeated = false); -std::string calculate_tag_size(const FieldDescriptor *f, - bool ignore_repeated = false); -class FieldGenerator : public GeneratorBase { - public: - FieldGenerator(const google::protobuf::FieldDescriptor *d, - const Options &options) - : GeneratorBase(options), d_(d) {} - void generate_definition(google::protobuf::io::Printer *p) const; - void generate_calculate_size(google::protobuf::io::Printer *p, - bool can_ignore_default_value) const; - void generate_serialization(google::protobuf::io::Printer *p, - bool can_ignore_default_value) const; - void generate_deserialization(google::protobuf::io::Printer *p) const; - - virtual void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const; - virtual void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const; - virtual void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const; - virtual std::string cpp_type_name() const; - virtual std::string pb_type_name() const; - - protected: - std::string get_type_name() const; - bool is_ptr() const; - std::string name() const; - bool is_optional() const; - std::string qualified_name() const; - - protected: - const google::protobuf::FieldDescriptor *d_; - friend class OneofGenerator; -}; -class OneofGenerator : public GeneratorBase { - public: - OneofGenerator(const google::protobuf::OneofDescriptor *d, - const Options &options) - : GeneratorBase(options), d_(d) {} - void generate_definition(google::protobuf::io::Printer *p); - void generate_calculate_size(google::protobuf::io::Printer *p); - void generate_serialization(google::protobuf::io::Printer *p, - const google::protobuf::FieldDescriptor *f); - void generate_deserialization(google::protobuf::io::Printer *p, - const google::protobuf::FieldDescriptor *f); - - private: - int get_index(const google::protobuf::FieldDescriptor *f) const; - std::string name() const; - - private: - const google::protobuf::OneofDescriptor *d_; -}; -class MapFieldGenerator; -class FieldGeneratorMap { - public: - FieldGeneratorMap(const Descriptor *descriptor, const Options &options); - FieldGeneratorMap(const FieldGeneratorMap &) = delete; - FieldGeneratorMap &operator=(const FieldGeneratorMap &) = delete; - - const FieldGenerator &get(const FieldDescriptor *field) const; - - private: - const Descriptor *descriptor_; - std::vector> field_generators_; - - static FieldGenerator *MakeGenerator(const FieldDescriptor *field, - const Options &options); - friend class MapFieldGenerator; -}; - -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/FileGenerator.cpp b/src/struct_pb/protoc-plugin/FileGenerator.cpp deleted file mode 100644 index 1525ad9ce..000000000 --- a/src/struct_pb/protoc-plugin/FileGenerator.cpp +++ /dev/null @@ -1,199 +0,0 @@ -#include "FileGenerator.h" - -#include - -#include "EnumGenerator.h" -#include "MessageGenerator.h" -#include "helpers.hpp" -using namespace google::protobuf; -using namespace google::protobuf::compiler; -namespace struct_pb { -namespace compiler { - -FileGenerator::FileGenerator(const google::protobuf::FileDescriptor *file, - Options options) - : GeneratorBase(options), file_(file) { - // std::vector msgs = flatten_messages_in_file(file); - for (int i = 0; i < file_->message_type_count(); ++i) { - message_generators_.push_back( - std::make_unique(file_->message_type(i), options)); - } - for (int i = 0; i < file->enum_type_count(); ++i) { - enum_generators_.push_back( - std::make_unique(file->enum_type(i), options)); - } -} - -void FileGenerator::generate_enum_definitions( - google::protobuf::io::Printer *p) { - for (int i = 0; i < enum_generators_.size(); ++i) { - enum_generators_[i]->generate_definition(p); - } -} -void FileGenerator::generate_message_definitions( - google::protobuf::io::Printer *p) { - for (int i = 0; i < message_generators_.size(); ++i) { - message_generators_[i]->generate_struct_definition(p); - } -} -void FileGenerator::generate_shared_header_code( - google::protobuf::io::Printer *p) { - generate_fwd_decls(p); - generate_enum_definitions(p); - generate_message_definitions(p); -} -void FileGenerator::generate_header(google::protobuf::io::Printer *p) { - p->Print( - {{"filename", file_->name()}}, - R"(// Generated by the protocol buffer compiler (struct_pb). DO NOT EDIT! -// source: $filename$ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "ylt/struct_pb.hpp" -)"); - - generate_dependency_includes(p); - generate_ns_open(p); - generate_shared_header_code(p); - generate_ns_close(p); - generate_message_struct_pb_func_definitions(p); - p->Print("// clang-format on\n"); -} - -void FileGenerator::generate_fwd_decls(google::protobuf::io::Printer *p) { - Formatter format(p); - for (int i = 0; i < file_->message_type_count(); ++i) { - auto m = file_->message_type(i); - format("struct $1$;\n", resolve_keyword(m->name())); - } -} -void FileGenerator::generate_dependency_includes( - google::protobuf::io::Printer *p) { - Formatter format(p); - for (int i = 0; i < file_->dependency_count(); ++i) { - auto dep = file_->dependency(i); - std::string basename = strip_proto(dep->name()); - std::string header_name = basename + ".struct_pb.h"; - format("#include \"$1$\"\n", header_name); - } -} -void FileGenerator::generate_source(google::protobuf::io::Printer *p) { - generate_message_struct_pb_func_source(p); -} -void FileGenerator::generate_message_struct_pb_func_definitions( - google::protobuf::io::Printer *p) { - std::vector msgs = flatten_messages_in_file(file_); - Formatter format(p); - format("namespace struct_pb {\n"); - format("namespace internal {\n"); - for (auto msg : msgs) { - auto name = qualified_class_name(msg, options_); - format("// $1$\n", name); - format( - "template<>\n" - "std::size_t get_needed_size<$1$>(const $1$& t, const " - "::struct_pb::UnknownFields& unknown_fields);\n", - name); - format( - "template<>\n" - "void serialize_to<$1$>(char* data, std::size_t size, const $1$& t, " - "const " - "::struct_pb::UnknownFields& unknown_fields);\n", - name); - format( - "template<>\n" - "bool deserialize_to<$1$>($1$& t, const char* data, std::size_t size, " - "::struct_pb::UnknownFields& unknown_fields);\n", - name); - format( - "template<>\n" - "bool deserialize_to<$1$>($1$& t, const char* data, std::size_t " - "size);\n", - name); - format("\n"); - } - format("} // internal\n"); - format("} // struct_pb\n"); -} -void FileGenerator::generate_message_struct_pb_func_source( - google::protobuf::io::Printer *p) { - std::vector msgs = flatten_messages_in_file(file_); - Formatter format(p); - format("namespace struct_pb {\n"); - format("namespace internal {\n"); - for (auto msg : msgs) { - auto name = qualified_class_name(msg, options_); - MessageGenerator g(msg, options_); - format("// $1$\n", name); - format( - "template<>\n" - "std::size_t get_needed_size<$1$>(const $1$& t, const " - "::struct_pb::UnknownFields& unknown_fields) {\n", - name); - format.indent(); - g.generate_get_needed_size(p); - format.outdent(); - format( - "} // std::size_t get_needed_size<$1$>(const $1$& t, const " - "::struct_pb::UnknownFields& unknown_fields)\n", - name); - - format( - "template<>\n" - "void serialize_to<$1$>(char* data, std::size_t size, const $1$& t, " - "const ::struct_pb::UnknownFields& unknown_fields) {\n", - name); - format.indent(); - g.generate_serialize_to(p); - format.outdent(); - format( - "} // void serialize_to<$1$>(char* data, std::size_t size, const $1$& " - "t, " - "const ::struct_pb::UnknownFields& unknown_fields)\n", - name); - - format( - "template<>\n" - "bool deserialize_to<$1$>($1$& t, const char* data, std::size_t size, " - "::struct_pb::UnknownFields& unknown_fields) {\n", - name); - format.indent(); - g.generate_deserialize_to(p); - format.outdent(); - format("return true;\n"); - format("} // bool deserialize_to<$1$>($1$&, const char*, std::size_t)\n", - name); - format("// end of $1$\n", name); - format( - "template<>\n" - "bool deserialize_to<$1$>($1$& t, const char* data, std::size_t size) " - "{\n", - name); - format.indent(); - format("::struct_pb::UnknownFields unknown_fields{};\n"); - format("return deserialize_to(t,data,size,unknown_fields);\n"); - format.outdent(); - format("}\n"); - format("\n"); - } - format("} // internal\n"); - format("} // struct_pb\n"); -} -void FileGenerator::generate_ns_open(google::protobuf::io::Printer *p) { - NamespaceOpener(p, options_.ns).open(); -} -void FileGenerator::generate_ns_close(google::protobuf::io::Printer *p) { - NamespaceOpener(p, options_.ns).close(); -} - -} // namespace compiler - -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/FileGenerator.h b/src/struct_pb/protoc-plugin/FileGenerator.h deleted file mode 100644 index ee4d50212..000000000 --- a/src/struct_pb/protoc-plugin/FileGenerator.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include "EnumGenerator.h" -#include "GeneratorBase.h" -#include "MessageGenerator.h" -#include "Options.hpp" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/io/printer.h" -namespace struct_pb { -namespace compiler { -class FileGenerator : public GeneratorBase { - public: - FileGenerator(const google::protobuf::FileDescriptor *file, Options options); - ; - void generate_header(google::protobuf::io::Printer *p); - void generate_source(google::protobuf::io::Printer *p); - - private: - void generate_shared_header_code(google::protobuf::io::Printer *p); - void generate_fwd_decls(google::protobuf::io::Printer *p); - void generate_enum_definitions(google::protobuf::io::Printer *p); - void generate_message_definitions(google::protobuf::io::Printer *p); - void generate_message_struct_pb_func_definitions( - google::protobuf::io::Printer *p); - void generate_message_struct_pb_func_source(google::protobuf::io::Printer *p); - void generate_dependency_includes(google::protobuf::io::Printer *p); - void generate_ns_open(google::protobuf::io::Printer *p); - void generate_ns_close(google::protobuf::io::Printer *p); - - private: - const google::protobuf::FileDescriptor *file_; - std::vector> message_generators_; - std::vector> enum_generators_; -}; -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/GeneratorBase.cpp b/src/struct_pb/protoc-plugin/GeneratorBase.cpp deleted file mode 100644 index 9f3546680..000000000 --- a/src/struct_pb/protoc-plugin/GeneratorBase.cpp +++ /dev/null @@ -1,26 +0,0 @@ -#include "GeneratorBase.h" - -#include -namespace struct_pb { -namespace compiler { - -// Convert lowerCamelCase and UpperCamelCase strings to lower_with_underscore. -std::string convert(const std::string &camelCase) { - std::string str(1, tolower(camelCase[0])); - - // First place underscores between contiguous lower and upper case letters. - // For example, `_LowerCamelCase` becomes `_Lower_Camel_Case`. - for (auto it = camelCase.begin() + 1; it != camelCase.end(); ++it) { - if (isupper(*it) && *(it - 1) != '_' && islower(*(it - 1))) { - str += "_"; - } - str += *it; - } - - // Then convert it to lower case. - std::transform(str.begin(), str.end(), str.begin(), ::tolower); - - return str; -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/GeneratorBase.h b/src/struct_pb/protoc-plugin/GeneratorBase.h deleted file mode 100644 index 9341acae5..000000000 --- a/src/struct_pb/protoc-plugin/GeneratorBase.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "Options.hpp" -#include "google/protobuf/descriptor.h" -namespace struct_pb { -namespace compiler { -using namespace google::protobuf; -class GeneratorBase { - public: - GeneratorBase(Options options) : options_(options) {} - - protected: - Options options_; -}; -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/MapFieldGenerator.cpp b/src/struct_pb/protoc-plugin/MapFieldGenerator.cpp deleted file mode 100644 index bbf577f4a..000000000 --- a/src/struct_pb/protoc-plugin/MapFieldGenerator.cpp +++ /dev/null @@ -1,298 +0,0 @@ -#include "MapFieldGenerator.h" - -#include "EnumFieldGenerator.h" -#include "MessageFieldGenerator.h" -#include "PrimitiveFieldGenerator.h" -#include "StringFieldGenerator.h" -namespace struct_pb { -namespace compiler { -MapFieldGenerator::MapFieldGenerator(const FieldDescriptor *field, - const Options &options) - : FieldGenerator(field, options) {} - -static std::string get_type_name_help(FieldDescriptor::Type type) { - switch (type) { - case google::protobuf::FieldDescriptor::TYPE_DOUBLE: - return "double"; - case google::protobuf::FieldDescriptor::TYPE_FLOAT: - return "float"; - case google::protobuf::FieldDescriptor::TYPE_INT64: - case google::protobuf::FieldDescriptor::TYPE_SFIXED64: - case google::protobuf::FieldDescriptor::TYPE_SINT64: - return "int64_t"; - case google::protobuf::FieldDescriptor::TYPE_UINT64: - case google::protobuf::FieldDescriptor::TYPE_FIXED64: - return "uint64_t"; - case google::protobuf::FieldDescriptor::TYPE_UINT32: - case google::protobuf::FieldDescriptor::TYPE_FIXED32: - return "uint32_t"; - case google::protobuf::FieldDescriptor::TYPE_INT32: - case google::protobuf::FieldDescriptor::TYPE_SFIXED32: - case google::protobuf::FieldDescriptor::TYPE_SINT32: - return "int32_t"; - case google::protobuf::FieldDescriptor::TYPE_BOOL: - return "bool"; - case google::protobuf::FieldDescriptor::TYPE_STRING: - case google::protobuf::FieldDescriptor::TYPE_BYTES: - return "std::string"; - case google::protobuf::FieldDescriptor::TYPE_GROUP: - // workaround for group - return "std::string"; - default: { - return "not support now"; - } - } -} -std::string MapFieldGenerator::cpp_type_name() const { - return "std::map<" + get_key_type_name() + ", " + get_value_type_name() + ">"; -} -std::string MapFieldGenerator::get_value_type_name() const { - return get_kv_type_name_helper(d_->message_type()->field(1)); -} -std::string MapFieldGenerator::get_key_type_name() const { - return get_kv_type_name_helper(d_->message_type()->field(0)); -} -std::string MapFieldGenerator::get_kv_type_name_helper( - const FieldDescriptor *f) const { - if (f->type() == FieldDescriptor::TYPE_MESSAGE) { - return qualified_class_name(f->message_type(), options_); - } - else if (f->type() == FieldDescriptor::TYPE_ENUM) { - return qualified_enum_name(f->enum_type(), options_); - } - else { - return get_type_name_help(f->type()); - } -} -void MapFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - generate_calculate_size_only(p, value); -} -void MapFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("for(const auto& e: $1$) {\n", value); - format.indent(); - format("std::size_t map_entry_sz = 0;\n"); - auto key_f = d_->message_type()->field(0); - auto value_f = d_->message_type()->field(1); - generate_calculate_kv_size(p, key_f, "e.first"); - generate_calculate_kv_size(p, value_f, "e.second"); - format("total += $1$ + calculate_varint_size(map_entry_sz) + map_entry_sz;", - calculate_tag_size(d_)); - format.outdent(); - format("}\n"); -} -void MapFieldGenerator::generate_calculate_kv_size( - google::protobuf::io::Printer *p, const FieldDescriptor *f, - const std::string &value) const { - Formatter format(p); - switch (f->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: { - p->Print({{"value", value}, {"tag_sz", calculate_tag_size(f)}}, R"( -std::size_t sz = get_needed_size($value$); -map_entry_sz += $tag_sz$ + calculate_varint_size(sz) + sz; -)"); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - format( - "map_entry_sz += $1$ + calculate_varint_size($2$.size()) + " - "$2$.size();\n", - calculate_tag_size(f), value); - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - p->Print({{"tag_sz", calculate_tag_size(f)}}, - R"( -map_entry_sz += $tag_sz$ + )"); - EnumFieldGenerator(f, options_).generate_calculate_size_only(p, value); - format(";\n"); - break; - } - default: { - format("map_entry_sz += $1$ + ", calculate_tag_size(f)); - PrimitiveFieldGenerator(f, options_) - .generate_calculate_size_only(p, value); - format(";\n"); - } - } -} -void MapFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - generate_serialization_only(p, value); -} -void MapFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - auto key_f = d_->message_type()->field(0); - auto value_f = d_->message_type()->field(1); - std::unique_ptr kg; - kg.reset(FieldGeneratorMap::MakeGenerator(key_f, options_)); - std::unique_ptr vg; - kg.reset(FieldGeneratorMap::MakeGenerator(value_f, options_)); - Formatter format(p); - format("for(const auto& e: $1$) {\n", value); - format.indent(); - format("serialize_varint(data, pos, size, $1$);\n", calculate_tag_str(d_)); - format("std::size_t map_entry_sz = 0;\n"); - format("{\n"); - format.indent(); - generate_calculate_kv_size(p, key_f, "e.first"); - format.outdent(); - format("}\n"); - format("{\n"); - format.indent(); - generate_calculate_kv_size(p, value_f, "e.second"); - format.outdent(); - format("}\n"); - - format("serialize_varint(data, pos, size, map_entry_sz);\n"); - format("{\n"); - format.indent(); - generate_serialize_kv_only(p, key_f, "e.first"); - format.outdent(); - format("}\n"); - format("{\n"); - format.indent(); - generate_serialize_kv_only(p, value_f, "e.second"); - format.outdent(); - format("}\n"); - - format.outdent(); - format("}\n"); -} -void MapFieldGenerator::generate_serialize_kv_only( - google::protobuf::io::Printer *p, const FieldDescriptor *f, - const std::string &value) const { - switch (f->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: { - p->Print({{"value", value}, {"tag", calculate_tag_str(f)}}, R"( -serialize_varint(data, pos, size, $tag$); -std::size_t sz = get_needed_size($value$); -serialize_varint(data, pos, size, sz); -serialize_to(data + pos, sz, $value$); -pos += sz; -)"); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - StringFieldGenerator(f, options_).generate_serialization_only(p, value); - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - EnumFieldGenerator(f, options_).generate_serialization_only(p, value); - break; - } - default: { - p->Print({{"tag", calculate_tag_str(f)}}, - R"( -serialize_varint(data, pos, size, $tag$); -)"); - PrimitiveFieldGenerator(f, options_) - .generate_serialization_only(p, value); - } - } -} -void MapFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"tag", calculate_tag_str(d_)}}, - R"( -case $tag$: { - uint64_t sz = 0; - ok = deserialize_varint(data, pos, size, sz); - if (!ok) { - return false; - } - std::size_t cur_max_size = pos + sz; -)"); - generate_deserialization_only(p, value); - p->Print(R"( -break; -} -)"); -} -void MapFieldGenerator::generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - auto key_f = d_->message_type()->field(0); - auto value_f = d_->message_type()->field(1); - Formatter format(p); - format("$1$ key_tmp_val{};\n", get_key_type_name()); - format("$1$ value_tmp_val{};\n", get_value_type_name()); - p->Print( - { - {"key_tag", calculate_tag_str(key_f)}, - }, - R"( -while (pos < cur_max_size) { - ok = read_tag(data, pos, size, tag); - if (!ok) { - return false; - } - switch(tag) { - case $key_tag$: { -)"); - generate_deserialize_kv_only(p, key_f, "key_tmp_val", "cur_max_size"); - p->Print( - { - {"value_tag", calculate_tag_str(value_f)}, - }, - R"( -break; -} -case $value_tag$: { -)"); - generate_deserialize_kv_only(p, value_f, "value_tmp_val", "cur_max_size"); - p->Print({{"value", value}}, R"( -break; - } - - default: { - return false; - } - } -} -$value$[key_tmp_val] = std::move(value_tmp_val); -)"); -} -void MapFieldGenerator::generate_deserialize_kv_only( - google::protobuf::io::Printer *p, const FieldDescriptor *f, - const std::string &value, const std::string &max_size) const { - switch (f->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: { - p->Print({{"value", value}, - {"tag", calculate_tag_str(f)}, - {"max_size", max_size}}, - R"( -uint64_t msg_sz = 0; -ok = deserialize_varint(data, pos, $max_size$, msg_sz); -if (!ok) { - return false; -} -ok = deserialize_to($value$, data + pos, msg_sz); -if (!ok) { - return false; -} -pos += msg_sz; -)"); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - StringFieldGenerator(f, options_) - .generate_deserialization_only(p, value, "str_sz", max_size); - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - EnumFieldGenerator(f, options_) - .generate_deserialization_only(p, value, max_size); - break; - } - default: { - PrimitiveFieldGenerator(f, options_) - .generate_deserialization_only(p, value); - } - } -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/MapFieldGenerator.h b/src/struct_pb/protoc-plugin/MapFieldGenerator.h deleted file mode 100644 index 04298364d..000000000 --- a/src/struct_pb/protoc-plugin/MapFieldGenerator.h +++ /dev/null @@ -1,44 +0,0 @@ -#pragma once -#include "FieldGenerator.h" -namespace struct_pb { -namespace compiler { - -class MapFieldGenerator : public FieldGenerator { - public: - MapFieldGenerator(const FieldDescriptor *field, const Options &options); - std::string cpp_type_name() const override; - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - void generate_deserialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - - private: - void generate_calculate_kv_size(google::protobuf::io::Printer *p, - const FieldDescriptor *f, - const std::string &value) const; - void generate_serialize_kv_only(google::protobuf::io::Printer *p, - const FieldDescriptor *f, - const std::string &value) const; - void generate_deserialize_kv_only(google::protobuf::io::Printer *p, - const FieldDescriptor *f, - const std::string &value, - const std::string &max_size) const; - - private: - std::string get_key_type_name() const; - std::string get_value_type_name() const; - std::string get_kv_type_name_helper(const FieldDescriptor *f) const; -}; - -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/MessageFieldGenerator.cpp b/src/struct_pb/protoc-plugin/MessageFieldGenerator.cpp deleted file mode 100644 index 4e61fd35f..000000000 --- a/src/struct_pb/protoc-plugin/MessageFieldGenerator.cpp +++ /dev/null @@ -1,149 +0,0 @@ -#include "MessageFieldGenerator.h" - -namespace struct_pb { -namespace compiler { -MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor *field, - const Options &options) - : FieldGenerator(field, options) {} -void MessageFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - if (can_ignore_default_value) { - p->Print({{"tag_sz", calculate_tag_size(d_)}, {"value", value}}, R"( -if ($value$) { - auto sz = get_needed_size(*$value$); - total += $tag_sz$ + calculate_varint_size(sz) + sz; -} -)"); - } - else { - p->Print({{"tag_sz", calculate_tag_size(d_)}, {"value", value}}, R"( -auto sz = get_needed_size(*$value$); -total += $tag_sz$ + calculate_varint_size(sz) + sz; -)"); - } -} -void MessageFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - p->Print({{"value", value}, {"tag", calculate_tag_str(d_)}}, R"( -if ($value$) { - serialize_varint(data, pos, size, $tag$); - auto sz = get_needed_size(*$value$); - serialize_varint(data, pos, size, sz); - serialize_to(data + pos, sz, *$value$); - pos += sz; -} -)"); -} -void MessageFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"value", value}, - {"tag", calculate_tag_str(d_)}, - {"classname", qualified_class_name(d_->message_type(), options_)}}, - R"(case $tag$: { - if (!$value$) { - $value$ = std::make_unique<$classname$>(); - } - uint64_t sz = 0; - ok = deserialize_varint(data, pos, size, sz); - if (!ok) { - return false; - } - ok = deserialize_to(*$value$, data + pos, sz); - if (!ok) { - return false; - } - pos += sz; - break; -} -)"); -} -std::string MessageFieldGenerator::cpp_type_name() const { - return "std::unique_ptr<" + - qualified_class_name(d_->message_type(), options_) + ">"; -} - -RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator( - const FieldDescriptor *field, const Options &options) - : FieldGenerator(field, options) {} -void RepeatedMessageFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (can_ignore_default_value) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - generate_calculate_size_only(p, value); - format.outdent(); - format("}\n"); - } - else { - generate_calculate_size_only(p, value); - } -} -void RepeatedMessageFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (can_ignore_default_value) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - generate_serialization_only(p, value); - format.outdent(); - format("}\n"); - } - else { - generate_serialization_only(p, value); - } -} -void RepeatedMessageFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"tag", std::to_string(calculate_tag(d_))}, - {"value", value}, - {"classname", qualified_class_name(d_->message_type(), options_)}}, - R"(case $tag$: { - uint64_t sz = 0; - ok = deserialize_varint(data, pos, size, sz); - if (!ok) { - return false; - } - $value$.emplace_back(); - ok = deserialize_to($value$.back(), data + pos, sz); - if (!ok) { - $value$.pop_back(); - return false; - } - pos += sz; - break; -} -)"); -} -std::string RepeatedMessageFieldGenerator::cpp_type_name() const { - return "std::vector<" + qualified_class_name(d_->message_type(), options_) + - ">"; -} -void RepeatedMessageFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"tag_sz", calculate_tag_size(d_)}, {"value", value}}, R"( -for(const auto& e: $value$) { - std::size_t sz = get_needed_size(e); - total += $tag_sz$ + calculate_varint_size(sz) + sz; -} -)"); -} -void RepeatedMessageFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - p->Print({{"tag", std::to_string(calculate_tag(d_))}, {"value", value}}, R"( -for(const auto& e: $value$) { - serialize_varint(data, pos, size, $tag$); - std::size_t sz = get_needed_size(e); - serialize_varint(data, pos, size, sz); - serialize_to(data+pos, sz, e); - pos += sz; -} -)"); -} - -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/MessageFieldGenerator.h b/src/struct_pb/protoc-plugin/MessageFieldGenerator.h deleted file mode 100644 index 12937b3db..000000000 --- a/src/struct_pb/protoc-plugin/MessageFieldGenerator.h +++ /dev/null @@ -1,38 +0,0 @@ -#pragma once -#include "FieldGenerator.h" -namespace struct_pb { -namespace compiler { - -class MessageFieldGenerator : public FieldGenerator { - public: - MessageFieldGenerator(const FieldDescriptor *field, const Options &options); - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - std::string cpp_type_name() const override; -}; -class RepeatedMessageFieldGenerator : public FieldGenerator { - public: - RepeatedMessageFieldGenerator(const FieldDescriptor *field, - const Options &options); - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - std::string cpp_type_name() const override; -}; -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/MessageGenerator.cpp b/src/struct_pb/protoc-plugin/MessageGenerator.cpp deleted file mode 100644 index 0fd3a11ea..000000000 --- a/src/struct_pb/protoc-plugin/MessageGenerator.cpp +++ /dev/null @@ -1,209 +0,0 @@ -#include "MessageGenerator.h" - -#include "EnumGenerator.h" -#include "FieldGenerator.h" -#include "helpers.hpp" -using namespace google::protobuf; -using namespace google::protobuf::internal; -namespace struct_pb { -namespace compiler { -std::unordered_map ClassVars( - const Descriptor *descriptor, Options options) { - std::unordered_map vars{}; - vars.emplace("classname", resolve_keyword(descriptor->name())); - vars.emplace("classtype", qualified_class_name(descriptor, options)); - return vars; -} -// copy from cpp compiler -static std::string UnderscoresToCamelCase(const std::string &input, - bool cap_next_letter) { - std::string result; - // Note: I distrust ctype.h due to locales. - for (int i = 0; i < input.size(); i++) { - if ('a' <= input[i] && input[i] <= 'z') { - if (cap_next_letter) { - result += input[i] + ('A' - 'a'); - } - else { - result += input[i]; - } - cap_next_letter = false; - } - else if ('A' <= input[i] && input[i] <= 'Z') { - // Capital letters are left as-is. - result += input[i]; - cap_next_letter = false; - } - else if ('0' <= input[i] && input[i] <= '9') { - result += input[i]; - cap_next_letter = true; - } - else { - cap_next_letter = true; - } - } - return result; -} - -void MessageGenerator::generate_struct_definition( - google::protobuf::io::Printer *p) { - // auto v = p->WithVars(ClassVars(d_, options_)); - Formatter format(p); - format("struct $1$ {\n", resolve_keyword(d_->name())); - format.indent(); - for (int i = 0; i < d_->enum_type_count(); ++i) { - auto e = d_->enum_type(i); - EnumGenerator(e, options_).generate_definition(p); - } - for (int i = 0; i < d_->oneof_decl_count(); ++i) { - auto oneof = d_->oneof_decl(i); - std::string enum_name = UnderscoresToCamelCase(oneof->name(), true); - format("enum class $1$Case {\n", enum_name); - format.indent(); - format("none = 0,\n"); - for (int j = 0; j < oneof->field_count(); ++j) { - auto f = oneof->field(j); - format("$1$ = $2$,\n", resolve_keyword(f->name()), f->number()); - } - format.outdent(); - format("};\n"); - format("$1$Case $2$_case() const {\n", enum_name, oneof->name()); - format.indent(); - format("switch ($1$.index()) {\n", resolve_keyword(oneof->name())); - format.indent(); - for (int j = 0; j < oneof->field_count(); ++j) { - format("case $1$:\n", j + 1); - format.indent(); - format("return $1$Case::$2$;\n", enum_name, - resolve_keyword(oneof->field(j)->name())); - format.outdent(); - } - format("default:\n"); - format.indent(); - format("return $1$Case::none;\n", enum_name); - format.outdent(); - - format.outdent(); - format("}\n"); - format.outdent(); - format("}\n"); - format("\n"); - } - for (int i = 0; i < d_->nested_type_count(); ++i) { - auto t = d_->nested_type(i); - auto name = t->name(); - if (is_map_entry(t)) { - continue; - } - MessageGenerator(t, options_).generate_struct_definition(p); - } - std::set oneof_set; - for (int i = 0; i < d_->field_count(); ++i) { - auto f = d_->field(i); - auto oneof = f->containing_oneof(); - if (oneof) { - if (oneof_set.find(oneof) == oneof_set.end()) { - OneofGenerator(oneof, options_).generate_definition(p); - oneof_set.insert(oneof); - } - else { - continue; - } - } - else { - fg_map_.get(f).generate_definition(p); - } - } - if (options_.generate_eq_op) { - format("bool operator==(const $1$&) const = default;\n", class_name(d_)); - } - // format("std::size_t get_needed_size() const;\n"); - // format("std::string SerializeAsString() const;\n"); - // format("bool ParseFromArray(const char* data, std::size_t size);\n"); - format.outdent(); - format("};\n"); -} -void MessageGenerator::generate_source(google::protobuf::io::Printer *p) { - generate_get_needed_size(p); - Formatter format(p); - format("std::string $1$::SerializeAsString() const {\n", d_->name()); - format.indent(); - format("std::string buffer;\n"); - format("// calculate buffer size\n"); - format("std::size_t total = get_needed_size();\n"); - format("std::size_t pos = 0;\n"); - format("buffer.resize(total);\n"); - for (int i = 0; i < d_->field_count(); ++i) { - auto f = d_->field(i); - // FieldGenerator(f, options_).generate_calculate_size(p); - } - format("return buffer;\n"); - format.outdent(); - format("}\n"); -} -void MessageGenerator::generate_get_needed_size( - google::protobuf::io::Printer *p) { - Formatter format(p); - format("std::size_t total = unknown_fields.total_size();\n"); - std::set oneof_set; - for (int i = 0; i < d_->field_count(); ++i) { - auto f = d_->field(i); - fg_map_.get(f).generate_calculate_size(p, true); - } - format("return total;\n"); -} -void MessageGenerator::generate_serialize_to(google::protobuf::io::Printer *p) { - Formatter format(p); - format("std::size_t pos = 0;\n"); - std::vector fs; - fs.reserve(d_->field_count()); - for (int i = 0; i < d_->field_count(); ++i) { - fs.push_back(d_->field(i)); - } - std::sort(fs.begin(), fs.end(), - [](const FieldDescriptor *lhs, const FieldDescriptor *rhs) { - return lhs->number() < rhs->number(); - }); - for (int i = 0; i < d_->field_count(); ++i) { - auto f = fs[i]; - format("{\n"); - format.indent(); - fg_map_.get(f).generate_serialization(p, true); - format.outdent(); - format("}\n"); - } - format("unknown_fields.serialize_to(data, pos, size);\n"); -} -void MessageGenerator::generate_deserialize_to( - google::protobuf::io::Printer *p) { - Formatter format(p); - format("std::size_t pos = 0;\n"); - format("bool ok = false;\n"); - format("while (pos < size) {\n"); - format.indent(); - p->Print(R"(uint64_t tag = 0; -ok = read_tag(data, pos, size, tag); -if (!ok) { - return false; -} -switch(tag) { -)"); - format.indent(); - for (int i = 0; i < d_->field_count(); ++i) { - auto f = d_->field(i); - fg_map_.get(f).generate_deserialization(p); - } - format("default: {\n"); - format.indent(); - format("ok = deserialize_unknown(data, pos, size, tag, unknown_fields);\n"); - format("return ok;\n"); - format.outdent(); - format("}\n"); - format.outdent(); - format("}\n"); - - format.outdent(); - format("}\n"); -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/MessageGenerator.h b/src/struct_pb/protoc-plugin/MessageGenerator.h deleted file mode 100644 index 49e4b42b8..000000000 --- a/src/struct_pb/protoc-plugin/MessageGenerator.h +++ /dev/null @@ -1,33 +0,0 @@ -#pragma once -#include "FieldGenerator.h" -#include "GeneratorBase.h" -namespace struct_pb { -namespace compiler { -class FileGenerator; -class MessageGenerator : public GeneratorBase { - public: - MessageGenerator(const google::protobuf::Descriptor *d, Options options) - : GeneratorBase(options), d_(d), fg_map_(d, options) {} - - void generate(google::protobuf::io::Printer *p); - void generate_struct_definition(google::protobuf::io::Printer *p); - void generate_source(google::protobuf::io::Printer *p); - - private: - void generate_get_needed_size(google::protobuf::io::Printer *p); - void generate_serialize_to(google::protobuf::io::Printer *p); - void generate_deserialize_to(google::protobuf::io::Printer *p); - - private: - const google::protobuf::Descriptor *d_; - std::vector field_name_list; - std::vector unpack_index_list; - std::vector field_number_list; - std::map n2i_map; - std::map i2n_map; - FieldGeneratorMap fg_map_; - friend class FileGenerator; -}; - -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/OneofFieldGenerator.cpp b/src/struct_pb/protoc-plugin/OneofFieldGenerator.cpp deleted file mode 100644 index 89516f20d..000000000 --- a/src/struct_pb/protoc-plugin/OneofFieldGenerator.cpp +++ /dev/null @@ -1,323 +0,0 @@ -#include "OneofFieldGenerator.h" - -#include "EnumFieldGenerator.h" -#include "PrimitiveFieldGenerator.h" -#include "StringFieldGenerator.h" -#include "helpers.hpp" -namespace struct_pb { -namespace compiler { -void OneofFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - format("if ($1$.index() == $2$) {\n", value, index()); - generate_calculate_size_only(p, value); - format("\n}\n"); -} -std::string OneofFieldGenerator::index() const { - auto oneof = d_->containing_oneof(); - assert(oneof); - int index = 0; - for (int i = 0; i < oneof->field_count(); ++i) { - if (oneof->field(i) == d_) { - index = i + 1; - break; - } - } - assert(index > 0); - return std::to_string(index); -} -void OneofFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - auto oneof_value = "std::get<" + index() + ">(" + value + ")"; - - switch (d_->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: { - p->Print({{"tag_sz", calculate_tag_size(d_)}, - {"index", index()}, - {"oneof_value", oneof_value}, - {"value", value}}, - R"( -uint64_t sz = 0; -if ($oneof_value$) { - sz = get_needed_size(*$oneof_value$); -} -total += $tag_sz$ + calculate_varint_size(sz) + sz; -)"); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - p->Print( - { - {"tag_sz", calculate_tag_size(d_)}, - }, - R"( -total += $tag_sz$ + calculate_varint_size()"); - StringFieldGenerator(d_, options_) - .generate_calculate_size_only(p, oneof_value); - p->Print(") + "); - - StringFieldGenerator(d_, options_) - .generate_calculate_size_only(p, oneof_value); - p->Print(";\n"); - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - format("total += $1$ + ", calculate_tag_size(d_)); - EnumFieldGenerator(d_, options_) - .generate_calculate_size_only(p, oneof_value); - format(";\n"); - break; - } - default: { - format("total += $1$ + ", calculate_tag_size(d_)); - PrimitiveFieldGenerator(d_, options_) - .generate_calculate_size_only(p, oneof_value); - format(";\n"); - } - } -} -void OneofFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - format("if ($1$.index() == $2$) {\n", value, index()); - generate_serialization_only(p, value); - format("\n}\n"); -} -void OneofFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - auto oneof_value = "std::get<" + index() + ">(" + value + ")"; - - switch (d_->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: { - p->Print({{"value", value}, - {"tag", std::to_string(calculate_tag(d_))}, - {"index", index()}, - {"oneof_value", oneof_value} - - }, - R"( -serialize_varint(data, pos, size, $tag$); -if ($oneof_value$) { - std::size_t sz = get_needed_size(*$oneof_value$); - serialize_varint(data, pos, size, sz); - serialize_to(data + pos, sz, *$oneof_value$); - pos += sz; -} -else { - serialize_varint(data, pos, size, 0); -} -)"); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - StringFieldGenerator(d_, options_) - .generate_serialization_only(p, oneof_value); - - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - EnumFieldGenerator(d_, options_) - .generate_serialization_only(p, oneof_value); - break; - } - default: { - p->Print({{"tag", calculate_tag_str(d_)}}, - R"( -serialize_varint(data, pos, size, $tag$); -)"); - PrimitiveFieldGenerator(d_, options_) - .generate_serialization_only(p, oneof_value); - } - } -} -void OneofFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("case $1$: {\n", calculate_tag_str(d_)); - generate_deserialization_only(p, value); - format("break;\n"); - format("}\n"); -} -void OneofFieldGenerator::generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &value, - const std::string &max_size) const { - Formatter format(p); - std::string oneof_value = "std::get<" + index() + ">(" + value + ")"; - - switch (d_->cpp_type()) { - case FieldDescriptor::CPPTYPE_MESSAGE: { - p->Print( - {{"value", value}, - {"type_name", qualified_class_name(d_->message_type(), options_)}, - {"tag", std::to_string(calculate_tag(d_))}, - {"max_size", max_size}, - {"oneof_value", oneof_value}, - {"index", index()}}, - - R"( -if ($value$.index() != $index$) { - $value$.emplace<$index$>(new $type_name$()); -} -uint64_t msg_sz = 0; -ok = deserialize_varint(data, pos, $max_size$, msg_sz); -if (!ok) { - return false; -} -ok = deserialize_to(*$oneof_value$, data + pos, msg_sz); -if (!ok) { - return false; -} -pos += msg_sz; -)"); - break; - } - case FieldDescriptor::CPPTYPE_STRING: { - format("if ($1$.index() != $2$) {\n", value, index()); - format.indent(); - format("$1$.emplace<$2$>();\n", value, index()); - format.outdent(); - format("}\n"); - StringFieldGenerator(d_, options_) - .generate_deserialization_only(p, oneof_value, "str_sz", max_size); - break; - } - case FieldDescriptor::CPPTYPE_ENUM: { - format("if ($1$.index() != $2$) {\n", value, index()); - format.indent(); - format("$1$.emplace<$2$>();\n", value, index()); - format.outdent(); - format("}\n"); - EnumFieldGenerator(d_, options_) - .generate_deserialization_only(p, oneof_value, max_size); - break; - } - default: { - format("if ($1$.index() != $2$) {\n", value, index()); - format.indent(); - format("$1$.emplace<$2$>();\n", value, index()); - format.outdent(); - format("}\n"); - PrimitiveFieldGenerator(d_, options_) - .generate_deserialization_only(p, oneof_value); - } - } -} -std::string OneofFieldGenerator::cpp_type_name() const { - return "std::variant"; -} -std::string OneofFieldGenerator::pb_type_name() const { - return d_->type_name(); -} -OneofFieldGenerator::OneofFieldGenerator(const FieldDescriptor *descriptor, - const Options &options) - : FieldGenerator(descriptor, options) {} - -MessageOneofFieldGenerator::MessageOneofFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : OneofFieldGenerator(descriptor, options) {} - -void MessageOneofFieldGenerator::generate_setter_and_getter( - google::protobuf::io::Printer *p) { - auto oneof = d_->containing_oneof(); - assert(oneof); - std::string type_name = get_type_name(); - type_name = qualified_class_name(d_->message_type(), options_); - p->Print({{"name", resolve_keyword(d_->name())}, - {"type_name", type_name}, - {"field_name", resolve_keyword(oneof->name())}, - {"index", index()}}, - R"( -bool has_$name$() const { - return $field_name$.index() == $index$; -} -void set_allocated_$name$($type_name$* p) { - assert(p); - $field_name$.emplace<$index$>(p); -} -const std::unique_ptr<$type_name$>& $name$() const { - assert($field_name$.index() == $index$); - return std::get<$index$>($field_name$); -} -)"); -} -PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : OneofFieldGenerator(descriptor, options) {} -void PrimitiveOneofFieldGenerator::generate_setter_and_getter( - google::protobuf::io::Printer *p) { - auto oneof = d_->containing_oneof(); - assert(oneof); - std::string type_name = get_type_name(); - p->Print({{"name", resolve_keyword(d_->name())}, - {"type_name", type_name}, - {"field_name", resolve_keyword(oneof->name())}, - {"index", index()}}, - R"( -bool has_$name$() const { - return $field_name$.index() == $index$; -} -void set_$name$($type_name$ $name$) { - $field_name$.emplace<$index$>($name$); -} -$type_name$ $name$() const { - assert($field_name$.index() == $index$); - return std::get<$index$>($field_name$); -} -)"); -} -StringOneofFieldGenerator::StringOneofFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : OneofFieldGenerator(descriptor, options) {} -void StringOneofFieldGenerator::generate_setter_and_getter( - google::protobuf::io::Printer *p) { - auto oneof = d_->containing_oneof(); - assert(oneof); - std::string type_name = get_type_name(); - p->Print({{"name", resolve_keyword(d_->name())}, - {"type_name", type_name}, - {"field_name", resolve_keyword(oneof->name())}, - {"index", index()}}, - R"( -bool has_$name$() const { - return $field_name$.index() == $index$; -} -void set_$name$($type_name$ $name$) { - $field_name$.emplace<$index$>(std::move($name$)); -} -const $type_name$& $name$() const { - assert($field_name$.index() == $index$); - return std::get<$index$>($field_name$); -} -)"); -} -EnumOneofFieldGenerator::EnumOneofFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : OneofFieldGenerator(descriptor, options) {} -void EnumOneofFieldGenerator::generate_setter_and_getter( - google::protobuf::io::Printer *p) { - auto oneof = d_->containing_oneof(); - assert(oneof); - std::string type_name = get_type_name(); - type_name = qualified_enum_name(d_->enum_type(), options_); - p->Print({{"name", resolve_keyword(d_->name())}, - {"type_name", type_name}, - {"field_name", resolve_keyword(oneof->name())}, - {"index", index()}}, - R"( -bool has_$name$() const { - return $field_name$.index() == $index$; -} -void set_allocated_$name$($type_name$ p) { - $field_name$.emplace<$index$>(p); -} -$type_name$ $name$() const { - assert($field_name$.index() == $index$); - return std::get<$index$>($field_name$); -} -)"); -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/OneofFieldGenerator.h b/src/struct_pb/protoc-plugin/OneofFieldGenerator.h deleted file mode 100644 index 8d936d94f..000000000 --- a/src/struct_pb/protoc-plugin/OneofFieldGenerator.h +++ /dev/null @@ -1,64 +0,0 @@ -#pragma once -#include "FieldGenerator.h" -namespace struct_pb { -namespace compiler { - -class OneofFieldGenerator : public FieldGenerator { - public: - OneofFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - - void generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &value, - const std::string &max_size = "size") const; - std::string cpp_type_name() const override; - std::string pb_type_name() const override; - virtual void generate_setter_and_getter(google::protobuf::io::Printer *p){}; - - protected: - std::string index() const; -}; - -class MessageOneofFieldGenerator : public OneofFieldGenerator { - public: - MessageOneofFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - void generate_setter_and_getter(google::protobuf::io::Printer *p) override; -}; - -class StringOneofFieldGenerator : public OneofFieldGenerator { - public: - StringOneofFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - void generate_setter_and_getter(google::protobuf::io::Printer *p) override; -}; - -class EnumOneofFieldGenerator : public OneofFieldGenerator { - public: - EnumOneofFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - void generate_setter_and_getter(google::protobuf::io::Printer *p) override; -}; - -class PrimitiveOneofFieldGenerator : public OneofFieldGenerator { - public: - PrimitiveOneofFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - void generate_setter_and_getter(google::protobuf::io::Printer *p) override; -}; - -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/Options.hpp b/src/struct_pb/protoc-plugin/Options.hpp deleted file mode 100644 index 024e1f8c7..000000000 --- a/src/struct_pb/protoc-plugin/Options.hpp +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once -#include - -#include "google/protobuf/descriptor.h" -struct Options { - Options(const google::protobuf::FileDescriptor* f) : f(f) {} - bool generate_eq_op = false; - std::string ns; - const google::protobuf::FileDescriptor* f; -}; \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.cpp b/src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.cpp deleted file mode 100644 index 7966a7401..000000000 --- a/src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.cpp +++ /dev/null @@ -1,453 +0,0 @@ -#include "PrimitiveFieldGenerator.h" - -namespace struct_pb { -namespace compiler { -std::string get_type_name_help(FieldDescriptor::Type type) { - switch (type) { - case google::protobuf::FieldDescriptor::TYPE_DOUBLE: - return "double"; - case google::protobuf::FieldDescriptor::TYPE_FLOAT: - return "float"; - case google::protobuf::FieldDescriptor::TYPE_INT64: - case google::protobuf::FieldDescriptor::TYPE_SFIXED64: - case google::protobuf::FieldDescriptor::TYPE_SINT64: - return "int64_t"; - case google::protobuf::FieldDescriptor::TYPE_UINT64: - case google::protobuf::FieldDescriptor::TYPE_FIXED64: - return "uint64_t"; - case google::protobuf::FieldDescriptor::TYPE_UINT32: - case google::protobuf::FieldDescriptor::TYPE_FIXED32: - return "uint32_t"; - case google::protobuf::FieldDescriptor::TYPE_INT32: - case google::protobuf::FieldDescriptor::TYPE_SFIXED32: - case google::protobuf::FieldDescriptor::TYPE_SINT32: - return "int32_t"; - case google::protobuf::FieldDescriptor::TYPE_BOOL: - return "bool"; - default: { - // can't reach, dead path - return "not support"; - } - } -} -PrimitiveFieldGenerator::PrimitiveFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : FieldGenerator(descriptor, options) {} -void PrimitiveFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (is_optional()) { - format("if ($1$.has_value()) {\n", value); - format.indent(); - format("total += $1$ + ", calculate_tag_size(d_)); - generate_calculate_size_only(p, value + ".value()"); - format(";\n"); - format.outdent(); - format("}\n"); - } - else { - if (can_ignore_default_value) { - format("if ($1$ != 0) {\n", value); - format.indent(); - format("total += $1$ + ", calculate_tag_size(d_)); - generate_calculate_size_only(p, value); - format(";\n"); - format.outdent(); - format("}\n"); - } - else { - format("total += $1$ + ", calculate_tag_size(d_)); - generate_calculate_size_only(p, value); - format(";\n"); - } - } -} -void PrimitiveFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - if (is_varint(d_)) { - if (is_sint(d_)) { - format("calculate_varint_size(encode_zigzag($1$))", value); - } - else if (is_bool(d_)) { - format("calculate_varint_size(static_cast($1$))", value); - } - else { - format("calculate_varint_size($1$)", value); - } - } - else if (is_i64(d_)) { - format("8"); - } - else if (is_i32(d_)) { - format("4"); - } -} - -std::string PrimitiveFieldGenerator::cpp_type_name() const { - std::string type_name = get_type_name_help(d_->type()); - if (is_optional()) { - type_name = "std::optional<" + type_name + ">"; - } - return type_name; -} -void PrimitiveFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (is_optional()) { - format("if ($1$.has_value()) {\n", value); - format.indent(); - format("serialize_varint(data, pos, size, $1$);\n", calculate_tag_str(d_)); - generate_serialization_only(p, value + ".value()"); - format("\n"); - format.outdent(); - format("}\n"); - } - else { - if (can_ignore_default_value) { - format("if ($1$ != 0) {\n", value); - format.indent(); - format("serialize_varint(data, pos, size, $1$);\n", - calculate_tag_str(d_)); - generate_serialization_only(p, value); - format("\n"); - format.outdent(); - format("}\n"); - } - else { - format("serialize_varint(data, pos, size, $1$);\n", - calculate_tag_str(d_)); - generate_serialization_only(p, value); - } - } -} -void PrimitiveFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - if (is_varint(d_)) { - if (is_sint(d_)) { - format("serialize_varint(data, pos, size, encode_zigzag($1$));", value); - } - else if (is_bool(d_)) { - format("serialize_varint(data, pos, size, static_cast($1$));", - value); - } - else { - if (d_->cpp_type() != FieldDescriptor::CPPTYPE_UINT64) { - format("serialize_varint(data, pos, size, static_cast($1$));", - value); - } - else { - format("serialize_varint(data, pos, size, $1$);", value); - } - } - } - else if (is_i64(d_) || is_i32(d_)) { - std::size_t sz = is_i64(d_) ? 8 : 4; - p->Print({{"value", value}, {"sz", std::to_string(sz)}}, R"( -std::memcpy(data + pos, &$value$, $sz$); -pos += $sz$; -)"); - } -} -void PrimitiveFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("case $1$: {\n", calculate_tag_str(d_)); - format.indent(); - generate_deserialization_only(p, value); - format("break;\n"); - format.outdent(); - format("}\n"); -} -void PrimitiveFieldGenerator::generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &output, - const std::string &max_size) const { - if (is_varint(d_)) { - p->Print({{"output", output}, - {"type_name", get_type_name_help(d_->type())}, - {"max_size", max_size}}, - R"( -uint64_t varint_tmp = 0; -ok = deserialize_varint(data, pos, $max_size$, varint_tmp); -if (!ok) { - return false; -} -)"); - if (is_sint(d_)) { - if (is_sint32(d_)) { - p->Print( - { - - {"output", output}, - {"type_name", get_type_name_help(d_->type())}, - {"max_size", max_size}}, - R"( -$output$ = static_cast<$type_name$>(decode_zigzag(uint32_t(varint_tmp))); -)"); - } - else { - p->Print( - { - - {"output", output}, - {"type_name", get_type_name_help(d_->type())}, - {"max_size", max_size}}, - R"( -$output$ = static_cast<$type_name$>(decode_zigzag(varint_tmp)); -)"); - } - } - else if (is_bool(d_)) { - p->Print( - { - - {"output", output}, - {"type_name", get_type_name_help(d_->type())}, - {"max_size", max_size}}, - R"( -$output$ = static_cast<$type_name$>(varint_tmp); -)"); - } - else { - p->Print( - { - - {"output", output}, - {"type_name", get_type_name_help(d_->type())}, - {"max_size", max_size}}, - R"( -$output$ = varint_tmp; -)"); - } - } - else if (is_i64(d_) || is_i32(d_)) { - auto sz = is_i64(d_) ? 8 : 4; - p->Print( - { - - {"output", output}, - {"type_name", get_type_name_help(d_->type())}, - {"max_size", max_size}, - {"sz", std::to_string(sz)}}, - R"( -if (pos + $sz$ > $max_size$) { - return false; -} -$type_name$ fixed_tmp = 0; -std::memcpy(&fixed_tmp, data + pos, $sz$); -pos += $sz$; -$output$ = fixed_tmp; -)"); - } -} -RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator( - const FieldDescriptor *descriptor, const Options &options) - : FieldGenerator(descriptor, options) {} -void RepeatedPrimitiveFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - PrimitiveFieldGenerator g(d_, options_); - if (is_packed()) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - generate_calculate_packed_size_only(p, value); - format( - "total += $1$ + calculate_varint_size(container_total) + " - "container_total;\n", - calculate_tag_size(d_)); - format.outdent(); - format("}\n"); - } - else { - format("if (!$1$.empty()) {\n", value); - format.indent(); - generate_calculate_unpacked_size_only(p, value); - format("total += container_total;\n"); - format.outdent(); - format("}\n"); - } -} -bool RepeatedPrimitiveFieldGenerator::is_packed() const { - return d_->is_packable() && d_->is_packed(); -} -std::string RepeatedPrimitiveFieldGenerator::cpp_type_name() const { - return "std::vector<" + get_type_name_help(d_->type()) + ">"; -} -void RepeatedPrimitiveFieldGenerator::generate_calculate_packed_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - PrimitiveFieldGenerator g(d_, options_); - if (is_varint(d_)) { - p->Print({{"value", value}}, - R"( -std::size_t container_total = 0; -for(const auto& e: $value$) { - container_total += )"); - g.generate_calculate_size_only(p, "e"); - format(";\n"); - format("}\n"); - } - else if (is_i64(d_) || is_i32(d_)) { - auto sz = is_i64(d_) ? 8 : 4; - p->Print({{"sz", std::to_string(sz)}, {"value", value}}, R"( -std::size_t container_total = $sz$ * $value$.size(); -)"); - } -} -void RepeatedPrimitiveFieldGenerator::generate_calculate_unpacked_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - PrimitiveFieldGenerator g(d_, options_); - Formatter format(p); - if (is_varint(d_)) { - p->Print({{"value", value}, {"tag_sz", calculate_tag_size(d_, true)}}, - R"( -std::size_t container_total = 0; -for(const auto& e: $value$) { - container_total += $tag_sz$; - container_total += )"); - g.generate_calculate_size_only(p, "e"); - format(";\n"); - format("}\n"); - } - else if (is_i64(d_) || is_i32(d_)) { - auto sz = is_i64(d_) ? 8 : 4; - p->Print({{"sz", std::to_string(sz)}, - {"value", value}, - {"tag_sz", calculate_tag_size(d_, true)}}, - R"( -std::size_t container_total = ($tag_sz$ + $sz$) * $value$.size(); -)"); - } -} -void RepeatedPrimitiveFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - PrimitiveFieldGenerator g(d_, options_); - Formatter format(p); - if (is_packed()) { - if (is_varint(d_)) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - format("serialize_varint(data, pos, size, $1$);\n", - calculate_tag_str(d_)); - generate_calculate_packed_size_only(p, value); - format("serialize_varint(data, pos, size, container_total);\n"); - format("for(const auto& v: $1$) {\n", value); - format.indent(); - g.generate_serialization_only(p, "v"); - format.outdent(); - format("}\n"); - format.outdent(); - format("}\n"); - } - else if (is_i64(d_) || is_i32(d_)) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - format("serialize_varint(data, pos, size, $1$);\n", - calculate_tag_str(d_)); - generate_calculate_packed_size_only(p, value); - format("serialize_varint(data, pos, size, container_total);\n"); - format("std::memcpy(data + pos, $1$.data(), container_total);\n", value); - format.outdent(); - format("}\n"); - } - } - else { - format("for(const auto& v: $1$) {\n", value); - format.indent(); - format("serialize_varint(data, pos, size, $1$);\n", - calculate_tag_str(d_, true)); - g.generate_serialization_only(p, "v"); - format.outdent(); - format("}\n"); - } -} -void RepeatedPrimitiveFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("case $1$: {\n", unpacked_tag()); - format.indent(); - format("$1$ e{};\n", get_type_name_help(d_->type())); - generate_deserialization_unpacked_only(p, "e"); - format("$1$.push_back(e);\n", value); - format("break;\n"); - format.outdent(); - format("}\n"); - - format("case $1$: {\n", packed_tag()); - format.indent(); - format("uint64_t sz = 0;\n"); - format("ok = deserialize_varint(data, pos, size, sz);\n"); - format("if (!ok) {\n"); - format.indent(); - format("return false;\n"); - format.outdent(); - format("}\n"); - format("std::size_t cur_max_size = pos + sz;\n"); - generate_deserialization_packed_only(p, value, "cur_max_size"); - format("break;\n"); - format.outdent(); - format("}\n"); -} -void RepeatedPrimitiveFieldGenerator::generate_deserialization_packed_only( - google::protobuf::io::Printer *p, const std::string &value, - const std::string &max_size) const { - if (is_varint(d_)) { - Formatter format(p); - format("while (pos < $1$) {\n", max_size); - format.indent(); - format("$1$ e{};\n", get_type_name_help(d_->type())); - PrimitiveFieldGenerator g(d_, options_); - g.generate_deserialization_only(p, "e"); - format("$1$.push_back(e);\n", value); - format.outdent(); - format("}\n"); - } - else if (is_i64(d_) || is_i32(d_)) { - auto sz = is_i64(d_) ? 8 : 4; - p->Print({{"value", value}, {"sz", std::to_string(sz)}}, R"( -int count = sz / $sz$; -if ($sz$ * count != sz) { - return false; -} -if (pos + sz > size) { - return false; -} -$value$.resize(count); -std::memcpy($value$.data(), data + pos, sz); -pos += sz; -)"); - } -} -std::string RepeatedPrimitiveFieldGenerator::packed_tag() const { - uint32_t number = d_->number(); - uint32_t wire_type = 2; - auto tag = number << 3 | wire_type; - return std::to_string(tag); -} -std::string RepeatedPrimitiveFieldGenerator::unpacked_tag() const { - uint32_t number = d_->number(); - uint32_t wire_type = 0; - if (is_varint(d_)) { - wire_type = 0; - } - else if (is_i64(d_)) { - wire_type = 1; - } - else if (is_i32(d_)) { - wire_type = 5; - } - auto tag = number << 3 | wire_type; - return std::to_string(tag); -} -void RepeatedPrimitiveFieldGenerator::generate_deserialization_unpacked_only( - google::protobuf::io::Printer *p, const std::string &output) const { - PrimitiveFieldGenerator g(d_, options_); - g.generate_deserialization_only(p, output); -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.h b/src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.h deleted file mode 100644 index fa06991fd..000000000 --- a/src/struct_pb/protoc-plugin/PrimitiveFieldGenerator.h +++ /dev/null @@ -1,59 +0,0 @@ -#pragma once -#include "FieldGenerator.h" -#include "google/protobuf/descriptor.h" -namespace struct_pb { -namespace compiler { -using namespace google::protobuf; -class PrimitiveFieldGenerator : public FieldGenerator { - public: - PrimitiveFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - PrimitiveFieldGenerator(const PrimitiveFieldGenerator &) = delete; - PrimitiveFieldGenerator &operator=(const PrimitiveFieldGenerator &) = delete; - std::string cpp_type_name() const override; - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - void generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &output, - const std::string &max_size = "size") const; -}; -class RepeatedPrimitiveFieldGenerator : public FieldGenerator { - public: - RepeatedPrimitiveFieldGenerator(const FieldDescriptor *descriptor, - const Options &options); - std::string cpp_type_name() const override; - void generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value = {}, - bool can_ignore_default_value = true) const override; - void generate_calculate_packed_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_calculate_unpacked_size_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - void generate_deserialization_packed_only(google::protobuf::io::Printer *p, - const std::string &value, - const std::string &max_size) const; - void generate_deserialization_unpacked_only(google::protobuf::io::Printer *p, - const std::string &output) const; - - private: - bool is_packed() const; - std::string packed_tag() const; - std::string unpacked_tag() const; -}; -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/StringFieldGenerator.cpp b/src/struct_pb/protoc-plugin/StringFieldGenerator.cpp deleted file mode 100644 index 5d7c5aee1..000000000 --- a/src/struct_pb/protoc-plugin/StringFieldGenerator.cpp +++ /dev/null @@ -1,185 +0,0 @@ -#include "StringFieldGenerator.h" - -namespace struct_pb { -namespace compiler { -StringFieldGenerator::StringFieldGenerator(const FieldDescriptor *field, - const Options &options) - : FieldGenerator(field, options) {} -void StringFieldGenerator::generate_calculate_size_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("$1$.size()", value); -} -void StringFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - auto tag_sz = calculate_tag_size(d_); - if (is_optional()) { - format("if ($1$.has_value()) {\n", value); - format.indent(); - format("total += $1$ + calculate_varint_size($2$->size()) + $2$->size();\n", - tag_sz, value); - format.outdent(); - format("}\n"); - } - else { - if (can_ignore_default_value) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - format("total += $1$ + calculate_varint_size($2$.size()) + $2$.size();\n", - tag_sz, value); - format.outdent(); - format("}\n"); - } - else { - format("total += $1$ + calculate_varint_size($2$.size()) + $2$.size();\n", - tag_sz, value); - } - } -} -void StringFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (is_optional()) { - format("if ($1$.has_value()) {\n", value); - format.indent(); - generate_serialization_only(p, value + ".value()"); - format.outdent(); - format("}\n"); - } - else { - if (can_ignore_default_value) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - generate_serialization_only(p, value); - format.outdent(); - format("}\n"); - } - else { - generate_serialization_only(p, value); - } - } -} -void StringFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("serialize_varint(data, pos, size, $1$);\n", calculate_tag_str(d_)); - format("serialize_varint(data, pos, size, $1$.size());\n", value); - format("std::memcpy(data + pos, $1$.data(), $1$.size());\n", value); - format("pos += $1$.size();\n", value); -} -std::string StringFieldGenerator::cpp_type_name() const { - if (d_->has_presence()) { - return "std::optional"; - } - return "std::string"; -} -void StringFieldGenerator::generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &output, - const std::string &sz, const std::string &max_size) const { - p->Print({{"output", output}, {"sz", sz}, {"max_size", max_size}}, - R"(uint64_t $sz$ = 0; -ok = deserialize_varint(data, pos, $max_size$, $sz$); -if (!ok) { - return false; -} -$output$.resize($sz$); -if (pos + $sz$ > $max_size$) { - return false; -} -std::memcpy($output$.data(), data+pos, $sz$); -pos += $sz$; -)"); -} -void StringFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("case $1$: {\n", calculate_tag_str(d_)); - format.indent(); - if (is_optional()) { - format("if (!$1$.has_value()) {\n", value); - format.indent(); - format("$1$ = std::string();\n", value); - format.outdent(); - format("}\n"); - generate_deserialization_only(p, value + ".value()"); - } - else { - generate_deserialization_only(p, value); - } - format("break;\n"); - format.outdent(); - format("}\n"); -} -RepeatedStringFieldGenerator::RepeatedStringFieldGenerator( - const FieldDescriptor *field, const Options &options) - : FieldGenerator(field, options) {} -std::string RepeatedStringFieldGenerator::cpp_type_name() const { - return "std::vector"; -} -void RepeatedStringFieldGenerator::generate_calculate_size( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - format("for (const auto& s: $1$) {\n", value); - format.indent(); - format("total += $1$ + calculate_varint_size(s.size()) + s.size();\n", - calculate_tag_size(d_)); - format.outdent(); - format("}\n"); -} -void RepeatedStringFieldGenerator::generate_calculate_only( - google::protobuf::io::Printer *p, const std::string &value, - const std::string &output) const { - p->Print({{"value", value}, - {"tag_sz", calculate_tag_size(d_)}, - {"output", output}}, - R"( -std::size_t $output$ = 0; -for (const auto& s: $value$) { - $output$ += $tag_sz$ + calculate_varint_size(s.size()) + s.size(); -} -)"); -} -void RepeatedStringFieldGenerator::generate_serialization( - google::protobuf::io::Printer *p, const std::string &value, - bool can_ignore_default_value) const { - Formatter format(p); - if (can_ignore_default_value) { - format("if (!$1$.empty()) {\n", value); - format.indent(); - generate_serialization_only(p, value); - format.outdent(); - format("}\n"); - } - else { - generate_serialization_only(p, value); - } -} -void RepeatedStringFieldGenerator::generate_serialization_only( - google::protobuf::io::Printer *p, const std::string &value) const { - Formatter format(p); - format("for(const auto& s: $1$) {\n", value); - format.indent(); - StringFieldGenerator g(d_, options_); - g.generate_serialization_only(p, "s"); - format.outdent(); - format("}\n"); -} -void RepeatedStringFieldGenerator::generate_deserialization( - google::protobuf::io::Printer *p, const std::string &value) const { - StringFieldGenerator g(d_, options_); - Formatter format(p); - format("case $1$: {\n", calculate_tag_str(d_)); - format.indent(); - format("std::string tmp_str;\n"); - g.generate_deserialization_only(p, "tmp_str"); - format("$1$.push_back(std::move(tmp_str));\n", value); - format("break;\n"); - format.outdent(); - format("}\n"); -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/StringFieldGenerator.h b/src/struct_pb/protoc-plugin/StringFieldGenerator.h deleted file mode 100644 index 3d1fdc3e1..000000000 --- a/src/struct_pb/protoc-plugin/StringFieldGenerator.h +++ /dev/null @@ -1,46 +0,0 @@ -#pragma once -#include "FieldGenerator.h" -namespace struct_pb { -namespace compiler { - -class StringFieldGenerator : public FieldGenerator { - public: - StringFieldGenerator(const FieldDescriptor *field, const Options &options); - std::string cpp_type_name() const override; - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_size_only(google::protobuf::io::Printer *p, - const std::string &value = {}) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - void generate_deserialization_only( - google::protobuf::io::Printer *p, const std::string &output, - const std::string &sz = "sz", const std::string &max_size = "size") const; -}; -class RepeatedStringFieldGenerator : public FieldGenerator { - public: - RepeatedStringFieldGenerator(const FieldDescriptor *field, - const Options &options); - void generate_calculate_size(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_calculate_only(google::protobuf::io::Printer *p, - const std::string &value, - const std::string &output) const; - void generate_serialization(google::protobuf::io::Printer *p, - const std::string &value, - bool can_ignore_default_value) const override; - void generate_serialization_only(google::protobuf::io::Printer *p, - const std::string &value) const; - void generate_deserialization(google::protobuf::io::Printer *p, - const std::string &value) const override; - std::string cpp_type_name() const override; -}; -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/StructGenerator.cpp b/src/struct_pb/protoc-plugin/StructGenerator.cpp deleted file mode 100644 index 3eafc68c0..000000000 --- a/src/struct_pb/protoc-plugin/StructGenerator.cpp +++ /dev/null @@ -1,71 +0,0 @@ -#include "StructGenerator.h" - -#include - -#include "FileGenerator.h" -#include "Options.hpp" -#include "google/protobuf/descriptor.pb.h" -#include "helpers.hpp" -namespace struct_pb { -namespace compiler { -bool StructGenerator::Generate( - const google::protobuf::FileDescriptor *file, const std::string ¶meter, - google::protobuf::compiler::GeneratorContext *generator_context, - std::string *error) const { - std::vector> options; - google::protobuf::compiler::ParseGeneratorParameter(parameter, &options); - Options struct_pb_options(file); - for (const auto &option : options) { - const auto &key = option.first; - const auto &value = option.second; - if (key == "generate_eq_op") { - struct_pb_options.generate_eq_op = true; - } - else if (key == "namespace") { - struct_pb_options.ns = value; - } - else { - *error = "Unknown generator option: " + key; - return false; - } - } - if (struct_pb_options.ns.empty()) { - struct_pb_options.ns = file->package(); - } - auto basename = strip_proto(file->name()); - FileGenerator file_generator(file, struct_pb_options); - // generate xxx.struct_pb.h - { - std::unique_ptr output( - generator_context->Open(basename + ".struct_pb.h")); - google::protobuf::io::Printer p(output.get(), '$'); - p.Print({{"parameter", parameter}}, R"(// protoc generate parameter -// clang-format off -// $parameter$ -// ========================= -#pragma once - -)"); - file_generator.generate_header(&p); - } - // generate xxx.struct_pb.cc - { - std::unique_ptr output( - generator_context->Open(basename + ".struct_pb.cc")); - google::protobuf::io::Printer p(output.get(), '$'); - p.Print( - {{"parameter", parameter}, {"header_file", basename + ".struct_pb.h"}}, - R"(// protoc generate parameter -// clang-format off -// $parameter$ -// ========================= -#include "$header_file$" -#include "ylt/struct_pb/struct_pb_impl.hpp" -)"); - Formatter format(&p); - file_generator.generate_source(&p); - } - return true; -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/StructGenerator.h b/src/struct_pb/protoc-plugin/StructGenerator.h deleted file mode 100644 index f8748d975..000000000 --- a/src/struct_pb/protoc-plugin/StructGenerator.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include -namespace struct_pb { -namespace compiler { - -class StructGenerator : public google::protobuf::compiler::CodeGenerator { - public: - bool Generate(const google::protobuf::FileDescriptor *file, - const std::string ¶meter, - google::protobuf::compiler::GeneratorContext *generator_context, - std::string *error) const override; -}; - -} // namespace compiler -} // namespace struct_pb diff --git a/src/struct_pb/protoc-plugin/helpers.cpp b/src/struct_pb/protoc-plugin/helpers.cpp deleted file mode 100644 index e67fd4c60..000000000 --- a/src/struct_pb/protoc-plugin/helpers.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include "helpers.hpp" - -#include -#include - -#include "google/protobuf/io/printer.h" -namespace struct_pb { -namespace compiler { -// https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string -template -void split(const std::string &s, char delim, Out result) { - std::istringstream iss(s); - std::string item; - while (std::getline(iss, item, delim)) { - *result++ = item; - } -} - -static std::vector split(const std::string &s, char delim) { - std::vector elems; - split(s, delim, std::back_inserter(elems)); - return elems; -} -NamespaceOpener::NamespaceOpener(google::protobuf::io::Printer *p, - const std::string &package) - : p_(p) { - ns_ = split(package, '.'); -} -NamespaceOpener::~NamespaceOpener() {} -void NamespaceOpener::open() const { - for (const auto &ns : ns_) { - p_->Print({{"ns", ns}}, R"( -namespace $ns$ { -)"); - } -} -void NamespaceOpener::close() const { - for (int i = 0; i < ns_.size(); ++i) { - auto ns = ns_[ns_.size() - i - 1]; - p_->Print({{"ns", ns}}, R"( -} // namespace $ns$ -)"); - } -} -// from std::string_view ends_with -bool string_ends_with(std::string_view s, std::string_view suffix) { - return s.size() >= suffix.size() && - s.compare(s.size() - suffix.size(), std::string_view::npos, suffix) == - 0; -} -std::string_view string_strip_suffix(const std::string_view s, - const std::string_view suffix) { - if (string_ends_with(s, suffix)) { - return s.substr(0, s.size() - suffix.size()); - } - return s; -} -std::string strip_proto(const std::string &filename) { - if (string_ends_with(filename, ".protodevel")) { - return std::string(string_strip_suffix(filename, ".protodevel")); - } - else { - return std::string(string_strip_suffix(filename, ".proto")); - } -} -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/helpers.hpp b/src/struct_pb/protoc-plugin/helpers.hpp deleted file mode 100644 index ac3f1dee7..000000000 --- a/src/struct_pb/protoc-plugin/helpers.hpp +++ /dev/null @@ -1,279 +0,0 @@ -#pragma once -#include -#include -#include - -#include "Options.hpp" -#include "google/protobuf/descriptor.h" -#include "google/protobuf/descriptor.pb.h" -#include "google/protobuf/io/printer.h" -namespace struct_pb { -namespace compiler { -using namespace google::protobuf; -using namespace google::protobuf::compiler; - -inline bool is_map_entry(const google::protobuf::Descriptor *descriptor) { - return descriptor->options().map_entry(); -} - -void flatten_messages_in_file( - const google::protobuf::FileDescriptor *file, - std::vector *result); -inline std::vector -flatten_messages_in_file(const google::protobuf::FileDescriptor *file) { - std::vector ret; - flatten_messages_in_file(file, &ret); - return ret; -} -template -void for_each_message(const google::protobuf::Descriptor *descriptor, - F &&func) { - for (int i = 0; i < descriptor->nested_type_count(); ++i) { - for_each_message(descriptor->nested_type(i), std::forward(func)); - } - func(descriptor); -} - -template -void for_each_message(const google::protobuf::FileDescriptor *descriptor, - F &&func) { - for (int i = 0; i < descriptor->message_type_count(); ++i) { - for_each_message(descriptor->message_type(i), std::forward(func)); - } -} - -inline void flatten_messages_in_file( - const google::protobuf::FileDescriptor *file, - std::vector *result) { - for (int i = 0; i < file->message_type_count(); ++i) { - for_each_message(file->message_type(i), - [&](const google::protobuf::Descriptor *descriptor) { - if (is_map_entry(descriptor)) { - return; - } - result->push_back(descriptor); - }); - } -} -inline std::string resolve_keyword(const std::string &name) { - // clang-format off - static std::set keyword_set{ - // - "NULL", - "alignas", - "alignof", - "and", - "and_eq", - "asm", - "auto", - "bitand", - "bitor", - "bool", - "break", - "case", - "catch", - "char", - "class", - "compl", - "const", - "constexpr", - "const_cast", - "continue", - "decltype", - "default", - "delete", - "do", - "double", - "dynamic_cast", - "else", - "enum", - "explicit", - "export", - "extern", - "false", - "float", - "for", - "friend", - "goto", - "if", - "inline", - "int", - "long", - "mutable", - "namespace", - "new", - "noexcept", - "not", - "not_eq", - "nullptr", - "operator", - "or", - "or_eq", - "private", - "protected", - "public", - "register", - "reinterpret_cast", - "return", - "short", - "signed", - "sizeof", - "static", - "static_assert", - "static_cast", - "struct", - "switch", - "template", - "this", - "thread_local", - "throw", - "true", - "try", - "typedef", - "typeid", - "typename", - "union", - "unsigned", - "using", - "virtual", - "void", - "volatile", - "wchar_t", - "while", - "xor", - "xor_eq", - "char8_t", - "char16_t", - "char32_t", - "concept", - "consteval", - "constinit", - "co_await", - "co_return", - "co_yield", - "requires", - // typedef - "uint32_t", - "int32_t", - "uint64_t", - "int64_t", - "size_t", - "memset" - }; - // clang-format on - auto it = keyword_set.find(name); - if (it == keyword_set.end()) { - return name; - } - return name + "_"; -} -inline std::string class_name(const google::protobuf::Descriptor *descriptor) { - // assert(descriptor); - auto parent = descriptor->containing_type(); - std::string ret; - if (parent) { - ret += class_name(parent) + "::"; - } - ret += resolve_keyword(descriptor->name()); - return resolve_keyword(ret); -} -inline std::string enum_name( - const google::protobuf::EnumDescriptor *descriptor) { - auto parent = descriptor->containing_type(); - std::string ret; - if (parent) { - ret += class_name(parent) + "::"; - } - ret += resolve_keyword(descriptor->name()); - return resolve_keyword(ret); -} -// https://stackoverflow.com/questions/2896600/how-to-replace-all-occurrences-of-a-character-in-string -inline std::string ReplaceAll(std::string str, const std::string &from, - const std::string &to) { - size_t start_pos = 0; - while ((start_pos = str.find(from, start_pos)) != std::string::npos) { - str.replace(start_pos, from.length(), to); - start_pos += - to.length(); // Handles case where 'to' is a substring of 'from' - } - return str; -} -inline std::string dots_to_colons(std::string name) { - return ReplaceAll(name, ".", "::"); -} -inline std::string get_namespace(const std::string &package) { - if (package.empty()) { - return ""; - } - return "::" + dots_to_colons(package); -} - -inline std::string get_namespace(const google::protobuf::FileDescriptor *file, - const Options &options) { - if (file == options.f) { - return get_namespace(options.ns); - } - else { - return get_namespace(file->package()); - } -} - -inline std::string qualified_file_level_symbol( - const google::protobuf::FileDescriptor *file, const std::string &name, - const Options &options) { - // if (options.ns.empty()) { - // return absl::StrCat("::", name); - // } - return get_namespace(file, options) + "::" + name; -} - -inline std::string qualified_class_name(const google::protobuf::Descriptor *d, - const Options &options) { - return qualified_file_level_symbol(d->file(), class_name(d), options); -} - -inline std::string qualified_enum_name( - const google::protobuf::EnumDescriptor *d, const Options &options) { - return qualified_file_level_symbol(d->file(), enum_name(d), options); -} - -class Formatter { - public: - Formatter(google::protobuf::io::Printer *printer) : printer_(printer) {} - void indent() const { printer_->Indent(); } - void outdent() const { printer_->Outdent(); } - template - void operator()(const char *format, const Args &...args) const { - printer_->FormatInternal({ToString(args)...}, vars_, format); - } - - private: - static std::string ToString(const std::string &s) { return s; } - template ::value>::type> - static std::string ToString(I x) { - return std::to_string(x); - } - - private: - google::protobuf::io::Printer *printer_; - std::map vars_; -}; - -class NamespaceOpener { - public: - NamespaceOpener(google::protobuf::io::Printer *p, - const std::string &package = {}); - ~NamespaceOpener(); - - public: - void open() const; - void close() const; - - private: - std::vector ns_; - google::protobuf::io::Printer *p_; -}; -std::string strip_proto(const std::string &filename); -} // namespace compiler -} // namespace struct_pb \ No newline at end of file diff --git a/src/struct_pb/protoc-plugin/main.cpp b/src/struct_pb/protoc-plugin/main.cpp deleted file mode 100644 index 3ef44008f..000000000 --- a/src/struct_pb/protoc-plugin/main.cpp +++ /dev/null @@ -1,9 +0,0 @@ -#include - -#include "StructGenerator.h" -using namespace struct_pb::compiler; -using namespace google::protobuf::compiler; -int main(int argc, char* argv[]) { - StructGenerator generator; - return PluginMain(argc, argv, &generator); -} \ No newline at end of file diff --git a/src/struct_pb/tests/CMakeLists.txt b/src/struct_pb/tests/CMakeLists.txt deleted file mode 100644 index 82985e7b0..000000000 --- a/src/struct_pb/tests/CMakeLists.txt +++ /dev/null @@ -1,55 +0,0 @@ -set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/tests) -find_package(Protobuf QUIET) -if (Protobuf_FOUND) -add_executable(test_struct_pb - test_pb.cpp - test_pb_oneof.cpp - test_pb_benchmark_struct.cpp - test_pb_bad_identifiers.cpp - ) -target_sources(test_struct_pb PRIVATE - main.cpp - ) -add_test(NAME test_struct_pb COMMAND test_struct_pb) -target_include_directories(test_struct_pb PUBLIC ${yaLanTingLibs_SOURCE_DIR}/src/struct_pack/benchmark) - target_compile_definitions(test_struct_pb PRIVATE HAVE_PROTOBUF) - target_link_libraries(test_struct_pb PRIVATE protobuf::libprotobuf) - # generate .pb.cc .pb.h - protobuf_generate_cpp(PROTO_SRCS - PROTO_HDRS - test_pb.proto - data_def.proto - ) - target_include_directories(test_struct_pb PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) - target_sources(test_struct_pb PRIVATE - ${PROTO_SRCS} - ${PROTO_HDRS} - ) - protobuf_generate_struct_pb(STRUCT_PB_PROTO_SRCS - STRUCT_PB_PROTO_HDRS - test_pb.proto - OPTION "generate_eq_op=true,namespace=test_struct_pb" - ) - target_sources(test_struct_pb PRIVATE - ${STRUCT_PB_PROTO_SRCS} - ${STRUCT_PB_PROTO_HDRS} - ) - protobuf_generate_struct_pb(STRUCT_PB_TEST_BENCHMARK_PROTO_SRCS - STRUCT_PB_TEST_BENCHMARK_PROTO_HDRS - data_def.proto - OPTION "namespace=struct_pb_sample" - ) - target_sources(test_struct_pb PRIVATE - ${STRUCT_PB_TEST_BENCHMARK_PROTO_SRCS} - ${STRUCT_PB_TEST_BENCHMARK_PROTO_HDRS} - ) - protobuf_generate_struct_pb(STRUCT_PB_PROTO_SRCS2 - STRUCT_PB_PROTO_HDRS2 - test_bad_identifiers.proto - test_large_enum_value.proto - ) - target_sources(test_struct_pb PRIVATE - ${STRUCT_PB_PROTO_SRCS2} - ${STRUCT_PB_PROTO_HDRS2} - ) -endif () \ No newline at end of file diff --git a/src/struct_pb/tests/data_def.proto b/src/struct_pb/tests/data_def.proto deleted file mode 100644 index 4083d7002..000000000 --- a/src/struct_pb/tests/data_def.proto +++ /dev/null @@ -1,60 +0,0 @@ -syntax = "proto3"; - -package mygame; - -option optimize_for = SPEED; -option cc_enable_arenas = true; - -message Vec3 { - float x = 1; - float y = 2; - float z = 3; -} - -message Weapon { - string name = 1; - int32 damage = 2; -} - -message Monster { - Vec3 pos = 1; - int32 mana = 2; - int32 hp = 3; - string name = 4; - bytes inventory = 5; - enum Color { - Red = 0; - Green = 1; - Blue = 2; - } - Color color = 6; - repeated Weapon weapons = 7; - Weapon equipped = 8; - repeated Vec3 path = 9; -} - -message Monsters { - repeated Monster monsters = 1; -} - -message rect32 { - int32 x = 1; - int32 y = 2; - int32 width = 3; - int32 height = 4; -} - -message rect32s { - repeated rect32 rect32_list = 1; -} - -message person { - int32 id = 1; - string name = 2; - int32 age = 3; - double salary = 4; -} - -message persons { - repeated person person_list = 1; -} \ No newline at end of file diff --git a/src/struct_pb/tests/helper.hpp b/src/struct_pb/tests/helper.hpp deleted file mode 100644 index bbb4477c2..000000000 --- a/src/struct_pb/tests/helper.hpp +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once -#include - -#include "data_def.struct_pb.h" -#include "hex_printer.hpp" -#include "test_pb.struct_pb.h" -#include "ylt/struct_pb.hpp" -#ifdef HAVE_PROTOBUF -#include "google/protobuf/repeated_field.h" -#endif - -template > -void check_self(const T& t, std::optional buf_opt = {}) { - auto size = struct_pb::internal::get_needed_size(t); - if (buf_opt.has_value()) { - REQUIRE(buf_opt.value().size() == size); - } - auto b = struct_pb::serialize(t); - if (buf_opt.has_value()) { - CHECK(hex_helper(buf_opt.value()) == hex_helper(b)); - } - T d_t{}; - auto ok = struct_pb::deserialize_to(d_t, b); - REQUIRE(ok); - CHECK(Pred()(t, d_t)); -} - -#ifdef HAVE_PROTOBUF -template -struct PB_equal { - constexpr bool operator()(const T& t, const PB_T& pb_t) const { - return t == pb_t; - } -}; -template > -void check_with_protobuf(const T& t, const PB_T& pb_t) { - auto pb_buf = pb_t.SerializeAsString(); - auto size = struct_pb::internal::get_needed_size(t); - REQUIRE(size == pb_buf.size()); - - std::string b = struct_pb::serialize(t); - CHECK(hex_helper(b) == hex_helper(pb_buf)); - - CHECK(Pred()(t, pb_t)); - T d_t{}; - auto ok = struct_pb::deserialize_to(d_t, b); - REQUIRE(ok); - CHECK(Pred()(d_t, pb_t)); -} -template -bool operator==(const std::vector& a, - const google::protobuf::RepeatedPtrField& b) { - if (a.size() != b.size()) { - return false; - } - auto sz = a.size(); - for (int i = 0; i < sz; ++i) { - if (!PB_equal()(a[i], b.at(i))) { - return false; - } - } - return true; -} -template -bool operator==(const std::vector& a, - const google::protobuf::RepeatedField& b) { - if (a.size() != b.size()) { - return false; - } - auto sz = a.size(); - for (int i = 0; i < sz; ++i) { - if (a[i] != b.at(i)) { - return false; - } - } - return true; -} -#endif \ No newline at end of file diff --git a/src/struct_pb/tests/hex_printer.hpp b/src/struct_pb/tests/hex_printer.hpp deleted file mode 100644 index 3e6cd4f8c..000000000 --- a/src/struct_pb/tests/hex_printer.hpp +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright (c) 2023, Alibaba Group Holding Limited; - * - * 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. - */ -#pragma once -#include -#include -// useful for debugging -inline void print_hex(uint8_t v) { - static std::string hex = "0123456789abcedf"; - if (v < 16) { - std::cout << "0"; - std::cout << hex[v]; - } - else { - std::size_t first = v / 16; - std::size_t last = v % 16; - std::cout << hex[first] << hex[last]; - } -} -inline void print_hex(std::string_view sv) { - for (char ch : sv) { - uint8_t v = static_cast(ch); - print_hex(v); - std::cout << " "; - } - std::cout << std::endl; -} -struct hex_helper { - hex_helper(std::string_view sv) : sv(sv) {} - friend std::ostream& operator<<(std::ostream& os, const hex_helper& helper) { - static std::string hex = "0123456789abcedf"; - auto to_hex = [&os](std::string_view hex, uint8_t v) { - if (v < 16) { - os << "0"; - os << hex[v]; - } - else { - std::size_t first = v / 16; - std::size_t last = v % 16; - os << hex[first] << hex[last]; - } - }; - for (char ch : helper.sv) { - uint8_t v = static_cast(ch); - to_hex(hex, v); - os << " "; - } - return os; - } - bool operator==(const hex_helper&) const = default; - std::string_view sv; -}; \ No newline at end of file diff --git a/src/struct_pb/tests/main.cpp b/src/struct_pb/tests/main.cpp deleted file mode 100644 index c5890983a..000000000 --- a/src/struct_pb/tests/main.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright (c) 2023, Alibaba Group Holding Limited; - * - * 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. - */ -#define DOCTEST_CONFIG_IMPLEMENT - -#include "doctest.h" - -// doctest comments -// 'function' : must be 'attribute' - see issue #182 -DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) -int main(int argc, char** argv) { return doctest::Context(argc, argv).run(); } -DOCTEST_MSVC_SUPPRESS_WARNING_POP \ No newline at end of file diff --git a/src/struct_pb/tests/test_bad_identifiers.proto b/src/struct_pb/tests/test_bad_identifiers.proto deleted file mode 100644 index ead67b6c6..000000000 --- a/src/struct_pb/tests/test_bad_identifiers.proto +++ /dev/null @@ -1,191 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Author: kenton@google.com (Kenton Varda) -// Based on original Protocol Buffers design by -// Sanjay Ghemawat, Jeff Dean, and others. -// -// This file tests that various identifiers work as field and type names even -// though the same identifiers are used internally by the C++ code generator. - -// LINT: LEGACY_NAMES - -syntax = "proto2"; - -// Some generic_services option(s) added automatically. -// See: http://go/proto2-generic-services-default -option cc_generic_services = true; // auto-added - -// We don't put this in a package within proto2 because we need to make sure -// that the generated code doesn't depend on being in the proto2 namespace. -package protobuf_unittest; - -// Test that fields can have names like "input" and "i" which are also used -// internally by the code generator for local variables. -message TestConflictingSymbolNames { - message BuildDescriptors {} - message TypeTraits {} - - optional int32 input = 1; - optional int32 output = 2; - optional string length = 3; - repeated int32 i = 4; - repeated string new_element = 5 [ctype = STRING_PIECE]; - optional int32 total_size = 6; - optional int32 tag = 7; - - enum TestEnum { - FOO = 0; - } - message Data1 { - repeated int32 data = 1; - } - message Data2 { - repeated TestEnum data = 1; - } - message Data3 { - repeated string data = 1; - } - message Data4 { - repeated Data4 data = 1; - } - message Data5 { - repeated string data = 1 [ctype = STRING_PIECE]; - } - message Data6 { - repeated string data = 1 [ctype = CORD]; - } - - optional int32 source = 8; - optional int32 value = 9; - optional int32 file = 10; - optional int32 from = 11; - optional int32 handle_uninterpreted = 12; - repeated int32 index = 13; - optional int32 controller = 14; - optional int32 already_here = 15; - - optional uint32 uint32 = 16; - optional uint32 uint32_t = 41; - optional uint64 uint64 = 17; - optional uint32 uint64_t = 42; - optional string string = 18; - optional int32 memset = 19; - optional int32 int32 = 20; - optional int32 int32_t = 43; - optional int64 int64 = 21; - optional int64 int64_t = 44; - optional int64 size_t = 45; - - optional uint32 cached_size = 22; - optional uint32 extensions = 23; - optional uint32 bit = 24; - optional uint32 bits = 25; - optional uint32 offsets = 26; - optional uint32 reflection = 27; - - message Cord {} - optional string some_cord = 28 [ctype = CORD]; - - message StringPiece {} - optional string some_string_piece = 29 [ctype = STRING_PIECE]; - - // Some keywords. - optional uint32 int = 30; - optional uint32 friend = 31; - optional uint32 class = 37; - optional uint32 typedecl = 39; - optional uint32 auto = 40; - - // The generator used to #define a macro called "DO" inside the .cc file. - message DO {} - optional DO do = 32; - - // Some template parameter names for extensions. - optional int32 field_type = 33; - optional bool is_packed = 34; - - // test conflicting release_$name$. "length" and "do" field in this message - // must remain string or message fields to make the test valid. - optional string release_length = 35; - // A more extreme case, the field name "do" here is a keyword, which will be - // escaped to "do_" already. Test there is no conflict even with escaped field - // names. - optional DO release_do = 36; - - // For clashing local variables in Serialize and ByteSize calculation. - optional string target = 38; - - extensions 1000 to max; // NO_PROTO3 -} - -message TestConflictingSymbolNamesExtension { // NO_PROTO3 - extend TestConflictingSymbolNames { // NO_PROTO3 - repeated int32 repeated_int32_ext = 20423638 [packed = true]; // NO_PROTO3 - } // NO_PROTO3 -} // NO_PROTO3 - -message TestConflictingEnumNames { // NO_PROTO3 - enum while { // NO_PROTO3 - default = 0; // NO_PROTO3 - and = 1; // NO_PROTO3 - class = 2; // NO_PROTO3 - int = 3; // NO_PROTO3 - typedef = 4; // NO_PROTO3 - XOR = 5; // NO_PROTO3 - } // NO_PROTO3 - - optional while conflicting_enum = 1; // NO_PROTO3 -} // NO_PROTO3 - -enum bool { // NO_PROTO3 - default = 0; // NO_PROTO3 - NOT_EQ = 1; // NO_PROTO3 - volatile = 2; // NO_PROTO3 - return = 3; // NO_PROTO3 -} // NO_PROTO3 - -message DummyMessage {} - -message NULL { - optional int32 int = 1; -} - -extend TestConflictingSymbolNames { // NO_PROTO3 - optional int32 void = 314253; // NO_PROTO3 -} // NO_PROTO3 - -// Message names that could conflict. -message Shutdown {} -message TableStruct {} - -service TestConflictingMethodNames { - rpc Closure(DummyMessage) returns (DummyMessage); -} diff --git a/src/struct_pb/tests/test_large_enum_value.proto b/src/struct_pb/tests/test_large_enum_value.proto deleted file mode 100644 index cb6ca1b15..000000000 --- a/src/struct_pb/tests/test_large_enum_value.proto +++ /dev/null @@ -1,43 +0,0 @@ -// Protocol Buffers - Google's data interchange format -// Copyright 2008 Google Inc. All rights reserved. -// https://developers.google.com/protocol-buffers/ -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are -// met: -// -// * Redistributions of source code must retain the above copyright -// notice, this list of conditions and the following disclaimer. -// * Redistributions in binary form must reproduce the above -// copyright notice, this list of conditions and the following disclaimer -// in the documentation and/or other materials provided with the -// distribution. -// * Neither the name of Google Inc. nor the names of its -// contributors may be used to endorse or promote products derived from -// this software without specific prior written permission. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS -// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR -// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT -// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, -// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, -// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY -// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Test that proto2 compiler can generate valid code when the enum value -// is INT_MAX. Note that this is a compile-only test and this proto is not -// referenced in any C++ code. -syntax = "proto2"; - -package protobuf_unittest; - -message TestLargeEnumValue { - enum EnumWithLargeValue { - VALUE_1 = 1; - VALUE_MAX = 0x7fffffff; - } -} diff --git a/src/struct_pb/tests/test_pb.cpp b/src/struct_pb/tests/test_pb.cpp deleted file mode 100644 index 06aae7f98..000000000 --- a/src/struct_pb/tests/test_pb.cpp +++ /dev/null @@ -1,851 +0,0 @@ -/* - * Copyright (c) 2023, Alibaba Group Holding Limited; - * - * 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 "doctest.h" -#include "helper.hpp" -#ifdef HAVE_PROTOBUF -#include "test_pb.pb.h" -#endif -using namespace doctest; -using namespace struct_pb; - -TEST_SUITE_BEGIN("test pb"); -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::Test1& t, const Test1& pb_t) const { - return t.a == pb_t.a(); - } -}; -#endif -TEST_CASE("testing test_struct_pb::Test1") { - test_struct_pb::Test1 t{}; - SUBCASE("empty") { check_self(t); } - SUBCASE("has value") { - std::string buf{0x08, (char)0x96, 0x01}; - t.a = 150; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - Test1 pb_t; - pb_t.set_a(150); - auto pb_buf = pb_t.SerializeAsString(); - REQUIRE(pb_buf == buf); - check_with_protobuf(t, pb_t); -#endif - } - - SUBCASE("negative") { - { - // an example for check arm char - std::string buf{0x08, (char)0xff, (char)0xff, (char)0xff, - (char)0xff, (char)0xff, (char)0xff, (char)0xff, - (char)0xff, (char)0xff, 0x01}; - test_struct_pb::Test1 t{.a = -1}; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - // for debug - Test1 pb_t; - pb_t.set_a(-1); - auto s = pb_t.SerializeAsString(); - check_with_protobuf(t, pb_t); -#endif - } - for (int32_t i = -1; i > INT16_MIN + 1; i *= 2) { - test_struct_pb::Test1 t{.a = i}; - check_self(t); -#ifdef HAVE_PROTOBUF - Test1 pb_t; - pb_t.set_a(i); - check_with_protobuf(t, pb_t); -#endif - } - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::Test2& t, const Test2& pb_t) const { - return t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing test_struct_pb::Test2") { - test_struct_pb::Test2 t{}; - SUBCASE("empty") { check_self(t); } - SUBCASE("has value") { - std::string buf{0x12, 0x07}; - std::string s = "testing"; - buf += s; - t.b = s; - check_self(t, buf); - -#ifdef HAVE_PROTOBUF - Test2 pb_t; - pb_t.set_b(s); - check_with_protobuf(t, pb_t); -#endif - } -} -namespace std { -template <> -struct equal_to { - bool operator()(const test_struct_pb::Test3& lhs, - const test_struct_pb::Test3& rhs) const { - if (lhs.c && rhs.c) { - return equal_to()(*lhs.c, *rhs.c); - } - if (!lhs.c && !rhs.c) { - return true; - } - return false; - } -}; -} // namespace std -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::Test3& t, const Test3& pb_t) const { - if (t.c && pb_t.has_c()) { - return PB_equal()(*t.c, pb_t.c()); - } - if (!t.c && !pb_t.has_c()) { - return true; - } - return false; - } -}; -#endif -TEST_CASE("testing test_struct_pb::Test3") { - test_struct_pb::Test3 t{}; - SUBCASE("empty") { check_self(t); } - SUBCASE("has value") { - std::string buf{0x1a, 0x03, 0x08, (char)0x96, 0x01}; - t.c = std::make_unique( - test_struct_pb::Test1{.a = 150}); - check_self(t, buf); - -#ifdef HAVE_PROTOBUF - Test3 pb_t; - auto pb_c = new Test1; - pb_c->set_a(150); - pb_t.set_allocated_c(pb_c); - - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::Test4& t, const Test4& pb_t) const { - return t.e == pb_t.e(); - } -}; -#endif -TEST_CASE("testing test_struct_pb::Test4") { - test_struct_pb::Test4 t{}; - SUBCASE("empty") { check_self(t); } - SUBCASE("string empty") { - std::string buf{0x2a, 0x01, 0x01}; - t.e = {1}; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - Test4 pb_t; - pb_t.add_e(1); - auto pb_buf = pb_t.SerializeAsString(); - REQUIRE(pb_buf == buf); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("repeated empty") { - // [4] 22 2 68 69 - std::string buf{0x22, 0x02, 0x68, 0x69}; - std::string s = "hi"; - t.d = s; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - Test4 pb_t; - pb_t.set_d(s); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("has value") { - std::string buf{0x22, 0x05, 0x68, 0x65, 0x6c, 0x6c, - 0x6f, 0x2a, 0x03, 0x01, 0x02, 0x03}; - // why document write - // 220568656c6c6f280128022803 - // while my pb c++ code generated - // 34 5 'h' 'e' 'l' 'l' 'o' 42 3 1 2 3 - // 22 5 68 65 6c 6c 6f 2a 3 1 2 3 - t.d = "hello"; - t.e = {1, 2, 3}; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - Test4 pb_t; - pb_t.set_d("hello"); - pb_t.add_e(1); - pb_t.add_e(2); - pb_t.add_e(3); - check_with_protobuf(t, pb_t); -#endif - } -} - -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestDouble& t, - const MyTestDouble& pb_t) const { - std::valarray ts{t.a, t.b, t.c}; - std::valarray pb_ts{pb_t.a(), pb_t.b(), pb_t.c()}; - return (std::abs(ts - pb_ts) < 0.00005f).min(); - } -}; -#endif -TEST_CASE("testing double") { - test_struct_pb::MyTestDouble t{.a = 123.456, .b = 0, .c = -678.123}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestDouble pb_t; - pb_t.set_a(t.a); - pb_t.set_b(t.b); - pb_t.set_c(t.c); - check_with_protobuf(t, pb_t); -#endif -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestFloat& t, - const MyTestFloat& pb_t) const { - std::valarray ts{t.a, t.b, t.c, t.d, t.e}; - std::valarray pb_ts{pb_t.a(), pb_t.b(), pb_t.c(), pb_t.d(), - pb_t.e()}; - return (std::abs(ts - pb_ts) < 0.00005f).min(); - } -}; -#endif -TEST_CASE("testing float") { - // [20] 15 00 00 80 3f 1d 00 00 80 bf 25 b6 f3 9d 3f 2d 00 04 f1 47 - std::string buf{0x15, 0x00, 0x00, (char)0x80, 0x3f, - 0x1d, 0x00, 0x00, (char)0x80, (char)0xbf, - 0x25, (char)0xb6, (char)0xf3, (char)0x9d, 0x3f, - 0x2d, 0x00, 0x04, (char)0xf1, 0x47}; - test_struct_pb::MyTestFloat t{ - .a = 0, .b = 1, .c = -1, .d = 1.234, .e = 1.234e5}; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestFloat pb_t; - pb_t.set_a(0); - pb_t.set_b(1); - pb_t.set_c(-1); - pb_t.set_d(1.234); - pb_t.set_e(1.234e5); - check_with_protobuf(t, pb_t); -#endif -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestInt32& t, - const MyTestInt32& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing int32") { - std::string buf{0x08, (char)0x80, 0x01}; - test_struct_pb::MyTestInt32 t; - t.a = 128; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestInt32 pb_t; - pb_t.set_a(128); - check_with_protobuf(t, pb_t); -#endif -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestInt64& t, - const MyTestInt64& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing int64") { - int64_t max_val = 4; - max_val *= INT32_MAX; - for (int64_t i = 1; i < max_val; i *= -2) { - test_struct_pb::MyTestInt64 t{.a = i}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestInt64 pb_t; - pb_t.set_a(i); - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestUint32& t, - const MyTestUint32& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing uint32") { - int32_t max_val = 4; - max_val *= INT16_MAX; - for (uint32_t i = 1; i < max_val; i *= 2) { - test_struct_pb::MyTestUint32 t{.a = i}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestUint32 pb_t; - pb_t.set_a(i); - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestUint64& t, - const MyTestUint64& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing uint64") { - int64_t max_val = 4; - max_val *= INT32_MAX; - for (uint64_t i = 1; i < max_val; i *= 2) { - test_struct_pb::MyTestUint64 t{.a = i}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestUint64 pb_t; - pb_t.set_a(i); - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestEnum& t, - const MyTestEnum& pb_t) const { - return static_cast(t.color) == - static_cast(pb_t.color()); - } -}; -#endif -TEST_CASE("testing enum") { - SUBCASE("Red") { - std::string buf; - test_struct_pb::MyTestEnum t{}; - t.color = test_struct_pb::MyTestEnum::Color::Red; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestEnum pb_t; - pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Red); - auto pb_buf = pb_t.SerializeAsString(); - REQUIRE(hex_helper(pb_buf) == hex_helper(buf)); - MyTestEnum pb_d_t; - auto ok = pb_d_t.ParseFromArray(pb_buf.data(), pb_buf.size()); - REQUIRE(ok); - CHECK(pb_d_t.IsInitialized()); - CHECK(pb_d_t.color() == pb_t.color()); - auto c = pb_d_t.color(); - CHECK(c == MyTestEnum_Color::MyTestEnum_Color_Red); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("Green") { - std::string buf{0x30, 0x01}; - test_struct_pb::MyTestEnum t{}; - t.color = test_struct_pb::MyTestEnum::Color::Green; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestEnum pb_t; - pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Green); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("Blue") { - std::string buf{0x30, 0x02}; - test_struct_pb::MyTestEnum t{}; - t.color = test_struct_pb::MyTestEnum::Color::Blue; - check_self(t, buf); - -#ifdef HAVE_PROTOBUF - MyTestEnum pb_t; - pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Blue); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("Enum127") { - std::string buf{0x30, (char)0x7f}; - test_struct_pb::MyTestEnum t{}; - t.color = test_struct_pb::MyTestEnum::Color::Enum127; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestEnum pb_t; - pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Enum127); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("Enum128") { - std::string buf{0x30, (char)0x80, 0x01}; - test_struct_pb::MyTestEnum t{}; - t.color = test_struct_pb::MyTestEnum::Color::Enum128; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestEnum pb_t; - pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Enum128); - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestRepeatedMessage& t, - const MyTestRepeatedMessage& pb_t) const { - return t.fs == pb_t.fs(); - } -}; -#endif -TEST_CASE("testing nested repeated message") { - SUBCASE("one") { - test_struct_pb::MyTestRepeatedMessage t{}; - t.fs = {{1, 2, 3}}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestRepeatedMessage pb_t; - { - auto f1 = pb_t.add_fs(); - f1->set_a(1); - f1->set_b(2); - f1->set_c(3); - } - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("two") { - test_struct_pb::MyTestRepeatedMessage t{}; - t.fs = {{1, 2, 3}, {4, 5, 6}}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestRepeatedMessage pb_t; - { - auto f1 = pb_t.add_fs(); - f1->set_a(1); - f1->set_b(2); - f1->set_c(3); - } - { - auto f1 = pb_t.add_fs(); - f1->set_a(4); - f1->set_b(5); - f1->set_c(6); - } - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestSint32& t, - const MyTestSint32& pb_t) const { - return t.a == pb_t.a(); - } -}; -#endif -TEST_CASE("testing sint32") { - SUBCASE("-1") { - std::string buf{0x08, 0x01}; - test_struct_pb::MyTestSint32 t{}; - t.a = -1; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestSint32 pb_t; - pb_t.set_a(-1); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("1") { - test_struct_pb::MyTestSint32 t{}; - t.a = 1; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestSint32 pb_t; - pb_t.set_a(1); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("128") { - std::string buf{0x08, (char)0x80, 0x02}; - test_struct_pb::MyTestSint32 t{}; - t.a = 128; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestSint32 pb_t; - pb_t.set_a(128); - check_with_protobuf(t, pb_t); -#endif - } - - SUBCASE("range") { - for (int32_t i = INT16_MAX; i > INT16_MIN + 1; --i) { - test_struct_pb::MyTestSint32 t{.a = i}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestSint32 pb_t; - pb_t.set_a(i); - check_with_protobuf(t, pb_t); -#endif - } - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestSint64& t, - const MyTestSint64& pb_t) const { - return t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing sint64") { - SUBCASE("-1") { - std::string buf{0x10, 0x01}; - test_struct_pb::MyTestSint64 t{}; - t.b = -1; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestSint64 pb_t; - pb_t.set_b(-1); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("128") { - std::string buf{0x10, (char)0x80, 0x02}; - test_struct_pb::MyTestSint64 t{}; - t.b = 128; - check_self(t, buf); - -#ifdef HAVE_PROTOBUF - MyTestSint64 pb_t; - pb_t.set_b(128); - check_with_protobuf(t, pb_t); - -#endif - } - - SUBCASE("range") { - for (int64_t i = -1; i > INT32_MIN + 1; i *= -2) { - test_struct_pb::MyTestSint64 t{.b = i}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestSint64 pb_t; - pb_t.set_b(i); - check_with_protobuf(t, pb_t); -#endif - } - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestMap& t, - const MyTestMap& pb_t) const { - if (t.e.size() != pb_t.e_size()) { - return false; - } - for (const auto& [k, v] : pb_t.e()) { - auto it = t.e.find(k); - if (it == t.e.end()) { - return false; - } - if (it->second != v) { - return false; - } - } - return true; - } -}; -#endif -TEST_CASE("testing map") { - SUBCASE("one entry") { - std::string buf{0x1a, 0x05, 0x0a, 0x01, 0x61, 0x10, 0x01}; - test_struct_pb::MyTestMap t; - t.e["a"] = 1; - check_self(t, buf); -#ifdef HAVE_PROTOBUF - MyTestMap pb_t; - auto& pb_m = *pb_t.mutable_e(); - pb_m["a"] = 1; - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("two entry") { - std::string buf{ - 0x1a, 0x0a, 0x0a, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x10, - (char)0x9a, 0x05, 0x1a, 0x05, 0x0a, 0x01, 0x61, 0x10, 0x01, - }; - std::string buf2{ - 0x1a, 0x05, 0x0a, 0x01, 0x61, 0x10, 0x01, 0x1a, 0x0a, 0x0a, - 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x10, (char)0x9a, 0x05, - }; - test_struct_pb::MyTestMap t; - t.e["a"] = 1; - t.e["hello"] = 666; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestMap pb_t; - auto& pb_m = *pb_t.mutable_e(); - pb_m["a"] = 1; - pb_m["hello"] = 666; - auto pb_buf = pb_t.SerializeAsString(); - - CHECK(buf.size() == pb_buf.size()); - REQUIRE((buf == pb_buf || buf2 == pb_buf)); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestFixed32& t, - const MyTestFixed32& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing fixed32") { - test_struct_pb::MyTestFixed32 t{}; - SUBCASE("single fixed") { - t.a = 888; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestFixed32 pb_t; - pb_t.set_a(888); - check_with_protobuf(t, pb_t); -#endif - } - SUBCASE("only repeated") { - t.b = {5, 4, 3, 2, 1}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestFixed32 pb_t; - pb_t.add_b(5); - pb_t.add_b(4); - pb_t.add_b(3); - pb_t.add_b(2); - pb_t.add_b(1); - check_with_protobuf(t, pb_t); -#endif - } -} - -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestFixed64& t, - const MyTestFixed64& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing fixed64") { - using T = uint64_t; - T max_val = 4; - max_val *= INT32_MAX; - for (T i = 1; i < max_val; i *= 2) { - test_struct_pb::MyTestFixed64 t{.a = i}; -#ifdef HAVE_PROTOBUF - MyTestFixed64 pb_t; - pb_t.set_a(i); -#endif - for (T j = 1; j <= i; j *= 2) { -#ifdef HAVE_PROTOBUF - pb_t.add_b(j * 3); -#endif - t.b.push_back(j * 3); - } - check_self(t); -#ifdef HAVE_PROTOBUF - check_with_protobuf(t, pb_t); -#endif - } -} - -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestSfixed32& t, - const MyTestSfixed32& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing sfixed32") { - using T = int32_t; - T max_val = 4; - max_val *= INT16_MAX; - for (T i = 1; i < max_val; i *= -2) { - test_struct_pb::MyTestSfixed32 t{.a = i}; -#ifdef HAVE_PROTOBUF - MyTestSfixed32 pb_t; - pb_t.set_a(i); -#endif - for (T j = 1; j <= i; j *= -2) { -#ifdef HAVE_PROTOBUF - pb_t.add_b(j * -3); -#endif - t.b.push_back(j * -3); - } - check_self(t); -#ifdef HAVE_PROTOBUF - check_with_protobuf(t, pb_t); -#endif - } -} - -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestSfixed64& t, - const MyTestSfixed64& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b(); - } -}; -#endif -TEST_CASE("testing sfixed64") { - using T = int64_t; - T max_val = 4; - max_val *= INT32_MAX; - for (T i = 1; i < max_val; i *= -2) { - test_struct_pb::MyTestSfixed64 t{.a = i}; -#ifdef HAVE_PROTOBUF - MyTestSfixed64 pb_t; - pb_t.set_a(i); -#endif - for (T j = 1; j <= i; j *= -2) { -#ifdef HAVE_PROTOBUF - pb_t.add_b(j * -3); -#endif - t.b.push_back(j * -3); - } - check_self(t); -#ifdef HAVE_PROTOBUF - check_with_protobuf(t, pb_t); -#endif - } -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestFieldNumberRandom& t, - const MyTestFieldNumberRandom& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b() && t.c == pb_t.c() && - t.f == pb_t.f() && std::abs(t.d - pb_t.d()) < 0.00005f && - std::abs(t.e - pb_t.e()) < 0.00005f; - } -}; -#endif -TEST_CASE("testing random field number") { - test_struct_pb::MyTestFieldNumberRandom t{.a = 666, - .b = 999, - .c = "random", - .d = 3.14, - .e = 3344.123, - .f = {5, 4, 3, 2, 1}}; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestFieldNumberRandom pb_t; - pb_t.set_a(666); - pb_t.set_b(999); - pb_t.set_c("random"); - pb_t.set_d(3.14); - pb_t.set_e(3344.123); - pb_t.add_f(5); - pb_t.add_f(4); - pb_t.add_f(3); - pb_t.add_f(2); - pb_t.add_f(1); - check_with_protobuf(t, pb_t); -#endif -} -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::MyTestAll& t, - const MyTestAll& pb_t) const { - return t.a == pb_t.a() && t.b == pb_t.b() && t.c == pb_t.c() && - t.d == pb_t.d() && t.e == pb_t.e() && t.f == pb_t.f() && - t.g == pb_t.g() && t.h == pb_t.h() && t.i == pb_t.i() && - t.j == pb_t.j() && t.k == pb_t.k() && t.l == pb_t.l() && - t.m == pb_t.m() && t.n == pb_t.n() && t.o == pb_t.o(); - } -}; -#endif -TEST_CASE("testing all") { - test_struct_pb::MyTestAll t{}; - - t.a = -100; - t.b = -200; - t.c = -300; - t.d = -2378; - t.e = 2323; - t.f = 255; - t.g = -890; - t.h = -2369723; - t.i = -23234; - t.j = -239223423; - t.k = 9232983; - t.l = 237982374432; - t.m = true; - t.n = "testing all types"; - t.o = "\1\2\3\4\5\t\n666"; - check_self(t); -#ifdef HAVE_PROTOBUF - MyTestAll pb_t; - pb_t.set_a(t.a); - pb_t.set_b(t.b); - pb_t.set_c(t.c); - pb_t.set_d(t.d); - pb_t.set_e(t.e); - pb_t.set_f(t.f); - pb_t.set_g(t.g); - pb_t.set_h(t.h); - pb_t.set_i(t.i); - pb_t.set_j(t.j); - pb_t.set_k(t.k); - pb_t.set_l(t.l); - pb_t.set_m(t.m); - pb_t.set_n(t.n); - pb_t.set_o(t.o); - - check_with_protobuf(t, pb_t); -#endif -} -TEST_SUITE_END; \ No newline at end of file diff --git a/src/struct_pb/tests/test_pb.proto b/src/struct_pb/tests/test_pb.proto deleted file mode 100644 index 820f3498d..000000000 --- a/src/struct_pb/tests/test_pb.proto +++ /dev/null @@ -1,127 +0,0 @@ -syntax = "proto3"; - - -message Test1 { - int32 a = 1; -} -message Test2 { - string b = 2; -} -message Test3 { - Test1 c = 3; -} - -message Test4 { - string d = 4; - repeated int32 e = 5; -} - -message MyTestDouble { - double a = 1; - double b = 2; - double c = 3; -} - -message MyTestFloat { - float a = 1; - float b = 2; - float c = 3; - float d = 4; - float e = 5; -} - -message MyTestInt32 { - int32 a = 1; - repeated int32 b = 2; -} -message MyTestInt64 { - int64 a = 1; - repeated int64 b = 2; -} -message MyTestUint32 { - uint32 a = 1; - repeated uint32 b = 2; -} -message MyTestUint64 { - uint64 a = 1; - repeated uint64 b = 2; -} -message MyTestEnum { - enum Color { - Red = 0; - Green = 1; - Blue = 2; - Enum127 = 127; - Enum128 = 128; - } - Color color = 6; -} - -message MyTestRepeatedMessage { - repeated MyTestFloat fs = 1; -} - -message MyTestSint32 { - sint32 a = 1; -} -message MyTestSint64 { - sint64 b = 2; -} -message MyTestMap { - map e = 3; -} -message MyTestFixed32 { - fixed32 a = 1; - repeated fixed32 b = 2; -} -message MyTestFixed64 { - fixed64 a = 1; - repeated fixed64 b = 2; -} -message MyTestSfixed32 { - sfixed32 a = 1; - repeated sfixed32 b = 2; -} -message MyTestSfixed64 { - sfixed64 a = 1; - repeated sfixed64 b = 2; -} - -message MyTestFieldNumberRandom { - int32 a = 6; - sint64 b = 3; - string c = 4; - double d = 5; - float e = 1; - repeated fixed32 f = 128; -} - -message MyTestAll { - double a = 1; - float b = 2; - int32 c = 3; - int64 d = 4; - uint32 e = 5; - uint64 f = 6; - sint32 g = 7; - sint64 h = 8; - fixed32 i = 9; - fixed64 j = 10; - sfixed32 k = 11; - sfixed64 l = 12; - bool m = 13; - string n = 14; - bytes o = 15; -} -message SubMessageForOneof { - bool ok = 1; -} -message SampleMessageOneof { - oneof test_oneof { - int32 b = 10; - int32 a = 8; - - string name = 4; - SubMessageForOneof sub_message = 9; - } -} \ No newline at end of file diff --git a/src/struct_pb/tests/test_pb_bad_identifiers.cpp b/src/struct_pb/tests/test_pb_bad_identifiers.cpp deleted file mode 100644 index 0089ac502..000000000 --- a/src/struct_pb/tests/test_pb_bad_identifiers.cpp +++ /dev/null @@ -1,46 +0,0 @@ -#include "doctest.h" -#include "test_bad_identifiers.struct_pb.h" -using namespace doctest; - -TEST_SUITE_BEGIN("test bad identifiers"); -TEST_CASE("testing conflicting symbol names") { - protobuf_unittest::TestConflictingSymbolNames message; - message.uint32 = 1; - auto sz = struct_pb::internal::get_needed_size(message); - CHECK(sz == 3); - // Due to different API, the code is useless - message.friend_ = 5; - CHECK(message.friend_ == 5); - message.class_ = 6; - CHECK(message.class_ == 6); - // NO PROTO3 - typedef protobuf_unittest::TestConflictingSymbolNamesExtension - ExtensionMessage; -} -TEST_CASE("testing conflicting enum names") { - protobuf_unittest::TestConflictingEnumNames message; - message.conflicting_enum = - protobuf_unittest::TestConflictingEnumNames::while_::and_; - CHECK(1 == static_cast(message.conflicting_enum.value())); - - message.conflicting_enum = - protobuf_unittest::TestConflictingEnumNames::while_::XOR; - CHECK(5 == static_cast(message.conflicting_enum.value())); - - protobuf_unittest::bool_ conflicting_enum; - conflicting_enum = protobuf_unittest::bool_::NOT_EQ; - CHECK(1 == static_cast(conflicting_enum)); - - conflicting_enum = protobuf_unittest::bool_::return_; - CHECK(3 == static_cast(conflicting_enum)); -} -TEST_CASE("testing conflicting message names") { - protobuf_unittest::NULL_ message; - message.int_ = 123; - CHECK(message.int_ == 123); -} -TEST_CASE("testing conflicting extension") { - protobuf_unittest::TestConflictingSymbolNames message; - // NO_PROTO3 -} -TEST_SUITE_END(); \ No newline at end of file diff --git a/src/struct_pb/tests/test_pb_benchmark_struct.cpp b/src/struct_pb/tests/test_pb_benchmark_struct.cpp deleted file mode 100644 index 7895e7a4a..000000000 --- a/src/struct_pb/tests/test_pb_benchmark_struct.cpp +++ /dev/null @@ -1,335 +0,0 @@ -/* - * Copyright (c) 2023, Alibaba Group Holding Limited; - * - * 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. - */ -#ifdef HAVE_PROTOBUF -#include "protobuf_sample.hpp" -#endif -#include "data_def.struct_pb.h" -#include "doctest.h" -#include "helper.hpp" -#include "struct_pb_sample.hpp" -using namespace doctest; - -namespace struct_pb_sample { -template -bool check_unique_ptr(const T& lhs, const T& rhs) { - if (lhs && rhs) { - return *lhs == *rhs; - } - return !lhs && !rhs; -} -bool operator==(const Vec3& lhs, const Vec3& rhs) { - std::valarray lh({lhs.x, lhs.y, lhs.z}); - std::valarray rh({rhs.x, rhs.y, rhs.z}); - return (std::abs(lh - rh) < 0.05f).min(); -} -bool operator==(const Weapon& lhs, const Weapon& rhs) { - return lhs.name == rhs.name && lhs.damage == rhs.damage; -}; -bool operator==(const rect32& lhs, const rect32& rhs) { - return lhs.x == rhs.x && lhs.y == rhs.y && lhs.width == rhs.width && - lhs.height == rhs.height; -} -bool operator==(const rect32s& lhs, const rect32s& rhs) { - return lhs.rect32_list == rhs.rect32_list; -} -bool operator==(const person& lhs, const person& rhs) { - return lhs.id == rhs.id && lhs.name == rhs.name && lhs.age == rhs.age && - lhs.salary == rhs.salary; -} -bool operator==(const persons& lhs, const persons& rhs) { - return lhs.person_list == rhs.person_list; -} -bool operator==(const Monster& lhs, const Monster& rhs) { - bool ok = check_unique_ptr(lhs.pos, rhs.pos); - if (!ok) { - return false; - } - ok = check_unique_ptr(lhs.equipped, rhs.equipped); - if (!ok) { - return false; - } - return lhs.mana == rhs.mana && lhs.hp == rhs.hp && lhs.name == rhs.name && - lhs.inventory == rhs.inventory && lhs.color == rhs.color && - lhs.weapons == rhs.weapons && lhs.path == rhs.path; -}; -bool operator==(const Monsters& lhs, const Monsters& rhs) { - return lhs.monsters == rhs.monsters; -} - -bool verify(const struct_pb_sample::Weapon& a, - const struct_pb_sample::Weapon& b) { - assert(a.name == b.name); - assert(a.damage == b.damage); - return true; -} -bool verify(const struct_pb_sample::Monster& a, - const struct_pb_sample::Monster& b) { - assert(a.pos && b.pos); - assert(*a.pos == *b.pos); - assert(a.mana == b.mana); - assert(a.hp == b.hp); - assert(a.name == b.name); - assert(a.inventory == b.inventory); - assert(a.color == b.color); - assert(a.weapons.size() == b.weapons.size()); - for (int i = 0; i < a.weapons.size(); ++i) { - auto ok = verify(a.weapons[i], b.weapons[i]); - if (!ok) { - return ok; - } - } - assert(a.weapons == b.weapons); - assert(a.equipped && b.equipped); - assert(*a.equipped == *b.equipped); - assert(a.path == b.path); - return true; -} -bool verify(const struct_pb_sample::Monsters& a, - const struct_pb_sample::Monsters& b) { - assert(a.monsters.size() == b.monsters.size()); - for (int i = 0; i < a.monsters.size(); ++i) { - auto ok = verify(a.monsters[i], b.monsters[i]); - if (!ok) { - return ok; - } - } - return true; -} -template -T copy(const T& t) { - return t; -} -template <> -struct_pb_sample::Monster copy(const struct_pb_sample::Monster& t) { - struct_pb_sample::Monster m; - m.pos = std::make_unique(); - *m.pos = *t.pos; - m.mana = t.mana; - m.hp = t.hp; - m.name = t.name; - m.inventory = t.inventory; - m.color = t.color; - m.weapons = t.weapons; - m.equipped = std::make_unique(); - *m.equipped = *t.equipped; - m.path = t.path; - return m; -} -template <> -struct_pb_sample::Monsters copy(const struct_pb_sample::Monsters& t) { - struct_pb_sample::Monsters m; - m.monsters.reserve(t.monsters.size()); - for (const auto& e : t.monsters) { - m.monsters.push_back(std::move(copy(e))); - } - return m; -} -} // namespace struct_pb_sample - -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::rect32s& t, - const mygame::rect32s& pb_t) const { - return t.rect32_list == pb_t.rect32_list(); - } -}; -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::rect32& lhs, - const mygame::rect32& rhs) const { - return lhs.x == rhs.x() && lhs.y == rhs.y() && lhs.width == rhs.width() && - lhs.height == rhs.height(); - } -}; -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::Vec3& lhs, - const mygame::Vec3& rhs) const { - return lhs.x == rhs.x() && lhs.y == rhs.y() && lhs.z == rhs.z(); - } -}; -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::person& lhs, - const mygame::person& rhs) const { - return lhs.id == rhs.id() && lhs.name == rhs.name() && - lhs.age == rhs.age() && - std::abs(lhs.salary - rhs.salary()) < 0.0005f; - } -}; -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::persons& lhs, - const mygame::persons& rhs) const { - return lhs.person_list == rhs.person_list(); - } -}; -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::Weapon& lhs, - const mygame::Weapon& rhs) const { - return lhs.name == rhs.name() && lhs.damage == rhs.damage(); - } -}; -bool operator==(const struct_pb_sample::Monster::Color& a, - const mygame::Monster::Color& b) { - return int(a) == int(b); -} -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::Monster& lhs, - const mygame::Monster& rhs) const { - auto ok = (lhs.name == rhs.name() && lhs.mana == rhs.mana() && - lhs.hp == rhs.hp() && lhs.inventory == rhs.inventory() && - lhs.color == rhs.color() && lhs.weapons == rhs.weapons() && - lhs.path == rhs.path()); - if (!ok) { - return false; - } - if (lhs.pos && rhs.has_pos()) { - ok = - PB_equal()(*lhs.pos, rhs.pos()); - if (!ok) { - return false; - } - } - else if (lhs.pos || rhs.has_pos()) { - return false; - } - if (lhs.equipped && rhs.has_equipped()) { - ok = PB_equal()(*lhs.equipped, - rhs.equipped()); - if (!ok) { - return false; - } - } - else if (lhs.equipped || rhs.has_equipped()) { - return false; - } - return true; - } -}; -template <> -struct PB_equal { - bool operator()(const struct_pb_sample::Monsters& lhs, - const mygame::Monsters& rhs) const { - return lhs.monsters == rhs.monsters(); - } -}; -template -void check_repeated(const std::vector& a, - const google::protobuf::RepeatedPtrField& b) { - bool ret = (a == b); - REQUIRE(ret); -} -#endif - -TEST_SUITE_BEGIN("test pb benchmark struct"); -TEST_CASE("testing rect") { - auto my_rects = struct_pb_sample::create_rects(OBJECT_COUNT); -#ifdef HAVE_PROTOBUF - auto pb_rects = protobuf_sample::create_rects(OBJECT_COUNT); -#endif - for (int i = 0; i < OBJECT_COUNT; ++i) { - auto my_rect = my_rects.rect32_list[i]; - check_self(my_rect); -#ifdef HAVE_PROTOBUF - auto pb_rect = *(pb_rects.rect32_list().begin() + i); - REQUIRE(my_rect.x == pb_rect.x()); - REQUIRE(my_rect.y == pb_rect.y()); - REQUIRE(my_rect.width == pb_rect.width()); - REQUIRE(my_rect.height == pb_rect.height()); - check_with_protobuf(my_rect, pb_rect); -#endif - } - check_self(my_rects); -#ifdef HAVE_PROTOBUF - check_with_protobuf(my_rects, pb_rects); -#endif -} - -TEST_CASE("testing person") { - auto my_persons = struct_pb_sample::create_persons(OBJECT_COUNT); -#ifdef HAVE_PROTOBUF - auto pb_persons = protobuf_sample::create_persons(OBJECT_COUNT); -#endif - for (int i = 0; i < OBJECT_COUNT; ++i) { - auto my_person = my_persons.person_list[i]; - check_self(my_person); -#ifdef HAVE_PROTOBUF - auto pb_person = *(pb_persons.person_list().begin() + i); - REQUIRE(my_person.id == pb_person.id()); - REQUIRE(my_person.name == pb_person.name()); - REQUIRE(my_person.age == pb_person.age()); - REQUIRE(my_person.salary == pb_person.salary()); - check_with_protobuf(my_person, pb_person); -#endif - } - check_self(my_persons); -#ifdef HAVE_PROTOBUF - check_with_protobuf(my_persons, pb_persons); -#endif -} - -TEST_CASE("testing monsters") { - using namespace struct_pb_sample; - auto my_ms = struct_pb_sample::create_monsters(OBJECT_COUNT); -#ifdef HAVE_PROTOBUF - auto pb_ms = protobuf_sample::create_monsters(OBJECT_COUNT); -#endif - for (int i = 0; i < OBJECT_COUNT; ++i) { - auto& my_m = my_ms.monsters[i]; - check_self(my_m); - -#ifdef HAVE_PROTOBUF - auto pb_m = *(pb_ms.monsters().begin() + i); - REQUIRE(my_m.pos); - REQUIRE(my_m.mana == pb_m.mana()); - REQUIRE(my_m.hp == pb_m.hp()); - REQUIRE(my_m.name == pb_m.name()); - REQUIRE(my_m.inventory == pb_m.inventory()); - REQUIRE(my_m.color == pb_m.color()); - check_repeated(my_m.weapons, pb_m.weapons()); - check_repeated(my_m.path, pb_m.path()); - - check_with_protobuf(my_m, pb_m); -#endif - - std::string my_buf = struct_pb::serialize(my_m); - struct_pb_sample::Monster d_t{}; - auto ok = struct_pb::deserialize_to(d_t, my_buf); - REQUIRE(ok); - CHECK(struct_pb_sample::verify(d_t, my_m)); - REQUIRE(d_t.pos); - REQUIRE(my_m.pos); - CHECK(*d_t.pos == *my_m.pos); - CHECK(d_t.mana == my_m.mana); - CHECK(d_t.hp == my_m.hp); - CHECK(d_t.name == my_m.name); - CHECK(d_t.inventory == my_m.inventory); - CHECK(d_t.color == my_m.color); - REQUIRE(d_t.equipped); - REQUIRE(my_m.equipped); - CHECK(*d_t.equipped == *my_m.equipped); - CHECK(d_t.path == my_m.path); - } - check_self(my_ms); -#ifdef HAVE_PROTOBUF - check_with_protobuf(my_ms, pb_ms); -#endif -} -TEST_SUITE_END; diff --git a/src/struct_pb/tests/test_pb_oneof.cpp b/src/struct_pb/tests/test_pb_oneof.cpp deleted file mode 100644 index 59ceaefc8..000000000 --- a/src/struct_pb/tests/test_pb_oneof.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "doctest.h" -#include "helper.hpp" -#ifdef HAVE_PROTOBUF -#include "test_pb.pb.h" -#endif -using namespace doctest; -#ifdef HAVE_PROTOBUF -template <> -struct PB_equal { - bool operator()(const test_struct_pb::SubMessageForOneof& t, - const SubMessageForOneof& pb_t) const { - return t.ok == pb_t.ok(); - } -}; -template <> -struct PB_equal { - bool operator()(const test_struct_pb::SampleMessageOneof& t, - const SampleMessageOneof& pb_t) const { - if (int(t.test_oneof_case()) != int(pb_t.test_oneof_case())) { - return false; - } - switch (pb_t.test_oneof_case()) { - case SampleMessageOneof::kB: { - return t.b() == pb_t.b(); - } break; - case SampleMessageOneof::kA: { - return t.a() == pb_t.a(); - } break; - case SampleMessageOneof::kName: { - return t.name() == pb_t.name(); - } break; - case SampleMessageOneof::kSubMessage: { - return PB_equal()(*t.sub_message(), - pb_t.sub_message()); - } break; - case SampleMessageOneof::TEST_ONEOF_NOT_SET: - break; - } - return true; - } -}; -#endif - -namespace std { -template <> -struct equal_to { - bool operator()(const test_struct_pb::SampleMessageOneof& lhs, - const test_struct_pb::SampleMessageOneof& rhs) const { - if (lhs.test_oneof_case() != rhs.test_oneof_case()) { - return false; - } - if (lhs.has_sub_message() && rhs.has_sub_message()) { - return equal_to()(*lhs.sub_message(), - *rhs.sub_message()); - } - return lhs.test_oneof == rhs.test_oneof; - } -}; -} // namespace std - -TEST_CASE("testing oneof, b") { - test_struct_pb::SampleMessageOneof t; - int b = 13298; - t.set_b(b); - check_self(t); -#ifdef HAVE_PROTOBUF - SampleMessageOneof pb_t; - pb_t.set_b(b); - check_with_protobuf(t, pb_t); -#endif -} -TEST_CASE("testing oneof, a") { - test_struct_pb::SampleMessageOneof t; - int a = 66613298; - t.set_a(a); - check_self(t); -#ifdef HAVE_PROTOBUF - SampleMessageOneof pb_t; - pb_t.set_a(a); - check_with_protobuf(t, pb_t); -#endif -} -TEST_CASE("testing oneof, name") { - std::string name = "oneof, name"; - test_struct_pb::SampleMessageOneof t; - t.set_name(name); - check_self(t); -#ifdef HAVE_PROTOBUF - SampleMessageOneof pb_t; - pb_t.set_name(name); - check_with_protobuf(t, pb_t); -#endif -} - -TEST_CASE("testing oneof, submessage") { - test_struct_pb::SampleMessageOneof t; - auto sub = new test_struct_pb::SubMessageForOneof{true}; - t.set_allocated_sub_message(sub); - check_self(t); -#ifdef HAVE_PROTOBUF - SampleMessageOneof pb_t; - auto m = new SubMessageForOneof(); - m->set_ok(true); - pb_t.set_allocated_sub_message(m); - check_with_protobuf(t, pb_t); -#endif -} diff --git a/website/docs/zh/guide/what_is_yalantinglibs.md b/website/docs/zh/guide/what_is_yalantinglibs.md index 9356d2625..fd484bf13 100644 --- a/website/docs/zh/guide/what_is_yalantinglibs.md +++ b/website/docs/zh/guide/what_is_yalantinglibs.md @@ -426,11 +426,9 @@ yalantinglibs工程自身支持如下配置项,如果你使用cmake find_packa 无依赖。 -### struct_pb (可选) +### struct_pb -默认情况下我们不会安装struct_pb, 你需要手动安装以下依赖: - -- [protobuf](https://protobuf.dev/) +无依赖。 ## 独立子仓库 From 1514a3bcddd03880f6573b5c8f561574eba792ba Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 22 May 2024 16:05:46 +0800 Subject: [PATCH 05/26] clean some doc --- website/.vitepress/config/en_data.ts | 38 ++- website/.vitepress/config/zh_data.ts | 4 - .../docs/en/guide/what_is_yalantinglibs.md | 6 +- .../struct_pb/images/struct_pb_overview.jpeg | Bin 68961 -> 0 bytes website/docs/en/struct_pb/struct_pb_api.md | 65 ----- .../struct_pb_generating_your_struct.md | 34 --- .../en/struct_pb/struct_pb_guide_proto3.md | 194 -------------- website/docs/en/struct_pb/struct_pb_intro.md | 3 - .../en/struct_pb/struct_pb_quick_start.md | 237 ------------------ website/docs/zh/struct_pb/struct_pb_api.md | 65 ----- .../struct_pb_generating_your_struct.md | 34 --- .../zh/struct_pb/struct_pb_guide_proto3.md | 194 -------------- website/docs/zh/struct_pb/struct_pb_intro.md | 3 - .../zh/struct_pb/struct_pb_quick_start.md | 237 ------------------ 14 files changed, 19 insertions(+), 1095 deletions(-) delete mode 100644 website/docs/en/struct_pb/images/struct_pb_overview.jpeg delete mode 100644 website/docs/en/struct_pb/struct_pb_api.md delete mode 100644 website/docs/en/struct_pb/struct_pb_generating_your_struct.md delete mode 100644 website/docs/en/struct_pb/struct_pb_guide_proto3.md delete mode 100644 website/docs/en/struct_pb/struct_pb_quick_start.md delete mode 100644 website/docs/zh/struct_pb/struct_pb_api.md delete mode 100644 website/docs/zh/struct_pb/struct_pb_generating_your_struct.md delete mode 100644 website/docs/zh/struct_pb/struct_pb_guide_proto3.md delete mode 100644 website/docs/zh/struct_pb/struct_pb_quick_start.md diff --git a/website/.vitepress/config/en_data.ts b/website/.vitepress/config/en_data.ts index 76b640ecb..980b764b2 100644 --- a/website/.vitepress/config/en_data.ts +++ b/website/.vitepress/config/en_data.ts @@ -1,36 +1,32 @@ export const guidLinks = [ - {text: 'Introduce YalantingLibs', link: '/en/guide/what_is_yalantinglibs'}, - {text: 'Use as Git Submodule', link: '/en/guide/how_to_use_as_git_submodule'}, - {text: 'Use by CMake find_package', link: '/en/guide/how_to_use_by_cmake_find_package'}, + { text: 'Introduce YalantingLibs', link: '/en/guide/what_is_yalantinglibs' }, + { text: 'Use as Git Submodule', link: '/en/guide/how_to_use_as_git_submodule' }, + { text: 'Use by CMake find_package', link: '/en/guide/how_to_use_by_cmake_find_package' }, ]; //构建系统相关语法 export const struct_pb_Links = [ - {text: 'What is struct_pb?', link: '/en/struct_pb/struct_pb_intro'}, - {text: 'Quick Start', link: '/en/struct_pb/struct_pb_quick_start'}, - {text: 'Supported Features', link: '/en/struct_pb/struct_pb_supported_features'}, - {text: 'Guide (proto3)', link: '/en/struct_pb/struct_pb_guide_proto3'}, - {text: 'Generating your struct', link: '/en/struct_pb/struct_pb_generating_your_struct'}, - {text: 'struct_pb API', link: '/en/struct_pb/struct_pb_api'}, + { text: 'What is struct_pb?', link: '/en/struct_pb/struct_pb_intro' }, + { text: 'Supported Features', link: '/en/struct_pb/struct_pb_supported_features' }, ]; export const struct_pack_Links = [ - {text: 'What is struct_pack?', link: '/en/struct_pack/struct_pack_intro'}, - {text: 'struct_pack tips', link: '/en/struct_pack/struct_pack_tips'}, - {text: 'struct_pack layout', link: '/en/struct_pack/struct_pack_layout'}, - {text: 'struct_pack type system', link: '/en/struct_pack/struct_pack_type_system'}, - {text: 'API Reference', link: "https://alibaba.github.io/yalantinglibs/doxygen_en/html/group__struct__pack.html"} + { text: 'What is struct_pack?', link: '/en/struct_pack/struct_pack_intro' }, + { text: 'struct_pack tips', link: '/en/struct_pack/struct_pack_tips' }, + { text: 'struct_pack layout', link: '/en/struct_pack/struct_pack_layout' }, + { text: 'struct_pack type system', link: '/en/struct_pack/struct_pack_type_system' }, + { text: 'API Reference', link: "https://alibaba.github.io/yalantinglibs/doxygen_en/html/group__struct__pack.html" } ]; export const coro_rpc_Links = [ - {text: 'coro_rpc introduction', link: '/en/coro_rpc/coro_rpc_introduction'}, - {text: 'coro_rpc client', link: '/en/coro_rpc/coro_rpc_client'}, - {text: 'coro_rpc server', link: '/en/coro_rpc/coro_rpc_server'}, + { text: 'coro_rpc introduction', link: '/en/coro_rpc/coro_rpc_introduction' }, + { text: 'coro_rpc client', link: '/en/coro_rpc/coro_rpc_client' }, + { text: 'coro_rpc server', link: '/en/coro_rpc/coro_rpc_server' }, ]; export const aboutLinks = [ - {text: 'purecpp', link: '/en/about/community'}, - {text: 'contribute', link: '/en/about/contribute'}, - {text: 'community', link: '/en/about/teams'}, - {text: 'team', link: '/en/about/yalantingUser'}, + { text: 'purecpp', link: '/en/about/community' }, + { text: 'contribute', link: '/en/about/contribute' }, + { text: 'community', link: '/en/about/teams' }, + { text: 'team', link: '/en/about/yalantingUser' }, ]; diff --git a/website/.vitepress/config/zh_data.ts b/website/.vitepress/config/zh_data.ts index 5ef2088f0..e404ab2d4 100644 --- a/website/.vitepress/config/zh_data.ts +++ b/website/.vitepress/config/zh_data.ts @@ -7,11 +7,7 @@ export const guidLinks = [ //构建系统相关语法 export const struct_pb_Links = [ { text: 'struct_pb简介', link: '/zh/struct_pb/struct_pb_intro' }, - { text: '快速开始', link: '/zh/struct_pb/struct_pb_quick_start' }, { text: '特性支持', link: '/zh/struct_pb/struct_pb_supported_features' }, - { text: '使用proto3', link: '/zh/struct_pb/struct_pb_guide_proto3' }, - { text: '生成结构体', link: '/zh/struct_pb/struct_pb_generating_your_struct' }, - { text: 'struct_pb API', link: '/zh/struct_pb/struct_pb_api' }, ]; export const struct_pack_Links = [ diff --git a/website/docs/en/guide/what_is_yalantinglibs.md b/website/docs/en/guide/what_is_yalantinglibs.md index 3c253e96f..7b99e6274 100644 --- a/website/docs/en/guide/what_is_yalantinglibs.md +++ b/website/docs/en/guide/what_is_yalantinglibs.md @@ -504,11 +504,9 @@ No dependency. No dependency. -### struct_pb (optional) +### struct_pb -In default, struct_pb wont be installed. You need install protobuf manually. - -- [protobuf](https://protobuf.dev/) +No dependency. ## Standalone sublibraries diff --git a/website/docs/en/struct_pb/images/struct_pb_overview.jpeg b/website/docs/en/struct_pb/images/struct_pb_overview.jpeg deleted file mode 100644 index be0978d4051936fc9c949bfc36ead2482daf4fa8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 68961 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⪚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 // message, field number = 9 - > test_oneof; - - bool has_name() const { - return test_oneof.index() == 1; - } - void set_name(std::string name) { - test_oneof.emplace<1>(std::move(name)); - } - const std::string& name() const { - assert(test_oneof.index() == 1); - return std::get<1>(test_oneof); - } - - bool has_sub_message() const { - return test_oneof.index() == 2; - } - void set_allocated_sub_message(::SubMessage* p) { - assert(p); - test_oneof.emplace<2>(p); - } - const std::unique_ptr<::SubMessage>& sub_message() const { - assert(test_oneof.index() == 2); - return std::get<2>(test_oneof); - } -}; -struct SubMessage { - int32_t val; // int32, field number = 1 -}; -``` - -## Maps - -``` -syntax = "proto3"; -message SampleMap { - map projects = 3; -} -message Project { - string name = 1; -} -``` - -```cpp -struct SampleMap { - std::map projects; // message, field number = 3 -}; -struct Project { - std::string name; // string, field number = 1 -}; -``` \ No newline at end of file diff --git a/website/docs/en/struct_pb/struct_pb_intro.md b/website/docs/en/struct_pb/struct_pb_intro.md index 746f4385d..d833e38db 100644 --- a/website/docs/en/struct_pb/struct_pb_intro.md +++ b/website/docs/en/struct_pb/struct_pb_intro.md @@ -18,9 +18,6 @@ Tag = (field_number << 3) | wire_type ### Base 128 Varints Variable-width integers, or _varints_, are at the core of the wire format. They allow encoding unsigned 64-bit integers using anywhere between one and ten bytes, with small values using fewer bytes. -## Design -![](images/struct_pb_overview.jpeg) - ## Type Mapping proto3 first, see also [Protocol Buffers Language Guide (proto3)](https://developers.google.com/protocol-buffers/docs/proto3#scalar) diff --git a/website/docs/en/struct_pb/struct_pb_quick_start.md b/website/docs/en/struct_pb/struct_pb_quick_start.md deleted file mode 100644 index 28fdb4d3c..000000000 --- a/website/docs/en/struct_pb/struct_pb_quick_start.md +++ /dev/null @@ -1,237 +0,0 @@ -# struct_pb Quick Start - -Note: if you are not familiar with the official c++ implement, -[Protocol Buffer Basics: C++](https://developers.google.com/protocol-buffers/docs/cpptutorial) -is a good material to learn. - -This tutorial provides a basic C++ programmer's introduction to work with struct_pb, -which is the protobuf compatible solution of the [yalantinglibs](https://github.com/alibaba/yalantinglibs). - -By walking through creating a simple example application, it shows you how to - -- Define message formats in a `.proto` file. (same as official protobuf document) -- Use the protocol buffer compiler (`protoc`) with `struct_pb` plugin. -- Use the `struct_pb` low-level API to write and read messages. - -## Defining Your Protocol Format - -we use proto3 here. - -``` -syntax = "proto3"; - -package tutorial; - -message Person { - string name = 1; - int32 id = 2; - string email = 3; - - enum PhoneType { - MOBILE = 0; - HOME = 1; - WORK = 2; - } - - message PhoneNumber { - string number = 1; - PhoneType type = 2; - } - - repeated PhoneNumber phones = 4; -} - -message AddressBook { - repeated Person people = 1; -} - -``` - -## Compiling Your Protocol Buffers - -Now that you have a `.proto`, the next thing you need to do is generate the struct you'll need to -read and write `AddressBook` (and hence `Person` and `PhoneNumber`) messages. -To do this, you need to run the protocol buffer compiler `protoc` with `struct_pb` plugin `protoc-gen-struct_pb` on your `.proto`. - -```shell -protoc -I=$SRC_DIR --plugin=$PATH_TO_protoc-gen-struct_pb --struct_pb_out=$DST_DIR $SRC_DIR/addressbook.proto -``` -see [Generating source code](https://alibaba.github.io/yalantinglibs/en/struct_pb/struct_pb_generating_your_struct.html) for details. - -This generates the following files in your specified destination directory: - -- `addressbook.struct_pb.h`, the header which declares your generated struct. -- `addressbook.struct_pb.cc`, which contains the `struct_pb` low-level API implementation of your struct. - - -## The struct_pb low-level API - -Let's look at some generated code and see what struct and functions the compiler has created for you. -If you look in `addressbook.struct_pb.h`, you can see that you have a struct for each message you specified in `addressbook.proto`. - - -```cpp - -namespace tutorial { -struct Person; -struct AddressBook; -struct Person { - enum class PhoneType: int { - MOBILE = 0, - HOME = 1, - WORK = 2, - }; - struct PhoneNumber { - std::string number; // string, field number = 1 - ::tutorial::Person::PhoneType type; // enum, field number = 2 - }; - std::string name; // string, field number = 1 - int32_t id; // int32, field number = 2 - std::string email; // string, field number = 3 - std::vector<::tutorial::Person::PhoneNumber> phones; // message, field number = 4 -}; -struct AddressBook { - std::vector<::tutorial::Person> people; // message, field number = 1 -}; - -} // namespace tutorial -namespace struct_pb { -namespace internal { -// ::tutorial::Person::PhoneNumber -template<> -std::size_t get_needed_size<::tutorial::Person::PhoneNumber>(const ::tutorial::Person::PhoneNumber&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -void serialize_to<::tutorial::Person::PhoneNumber>(char*, std::size_t, const ::tutorial::Person::PhoneNumber&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person::PhoneNumber>(::tutorial::Person::PhoneNumber&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person::PhoneNumber>(::tutorial::Person::PhoneNumber&, const char*, std::size_t); - -// ::tutorial::Person -template<> -std::size_t get_needed_size<::tutorial::Person>(const ::tutorial::Person&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -void serialize_to<::tutorial::Person>(char*, std::size_t, const ::tutorial::Person&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person>(::tutorial::Person&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person>(::tutorial::Person&, const char*, std::size_t); - -// ::tutorial::AddressBook -template<> -std::size_t get_needed_size<::tutorial::AddressBook>(const ::tutorial::AddressBook&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -void serialize_to<::tutorial::AddressBook>(char*, std::size_t, const ::tutorial::AddressBook&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::AddressBook>(::tutorial::AddressBook&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::AddressBook>(::tutorial::AddressBook&, const char*, std::size_t); - -} // internal -} // struct_pb -``` - -## The struct_pb high-level API - -We encapsulate the low-level API to make `struct_pb` easier to use. - -``` -/* - * High-Level API for struct_pb user - * If you need more fine-grained operations, encapsulate the internal API yourself. - */ -template, typename T> -Buffer serialize(const T& t, const UnknownFields& unknown_fields = {}) { - Buffer buffer; - auto size = struct_pb::internal::get_needed_size(t, unknown_fields); - buffer.resize(size); - struct_pb::internal::serialize_to(buffer.data(), buffer.size(), t, unknown_fields); - return buffer; -} -template -bool deserialize_to(T& t, UnknownFields& unknown_fields, const Buffer& buffer) { - return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size(), unknown_fields); -} -template -bool deserialize_to(T& t, const Buffer& buffer) { - return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size()); -} - -``` - -## Writing A Message - -```cpp -void prompt_for_address(tutorial::Person& person) { - std::cout << "==================================" << std::endl; - std::cout << " Add People " << std::endl; - std::cout << "==================================" << std::endl; - std::cout << "Enter person ID number: "; - std::cin >> person.id; - std::cin.ignore(256, '\n'); - std::cout << "Enter name: "; - std::getline(std::cin, person.name); - std::cout << "Enter email address (blank for none): "; - std::getline(std::cin, person.email); - while (true) { - std::cout << "Enter a phone number (or leave blank to finish): "; - tutorial::Person::PhoneNumber phone_number; - std::getline(std::cin, phone_number.number); - if (phone_number.number.empty()) { - break ; - } - std::cout << "Is this a mobile, home, or work phone? "; - std::string type; - std::getline(std::cin, type); - if (type == "mobile") { - phone_number.type = tutorial::Person::PhoneType::MOBILE; - } - else if (type == "home") { - phone_number.type = tutorial::Person::PhoneType::HOME; - } - else if (type == "work") { - phone_number.type = tutorial::Person::PhoneType::WORK; - } - else { - std::cout << "Unknown phone type: Using default." << std::endl; - } - person.phones.push_back(phone_number); - } -} -``` - -## Reading A Message - -```cpp -void list_people(const tutorial::AddressBook& address_book) { - std::cout << "==================================" << std::endl; - std::cout << " List People " << std::endl; - std::cout << "==================================" << std::endl; - for(const auto& person: address_book.people) { - std::cout << " Person ID: " << person.id << std::endl; - std::cout << " Name: " << person.name << std::endl; - if (!person.email.empty()) { - std::cout << "E-mail address: " << person.email << std::endl; - } - for(const auto& phone: person.phones) { - switch (phone.type) { - case tutorial::Person::PhoneType::MOBILE: - std::cout << "Mobile phone #: "; - break; - case tutorial::Person::PhoneType::HOME: - std::cout << " Home phone #: "; - break; - case tutorial::Person::PhoneType::WORK: - std::cout << " Work phone #: "; - break; - } - std::cout << phone.number << std::endl; - } - } -} -``` - -## the demo code - -- [code in yalantinglibs repo](https://github.com/alibaba/yalantinglibs/blob/main/src/struct_pb/examples/tutorial.cpp) -- [code in standalone repo](https://github.com/PikachuHyA/struct_pb_tutorial) diff --git a/website/docs/zh/struct_pb/struct_pb_api.md b/website/docs/zh/struct_pb/struct_pb_api.md deleted file mode 100644 index 2bc379d4e..000000000 --- a/website/docs/zh/struct_pb/struct_pb_api.md +++ /dev/null @@ -1,65 +0,0 @@ -# struct_pb API - -Current, struct_pb provide low-level APIs only, which are in namespace `struct_pb::internal`. - -For example, the `SearchRequest` message from [Language Guide (proto3)](https://developers.google.com/protocol-buffers/docs/proto3#simple) - -``` -syntax = "proto3"; - -message SearchRequest { - string query = 1; - int32 page_number = 2; - int32 result_per_page = 3; -} -``` - -we generate the source code -```cpp -struct SearchRequest { - std::string query; // string, field number = 1 - int32_t page_number; // int32, field number = 2 - int32_t result_per_page; // int32, field number = 3 -}; - -namespace struct_pb { -namespace internal { -// ::SearchRequest -std::size_t get_needed_size(const ::SearchRequest&, const ::struct_pb::UnknownFields& unknown_fields = {}); -void serialize_to(char*, std::size_t, const ::SearchRequest&, const ::struct_pb::UnknownFields& unknown_fields = {}); -bool deserialize_to(::SearchRequest&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -bool deserialize_to(::SearchRequest&, const char*, std::size_t); - -} // internal -} // struct_pb -``` - -## Serialization - -- get_needed_size - -To get the buffer size, use the `get_needed_size` function. - -To support [Unknown Fields](https://developers.google.com/protocol-buffers/docs/proto3#unknowns), -an extra argument `unknown_fields` with default value is added. - -- serialize_to - -To serialize a message to a buffer, use the `serialize_to` function. - -Before use this function, make sure the buffer is sufficiently large. -e.g. use `get_needed_size` and then allocate buffer. - -To support [Unknown Fields](https://developers.google.com/protocol-buffers/docs/proto3#unknowns), -an extra argument `unknown_fields` with default value is added. - -## Deserialization - -- deserialize_to - -To deserialize a message from buffer, use the `deserialize_to` function. - -Returns true on success. - -To support [Unknown Fields](https://developers.google.com/protocol-buffers/docs/proto3#unknowns), -the overload function with an extra argument `unknown_fields` is added. diff --git a/website/docs/zh/struct_pb/struct_pb_generating_your_struct.md b/website/docs/zh/struct_pb/struct_pb_generating_your_struct.md deleted file mode 100644 index 10b2d0021..000000000 --- a/website/docs/zh/struct_pb/struct_pb_generating_your_struct.md +++ /dev/null @@ -1,34 +0,0 @@ -# Generating source code - -First, you need install protobuf. - -on Mac -```shell -brew install protobuf -``` - -on Ubuntu -```shell -apt-get install protobuf -``` - -on CentOS -```shell -yum install protobuf -``` - -Second, you need install or compile struct_pb protoc plugin `protoc-gen-struct_pb`. - -Finally, you can use the following command to generate the code. - -```shell -protoc --plugin=protoc-gen-struct_pb --struct_pb_out . xxx.proto -``` - -or use the helper function on your `CMakeLists.txt` - -```cmake -find_package(Protobuf) -protobuf_generate_struct_pb(PROTO_SRCS PROTO_HDRS xxxx.proto) -``` - diff --git a/website/docs/zh/struct_pb/struct_pb_guide_proto3.md b/website/docs/zh/struct_pb/struct_pb_guide_proto3.md deleted file mode 100644 index 9366ccb28..000000000 --- a/website/docs/zh/struct_pb/struct_pb_guide_proto3.md +++ /dev/null @@ -1,194 +0,0 @@ -# struct_pb Guide (proto3) - -## Defining A Message Type - -Here is a simple message type from [official document - Defining A Message Type](https://developers.google.com/protocol-buffers/docs/proto3#simple). - -``` -syntax = "proto3"; - -message SearchRequest { - string query = 1; - int32 page_number = 2; - int32 result_per_page = 3; -} -``` -Our protoc plugin convert the message type to C++ struct and corresponding low-level serialization API. - -```cpp -struct SearchRequest { - std::string query; // string, field number = 1 - int32_t page_number; // int32, field number = 2 - int32_t result_per_page; // int32, field number = 3 -}; -namespace struct_pb { -namespace internal { -// ::SearchRequest -std::size_t get_needed_size(const ::SearchRequest&, const ::struct_pb::UnknownFields& unknown_fields = {}); -void serialize_to(char*, std::size_t, const ::SearchRequest&, const ::struct_pb::UnknownFields& unknown_fields = {}); -bool deserialize_to(::SearchRequest&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -bool deserialize_to(::SearchRequest&, const char*, std::size_t); - -} // internal -} // struct_pb -``` - -You can use the struct `SearchRequest` as a normal C++ struct. - -## Enumerations - -``` -syntax = "proto3"; -enum Corpus { - CORPUS_UNSPECIFIED = 0; - CORPUS_UNIVERSAL = 1; - CORPUS_WEB = 2; - CORPUS_IMAGES = 3; - CORPUS_LOCAL = 4; - CORPUS_NEWS = 5; - CORPUS_PRODUCTS = 6; - CORPUS_VIDEO = 7; -} -``` - -```cpp -enum class Corpus: int { - CORPUS_UNSPECIFIED = 0, - CORPUS_UNIVERSAL = 1, - CORPUS_WEB = 2, - CORPUS_IMAGES = 3, - CORPUS_LOCAL = 4, - CORPUS_NEWS = 5, - CORPUS_PRODUCTS = 6, - CORPUS_VIDEO = 7, -}; -``` - -## Nested messages - -Here is the sample from [proto3 Nested Types](https://developers.google.com/protocol-buffers/docs/proto3#nested) - -``` -syntax = "proto3"; -message Outer { // Level 0 - message MiddleAA { // Level 1 - message Inner { // Level 2 - int64 ival = 1; - bool booly = 2; - } - } - message MiddleBB { // Level 1 - message Inner { // Level 2 - int32 ival = 1; - bool booly = 2; - } - } -} -``` - -```cpp -struct Outer { - struct MiddleAA { - struct Inner { - int64_t ival; // int64, field number = 1 - bool booly; // bool, field number = 2 - }; - }; - struct MiddleBB { - struct Inner { - int32_t ival; // int32, field number = 1 - bool booly; // bool, field number = 2 - }; - }; -}; -``` - -## Oneof - -Here is the sample from [proto3 Oneof](https://developers.google.com/protocol-buffers/docs/proto3#oneof) - -``` -syntax = "proto3"; -message SampleMessage { - oneof test_oneof { - string name = 4; - SubMessage sub_message = 9; - } -} -message SubMessage { - int32 val = 1; -} -``` -The oneof type is mapped to `std::varint` with lots of helper functions. - -```cpp -struct SampleMessage { - enum class TestOneofCase { - none = 0, - name = 4, - sub_message = 9, - }; - TestOneofCase test_oneof_case() const { - switch (test_oneof.index()) { - case 1: - return TestOneofCase::name; - case 2: - return TestOneofCase::sub_message; - default: - return TestOneofCase::none; - } - } - - std::variant // message, field number = 9 - > test_oneof; - - bool has_name() const { - return test_oneof.index() == 1; - } - void set_name(std::string name) { - test_oneof.emplace<1>(std::move(name)); - } - const std::string& name() const { - assert(test_oneof.index() == 1); - return std::get<1>(test_oneof); - } - - bool has_sub_message() const { - return test_oneof.index() == 2; - } - void set_allocated_sub_message(::SubMessage* p) { - assert(p); - test_oneof.emplace<2>(p); - } - const std::unique_ptr<::SubMessage>& sub_message() const { - assert(test_oneof.index() == 2); - return std::get<2>(test_oneof); - } -}; -struct SubMessage { - int32_t val; // int32, field number = 1 -}; -``` - -## Maps - -``` -syntax = "proto3"; -message SampleMap { - map projects = 3; -} -message Project { - string name = 1; -} -``` - -```cpp -struct SampleMap { - std::map projects; // message, field number = 3 -}; -struct Project { - std::string name; // string, field number = 1 -}; -``` \ No newline at end of file diff --git a/website/docs/zh/struct_pb/struct_pb_intro.md b/website/docs/zh/struct_pb/struct_pb_intro.md index 746f4385d..d833e38db 100644 --- a/website/docs/zh/struct_pb/struct_pb_intro.md +++ b/website/docs/zh/struct_pb/struct_pb_intro.md @@ -18,9 +18,6 @@ Tag = (field_number << 3) | wire_type ### Base 128 Varints Variable-width integers, or _varints_, are at the core of the wire format. They allow encoding unsigned 64-bit integers using anywhere between one and ten bytes, with small values using fewer bytes. -## Design -![](images/struct_pb_overview.jpeg) - ## Type Mapping proto3 first, see also [Protocol Buffers Language Guide (proto3)](https://developers.google.com/protocol-buffers/docs/proto3#scalar) diff --git a/website/docs/zh/struct_pb/struct_pb_quick_start.md b/website/docs/zh/struct_pb/struct_pb_quick_start.md deleted file mode 100644 index 28fdb4d3c..000000000 --- a/website/docs/zh/struct_pb/struct_pb_quick_start.md +++ /dev/null @@ -1,237 +0,0 @@ -# struct_pb Quick Start - -Note: if you are not familiar with the official c++ implement, -[Protocol Buffer Basics: C++](https://developers.google.com/protocol-buffers/docs/cpptutorial) -is a good material to learn. - -This tutorial provides a basic C++ programmer's introduction to work with struct_pb, -which is the protobuf compatible solution of the [yalantinglibs](https://github.com/alibaba/yalantinglibs). - -By walking through creating a simple example application, it shows you how to - -- Define message formats in a `.proto` file. (same as official protobuf document) -- Use the protocol buffer compiler (`protoc`) with `struct_pb` plugin. -- Use the `struct_pb` low-level API to write and read messages. - -## Defining Your Protocol Format - -we use proto3 here. - -``` -syntax = "proto3"; - -package tutorial; - -message Person { - string name = 1; - int32 id = 2; - string email = 3; - - enum PhoneType { - MOBILE = 0; - HOME = 1; - WORK = 2; - } - - message PhoneNumber { - string number = 1; - PhoneType type = 2; - } - - repeated PhoneNumber phones = 4; -} - -message AddressBook { - repeated Person people = 1; -} - -``` - -## Compiling Your Protocol Buffers - -Now that you have a `.proto`, the next thing you need to do is generate the struct you'll need to -read and write `AddressBook` (and hence `Person` and `PhoneNumber`) messages. -To do this, you need to run the protocol buffer compiler `protoc` with `struct_pb` plugin `protoc-gen-struct_pb` on your `.proto`. - -```shell -protoc -I=$SRC_DIR --plugin=$PATH_TO_protoc-gen-struct_pb --struct_pb_out=$DST_DIR $SRC_DIR/addressbook.proto -``` -see [Generating source code](https://alibaba.github.io/yalantinglibs/en/struct_pb/struct_pb_generating_your_struct.html) for details. - -This generates the following files in your specified destination directory: - -- `addressbook.struct_pb.h`, the header which declares your generated struct. -- `addressbook.struct_pb.cc`, which contains the `struct_pb` low-level API implementation of your struct. - - -## The struct_pb low-level API - -Let's look at some generated code and see what struct and functions the compiler has created for you. -If you look in `addressbook.struct_pb.h`, you can see that you have a struct for each message you specified in `addressbook.proto`. - - -```cpp - -namespace tutorial { -struct Person; -struct AddressBook; -struct Person { - enum class PhoneType: int { - MOBILE = 0, - HOME = 1, - WORK = 2, - }; - struct PhoneNumber { - std::string number; // string, field number = 1 - ::tutorial::Person::PhoneType type; // enum, field number = 2 - }; - std::string name; // string, field number = 1 - int32_t id; // int32, field number = 2 - std::string email; // string, field number = 3 - std::vector<::tutorial::Person::PhoneNumber> phones; // message, field number = 4 -}; -struct AddressBook { - std::vector<::tutorial::Person> people; // message, field number = 1 -}; - -} // namespace tutorial -namespace struct_pb { -namespace internal { -// ::tutorial::Person::PhoneNumber -template<> -std::size_t get_needed_size<::tutorial::Person::PhoneNumber>(const ::tutorial::Person::PhoneNumber&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -void serialize_to<::tutorial::Person::PhoneNumber>(char*, std::size_t, const ::tutorial::Person::PhoneNumber&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person::PhoneNumber>(::tutorial::Person::PhoneNumber&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person::PhoneNumber>(::tutorial::Person::PhoneNumber&, const char*, std::size_t); - -// ::tutorial::Person -template<> -std::size_t get_needed_size<::tutorial::Person>(const ::tutorial::Person&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -void serialize_to<::tutorial::Person>(char*, std::size_t, const ::tutorial::Person&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person>(::tutorial::Person&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::Person>(::tutorial::Person&, const char*, std::size_t); - -// ::tutorial::AddressBook -template<> -std::size_t get_needed_size<::tutorial::AddressBook>(const ::tutorial::AddressBook&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -void serialize_to<::tutorial::AddressBook>(char*, std::size_t, const ::tutorial::AddressBook&, const ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::AddressBook>(::tutorial::AddressBook&, const char*, std::size_t, ::struct_pb::UnknownFields& unknown_fields); -template<> -bool deserialize_to<::tutorial::AddressBook>(::tutorial::AddressBook&, const char*, std::size_t); - -} // internal -} // struct_pb -``` - -## The struct_pb high-level API - -We encapsulate the low-level API to make `struct_pb` easier to use. - -``` -/* - * High-Level API for struct_pb user - * If you need more fine-grained operations, encapsulate the internal API yourself. - */ -template, typename T> -Buffer serialize(const T& t, const UnknownFields& unknown_fields = {}) { - Buffer buffer; - auto size = struct_pb::internal::get_needed_size(t, unknown_fields); - buffer.resize(size); - struct_pb::internal::serialize_to(buffer.data(), buffer.size(), t, unknown_fields); - return buffer; -} -template -bool deserialize_to(T& t, UnknownFields& unknown_fields, const Buffer& buffer) { - return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size(), unknown_fields); -} -template -bool deserialize_to(T& t, const Buffer& buffer) { - return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size()); -} - -``` - -## Writing A Message - -```cpp -void prompt_for_address(tutorial::Person& person) { - std::cout << "==================================" << std::endl; - std::cout << " Add People " << std::endl; - std::cout << "==================================" << std::endl; - std::cout << "Enter person ID number: "; - std::cin >> person.id; - std::cin.ignore(256, '\n'); - std::cout << "Enter name: "; - std::getline(std::cin, person.name); - std::cout << "Enter email address (blank for none): "; - std::getline(std::cin, person.email); - while (true) { - std::cout << "Enter a phone number (or leave blank to finish): "; - tutorial::Person::PhoneNumber phone_number; - std::getline(std::cin, phone_number.number); - if (phone_number.number.empty()) { - break ; - } - std::cout << "Is this a mobile, home, or work phone? "; - std::string type; - std::getline(std::cin, type); - if (type == "mobile") { - phone_number.type = tutorial::Person::PhoneType::MOBILE; - } - else if (type == "home") { - phone_number.type = tutorial::Person::PhoneType::HOME; - } - else if (type == "work") { - phone_number.type = tutorial::Person::PhoneType::WORK; - } - else { - std::cout << "Unknown phone type: Using default." << std::endl; - } - person.phones.push_back(phone_number); - } -} -``` - -## Reading A Message - -```cpp -void list_people(const tutorial::AddressBook& address_book) { - std::cout << "==================================" << std::endl; - std::cout << " List People " << std::endl; - std::cout << "==================================" << std::endl; - for(const auto& person: address_book.people) { - std::cout << " Person ID: " << person.id << std::endl; - std::cout << " Name: " << person.name << std::endl; - if (!person.email.empty()) { - std::cout << "E-mail address: " << person.email << std::endl; - } - for(const auto& phone: person.phones) { - switch (phone.type) { - case tutorial::Person::PhoneType::MOBILE: - std::cout << "Mobile phone #: "; - break; - case tutorial::Person::PhoneType::HOME: - std::cout << " Home phone #: "; - break; - case tutorial::Person::PhoneType::WORK: - std::cout << " Work phone #: "; - break; - } - std::cout << phone.number << std::endl; - } - } -} -``` - -## the demo code - -- [code in yalantinglibs repo](https://github.com/alibaba/yalantinglibs/blob/main/src/struct_pb/examples/tutorial.cpp) -- [code in standalone repo](https://github.com/PikachuHyA/struct_pb_tutorial) From 7e037c1a62d741434878c6b6e244e7e5bd5b0391 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 22 May 2024 16:20:39 +0800 Subject: [PATCH 06/26] rename --- include/ylt/struct_pb.hpp | 89 +----- include/ylt/struct_pb/struct_pb_impl.hpp | 173 +---------- include/ylt/struct_pb/struct_pb_reader.hpp | 18 -- include/ylt/struct_pb/struct_pb_writer.hpp | 18 -- include/ylt/struct_pb0.hpp | 18 -- src/struct_pack/benchmark/benchmark.cpp | 12 +- src/struct_pack/benchmark/config.hpp | 9 +- .../benchmark/struct_pb_sample.hpp | 275 ++++++++++-------- .../benchmark/struct_pb_sample0.hpp | 210 ------------- 9 files changed, 164 insertions(+), 658 deletions(-) delete mode 100644 include/ylt/struct_pb/struct_pb_reader.hpp delete mode 100644 include/ylt/struct_pb/struct_pb_writer.hpp delete mode 100644 include/ylt/struct_pb0.hpp delete mode 100644 src/struct_pack/benchmark/struct_pb_sample0.hpp diff --git a/include/ylt/struct_pb.hpp b/include/ylt/struct_pb.hpp index a57ea241d..b49a220eb 100644 --- a/include/ylt/struct_pb.hpp +++ b/include/ylt/struct_pb.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Alibaba Group Holding Limited; + * Copyright (c) 2024, Alibaba Group Holding Limited; * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,89 +14,4 @@ * limitations under the License. */ #pragma once -#include -#include -#include -#include -#if defined __clang__ -#define STRUCT_PB_INLINE __attribute__((always_inline)) inline -#elif defined _MSC_VER -#define STRUCT_PB_INLINE __forceinline -#else -#define STRUCT_PB_INLINE __attribute__((always_inline)) inline -#endif -#define STRUCT_PB_NODISCARD [[nodiscard]] -namespace struct_pb { - -struct UnknownFields { - STRUCT_PB_NODISCARD std::size_t total_size() const { - std::size_t total = 0; - for (const auto& f : fields) { - total += f.len; - } - return total; - } - void serialize_to(char* data, std::size_t& pos, std::size_t size) const { - for (const auto& f : fields) { - assert(pos + f.len <= size); - std::memcpy(data + pos, f.data, f.len); - pos += f.len; - } - } - void add_field(const char* data, std::size_t start, std::size_t end) { - fields.push_back(Field{data + start, end - start}); - } - struct Field { - const char* data; - std::size_t len; - }; - std::vector fields; -}; -/* - * Low-Level API for struct_pb user - * the following internal API will be generated by struct_pb protoc plugin - */ -namespace internal { -template -STRUCT_PB_NODISCARD std::size_t get_needed_size( - const T& t, const UnknownFields& unknown_fields = {}); -template -void serialize_to(char* data, std::size_t size, const T& t, - const UnknownFields& unknown_fields = {}); -template -STRUCT_PB_NODISCARD bool deserialize_to(T& t, const char* data, - std::size_t size, - UnknownFields& unknown_fields); -template -STRUCT_PB_NODISCARD bool deserialize_to(T& t, const char* data, - std::size_t size); -} // namespace internal - -/* - * High-Level API for struct_pb user - * If you need more fine-grained operations, encapsulate the internal API - * yourself. - */ -template , typename T> -STRUCT_PB_NODISCARD Buffer serialize(const T& t, - const UnknownFields& unknown_fields = {}) { - Buffer buffer; - auto size = struct_pb::internal::get_needed_size(t, unknown_fields); - buffer.resize(size); - struct_pb::internal::serialize_to(buffer.data(), buffer.size(), t, - unknown_fields); - return buffer; -} -template -STRUCT_PB_NODISCARD STRUCT_PB_INLINE bool deserialize_to( - T& t, UnknownFields& unknown_fields, const Buffer& buffer) { - return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size(), - unknown_fields); -} -template -STRUCT_PB_NODISCARD STRUCT_PB_INLINE bool deserialize_to(T& t, - const Buffer& buffer) { - return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size()); -} - -} // namespace struct_pb +#include "struct_pb/struct_pb_impl.hpp" diff --git a/include/ylt/struct_pb/struct_pb_impl.hpp b/include/ylt/struct_pb/struct_pb_impl.hpp index 12a2a76c2..909995d8c 100644 --- a/include/ylt/struct_pb/struct_pb_impl.hpp +++ b/include/ylt/struct_pb/struct_pb_impl.hpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2023, Alibaba Group Holding Limited; + * Copyright (c) 2024, Alibaba Group Holding Limited; * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -14,171 +14,6 @@ * limitations under the License. */ #pragma once -#include -#include -#include -#include -#include - -#include "ylt/struct_pb.hpp" - -namespace struct_pb { - -namespace internal { -STRUCT_PB_NODISCARD STRUCT_PB_INLINE uint32_t encode_zigzag(int32_t v) { - return (static_cast(v) << 1U) ^ - static_cast( - -static_cast(static_cast(v) >> 31U)); -} -STRUCT_PB_NODISCARD STRUCT_PB_INLINE uint64_t encode_zigzag(int64_t v) { - return (static_cast(v) << 1U) ^ - static_cast( - -static_cast(static_cast(v) >> 63U)); -} - -STRUCT_PB_NODISCARD STRUCT_PB_INLINE int64_t decode_zigzag(uint64_t u) { - return static_cast((u >> 1U)) ^ - static_cast(-static_cast(u & 1U)); -} -STRUCT_PB_NODISCARD STRUCT_PB_INLINE int64_t decode_zigzag(uint32_t u) { - return static_cast((u >> 1U)) ^ - static_cast(-static_cast(u & 1U)); -} - -STRUCT_PB_NODISCARD STRUCT_PB_INLINE std::size_t calculate_varint_size( - uint64_t v) { - std::size_t ret = 0; - do { - ret++; - v >>= 7; - } while (v != 0); - return ret; -} - -[[nodiscard]] STRUCT_PB_INLINE bool decode_varint(const char* data, - std::size_t& pos_, - std::size_t size_, - uint64_t& v) { - // fix test failed on arm due to different char definition - const signed char* data_ = reinterpret_cast(data); - // from https://github.com/facebook/folly/blob/main/folly/Varint.h - if (pos_ < size_ && (static_cast(data_[pos_]) & 0x80U) == 0) { - v = static_cast(data_[pos_]); - pos_++; - return true; - } - constexpr const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1; - uint64_t val = 0; - if (size_ - pos_ >= max_varint_length) [[likely]] { - do { - // clang-format off - int64_t b = data_[pos_++]; - val = ((uint64_t(b) & 0x7fU) ); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 7U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 14U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 21U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 28U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 35U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 42U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 49U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 56U); if (b >= 0) { break; } - b = data_[pos_++]; val |= ((uint64_t(b) & 0x01U) << 63U); if (b >= 0) { break; } - // clang-format on - return false; - } while (false); - } - else { - unsigned int shift = 0; - while (pos_ != size_ && int64_t(data_[pos_]) < 0) { - val |= (uint64_t(data_[pos_++]) & 0x7fU) << shift; - shift += 7; - } - if (pos_ == size_) { - return false; - } - val |= uint64_t(data_[pos_++]) << shift; - } - v = val; - return true; -} -STRUCT_PB_INLINE void serialize_varint(char* const data, std::size_t& pos, - std::size_t size, uint64_t v) { - while (v >= 0x80) { - assert(pos < size); - data[pos++] = static_cast(v | 0x80); - v >>= 7; - } - data[pos++] = static_cast(v); -} -STRUCT_PB_NODISCARD STRUCT_PB_INLINE bool deserialize_varint(const char* data, - std::size_t& pos, - std::size_t size, - uint64_t& v) { - return decode_varint(data, pos, size, v); -} -STRUCT_PB_NODISCARD STRUCT_PB_INLINE bool read_tag(const char* data, - std::size_t& pos, - std::size_t size, - uint64_t& tag) { - return deserialize_varint(data, pos, size, tag); -} -inline bool deserialize_unknown(const char* data, std::size_t& pos, - std::size_t size, uint32_t tag, - UnknownFields& unknown_fields) { - uint32_t field_number = tag >> 3; - if (field_number == 0) { - return false; - } - auto offset = internal::calculate_varint_size(tag); - auto start = pos - offset; - uint32_t wire_type = tag & 0b0000'0111; - switch (wire_type) { - case 0: { - uint64_t t; - auto ok = internal::deserialize_varint(data, pos, size, t); - if (!ok) [[unlikely]] { - return false; - } - unknown_fields.add_field(data, start, pos); - break; - } - case 1: { - static_assert(sizeof(double) == 8); - if (pos + 8 > size) [[unlikely]] { - return false; - } - pos += 8; - unknown_fields.add_field(data, start, pos); - break; - } - case 2: { - uint64_t sz; - auto ok = internal::deserialize_varint(data, pos, size, sz); - if (!ok) [[unlikely]] { - return false; - } - if (pos + sz > size) [[unlikely]] { - return false; - } - pos += sz; - unknown_fields.add_field(data, start, pos); - break; - } - case 5: { - static_assert(sizeof(float) == 4); - if (pos + 4 > size) [[unlikely]] { - return false; - } - pos += 4; - unknown_fields.add_field(data, start, pos); - break; - } - default: { - assert(false && "error path"); - } - } - return true; -} -} // namespace internal - -} // namespace struct_pb \ No newline at end of file +#include +#include +namespace struct_pb = iguana; diff --git a/include/ylt/struct_pb/struct_pb_reader.hpp b/include/ylt/struct_pb/struct_pb_reader.hpp deleted file mode 100644 index 5344e7b39..000000000 --- a/include/ylt/struct_pb/struct_pb_reader.hpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2024, Alibaba Group Holding Limited; - * - * 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. - */ -#pragma once -#include -namespace struct_pb0 = iguana; diff --git a/include/ylt/struct_pb/struct_pb_writer.hpp b/include/ylt/struct_pb/struct_pb_writer.hpp deleted file mode 100644 index f54e6a878..000000000 --- a/include/ylt/struct_pb/struct_pb_writer.hpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2024, Alibaba Group Holding Limited; - * - * 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. - */ -#pragma once -#include -namespace struct_pb0 = iguana; diff --git a/include/ylt/struct_pb0.hpp b/include/ylt/struct_pb0.hpp deleted file mode 100644 index 37f64d425..000000000 --- a/include/ylt/struct_pb0.hpp +++ /dev/null @@ -1,18 +0,0 @@ -/* - * Copyright (c) 2024, Alibaba Group Holding Limited; - * - * 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. - */ -#pragma once -#include "struct_pb/struct_pb_reader.hpp" -#include "struct_pb/struct_pb_writer.hpp" diff --git a/src/struct_pack/benchmark/benchmark.cpp b/src/struct_pack/benchmark/benchmark.cpp index 5b127be0f..7a5128799 100644 --- a/src/struct_pack/benchmark/benchmark.cpp +++ b/src/struct_pack/benchmark/benchmark.cpp @@ -14,11 +14,8 @@ #ifdef HAVE_PROTOBUF #include "protobuf_sample.hpp" -#ifdef HAVE_STRUCT_PB -#include "struct_pb_sample.hpp" -#endif #endif -#include "struct_pb_sample0.hpp" +#include "struct_pb_sample.hpp" #ifdef HAVE_FLATBUFFER #include "flatbuffer_sample.hpp" #endif @@ -121,12 +118,9 @@ int main(int argc, char** argv) { map.emplace(LibType::MSGPACK, new message_pack_sample()); #endif #ifdef HAVE_PROTOBUF -#ifdef HAVE_STRUCT_PB - map.emplace(LibType::STRUCT_PB, new struct_pb_sample::struct_pb_sample_t()); -#endif map.emplace(LibType::PROTOBUF, new protobuf_sample_t()); #endif - map.emplace(LibType::STRUCT_PB0, new struct_pb_sample0()); + map.emplace(LibType::STRUCT_PB, new struct_pb_sample()); #ifdef HAVE_FLATBUFFER map.emplace(LibType::FLATBUFFER, new flatbuffer_sample_t()); #endif @@ -145,9 +139,7 @@ int main(int argc, char** argv) { run_benchmark(map, LibType::STRUCT_PACK); -#ifdef HAVE_STRUCT_PB run_benchmark(map, LibType::STRUCT_PB); -#endif return 0; } diff --git a/src/struct_pack/benchmark/config.hpp b/src/struct_pack/benchmark/config.hpp index dff85263b..ab80af1d8 100644 --- a/src/struct_pack/benchmark/config.hpp +++ b/src/struct_pack/benchmark/config.hpp @@ -11,7 +11,6 @@ inline constexpr int ITERATIONS = 1000000; enum class LibType { STRUCT_PACK, STRUCT_PB, - STRUCT_PB0, MSGPACK, PROTOBUF, FLATBUFFER, @@ -48,9 +47,11 @@ inline const std::unordered_map g_sample_name_map = { std::to_string(OBJECT_COUNT) + " monsters(with zero-copy deserialize)"}}; inline const std::unordered_map g_lib_name_map = { - {LibType::STRUCT_PACK, "struct_pack"}, {LibType::STRUCT_PB, "struct_pb"}, - {LibType::STRUCT_PB0, "struct_pb0"}, {LibType::MSGPACK, "msgpack"}, - {LibType::PROTOBUF, "protobuf"}, {LibType::FLATBUFFER, "flatbuffer"}}; + {LibType::STRUCT_PACK, "struct_pack"}, + {LibType::STRUCT_PB, "struct_pb"}, + {LibType::MSGPACK, "msgpack"}, + {LibType::PROTOBUF, "protobuf"}, + {LibType::FLATBUFFER, "flatbuffer"}}; inline const std::vector g_sample_type_vec = { SampleType::RECT, SampleType::RECTS, SampleType::PERSON, diff --git a/src/struct_pack/benchmark/struct_pb_sample.hpp b/src/struct_pack/benchmark/struct_pb_sample.hpp index 8706f8a10..eca399655 100644 --- a/src/struct_pack/benchmark/struct_pb_sample.hpp +++ b/src/struct_pack/benchmark/struct_pb_sample.hpp @@ -1,159 +1,191 @@ #pragma once -#include -#include -#include -#include +#include #include "ScopedTimer.hpp" #include "no_op.h" #include "sample.hpp" -#ifdef HAVE_PROTOBUF -#include "data_def.struct_pb.h" -#endif +namespace pb_sample { +struct person : public iguana::pb_base { + int32_t id; + std::string name; + int age; + double salary; +}; +REFLECTION(person, id, name, age, salary); + +struct persons : public iguana::pb_base { + std::vector list; +}; +REFLECTION(persons, list); + +struct rect : public iguana::pb_base { + int32_t x = 1; + int32_t y = 0; + int32_t width = 11; + int32_t height = 1; +}; +REFLECTION(rect, x, y, width, height); + +struct rects : public iguana::pb_base { + std::vector list; +}; +REFLECTION(rects, list); + +struct Vec3 : public iguana::pb_base { + float x; + float y; + float z; + + REFLECTION(Vec3, x, y, z); +}; -namespace struct_pb_sample { +struct Weapon : public iguana::pb_base { + std::string name; + int32_t damage; +}; +REFLECTION(Weapon, name, damage); + +enum Color : uint8_t { Red, Green, Blue }; + +struct Monster : public iguana::pb_base { + Vec3 pos; + int32_t mana; + int32_t hp; + std::string name; + std::string inventory; + Color color; + std::vector weapons; + Weapon equipped; + std::vector path; +}; +REFLECTION(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, + path); + +struct Monsters : public iguana::pb_base { + std::vector list; +}; +REFLECTION(Monsters, list); -inline auto create_rects(std::size_t object_count) { - rect32s rcs; - for (int i = 0; i < object_count; ++i) { - rect32 rc{1, 0, 11, 1}; - rcs.rect32_list.emplace_back(rc); +inline auto create_rects(size_t object_count) { + rect rc{1, 0, 11, 1}; + std::vector v{}; + for (std::size_t i = 0; i < object_count; i++) { + v.push_back(rc); } - return rcs; + return v; } -inline auto create_persons(std::size_t object_count) { - persons ps; - for (int i = 0; i < object_count; ++i) { - person p{.id = 432798, - .name = std::string(1024, 'A'), - .age = 24, - .salary = 65536.42}; - ps.person_list.emplace_back(p); + +inline auto create_persons(size_t object_count) { + std::vector v{}; + person p{0, 432798, std::string(1024, 'A'), 24, 65536.42}; + + for (std::size_t i = 0; i < object_count; i++) { + v.push_back(p); } - return ps; + return v; } -inline auto create_monsters(std::size_t object_count) { - Monsters monsters; - for (int i = 0; i < object_count / 2; ++i) { - { - Monster m{}; - m.pos = std::make_unique(); - *m.pos = struct_pb_sample::Vec3{1, 2, 3}; - // m.pos = {1, 2, 3}; - m.mana = 16; - m.hp = 24; - m.name = "it is a test"; - m.inventory = "\1\2\3\4"; - m.color = Monster::Color::Red; - m.weapons = {{"gun", 42}, {"shotgun", 56}}; - m.equipped = std::make_unique(); - *m.equipped = struct_pb_sample::Weapon{"air craft", 67}; - // m.equipped = {"air craft", 67}; - m.path = {{7, 8, 9}, {71, 81, 91}}; - monsters.monsters.push_back(std::move(m)); - } - { - Monster m; - m.pos = std::make_unique(); - *m.pos = struct_pb_sample::Vec3{11, 22, 33}; - m.mana = 161; - m.hp = 241; - m.name = "it is a test, ok"; - m.inventory = "\24\25\26\24"; - m.color = Monster::Color::Red; - m.weapons = {{"gun", 421}, {"shotgun", 561}}; - m.equipped = std::make_unique(); - *m.equipped = struct_pb_sample::Weapon{"air craft", 671}; - // m.equipped = {"air craft", 671}; - m.path = {{71, 82, 93}, {711, 821, 931}}; - monsters.monsters.push_back(std::move(m)); - } + +inline std::vector create_monsters(size_t object_count) { + std::vector v{}; + Monster m = { + 0, + Vec3{0, 1, 2, 3}, + 16, + 24, + "it is a test", + "\1\2\3\4", + Color::Red, + {{0, "gun", 42}, {0, "shotgun", 56}}, + {0, "air craft", 67}, + {{0, 7, 8, 9}, {0, 71, 81, 91}}, + }; + + Monster m1 = { + 0, + {0, 11, 22, 33}, + 161, + 241, + "it is a test, ok", + "\24\25\26\24", + Color::Red, + {{0, "gun", 421}, {0, "shotgun", 561}}, + {0, "air craft", 671}, + {{0, 71, 82, 93}, {0, 711, 821, 931}}, + }; + + for (std::size_t i = 0; i < object_count / 2; i++) { + v.push_back(m); + v.push_back(m1); } + if (object_count % 2 == 1) { - Monster m{}; - m.pos = std::make_unique(); - *m.pos = struct_pb_sample::Vec3{1, 2, 3}; - // m.pos = {1, 2, 3}; - m.mana = 16; - m.hp = 24; - m.name = "it is a test"; - m.inventory = "\1\2\3\4"; - m.color = Monster::Color::Red; - m.weapons = {{"gun", 42}, {"shotgun", 56}}; - m.equipped = std::make_unique(); - *m.equipped = struct_pb_sample::Weapon{"air craft", 67}; - // m.equipped = {"air craft", 67}; - m.path = {{7, 8, 9}, {71, 81, 91}}; - monsters.monsters.push_back(std::move(m)); + v.push_back(m); } - return monsters; + + return v; } +} // namespace pb_sample -struct struct_pb_sample_t : public base_sample { +struct struct_pb_sample : public base_sample { static inline constexpr LibType lib_type = LibType::STRUCT_PB; std::string name() const override { return get_lib_name(lib_type); } void create_samples() override { - rects_ = struct_pb_sample::create_rects(OBJECT_COUNT); - persons_ = struct_pb_sample::create_persons(OBJECT_COUNT); - monsters_ = struct_pb_sample::create_monsters(OBJECT_COUNT); + rects_.list = {pb_sample::create_rects(OBJECT_COUNT)}; + persons_.list = {pb_sample::create_persons(OBJECT_COUNT)}; + monsters_.list = {pb_sample::create_monsters(OBJECT_COUNT)}; } void do_serialization() override { - serialize(SampleType::RECT, rects_.rect32_list[0]); + serialize(SampleType::RECT, rects_.list[0]); + struct_pb::to_pb(rects_, buffer_); + struct_pb::to_pb(rects_, buffer_); + struct_pb::to_pb(rects_, buffer_); + std::cout << rects_.list.size() << "\n"; serialize(SampleType::RECTS, rects_); - serialize(SampleType::PERSON, persons_.person_list[0]); + serialize(SampleType::PERSON, persons_.list[0]); serialize(SampleType::PERSONS, persons_); - serialize(SampleType::MONSTER, monsters_.monsters[0]); + serialize(SampleType::MONSTER, monsters_.list[0]); serialize(SampleType::MONSTERS, monsters_); } void do_deserialization() override { - deserialize(SampleType::RECT, rects_.rect32_list[0]); + deserialize(SampleType::RECT, rects_.list[0]); deserialize(SampleType::RECTS, rects_); - deserialize(SampleType::PERSON, persons_.person_list[0]); + deserialize(SampleType::PERSON, persons_.list[0]); deserialize(SampleType::PERSONS, persons_); - deserialize(SampleType::MONSTER, monsters_.monsters[0]); + deserialize(SampleType::MONSTER, monsters_.list[0]); deserialize(SampleType::MONSTERS, monsters_); } private: template - void serialize(SampleType sample_type, T& sample) { - auto sz = struct_pb::internal::get_needed_size(sample); - buffer_.resize(sz); - struct_pb::internal::serialize_to(buffer_.data(), buffer_.size(), sample); - buffer_.clear(); - buffer_.resize(sz); - - uint64_t ns = 0; - std::string bench_name = - name() + " serialize " + get_sample_name(sample_type); - + void serialize(SampleType sample_type, T &sample) { { - ScopedTimer timer(bench_name.data(), ns); - for (int i = 0; i < ITERATIONS; ++i) { - buffer_.clear(); - auto sz = struct_pb::internal::get_needed_size(sample); - buffer_.resize(sz); - struct_pb::internal::serialize_to(buffer_.data(), buffer_.size(), - sample); - no_op(buffer_); - no_op((char*)&sample); + struct_pb::to_pb(sample, buffer_); + buffer_.clear(); + + uint64_t ns = 0; + std::string bench_name = + name() + " serialize " + get_sample_name(sample_type); + + { + ScopedTimer timer(bench_name.data(), ns); + for (int i = 0; i < ITERATIONS; ++i) { + struct_pb::to_pb(sample, buffer_); + no_op(buffer_); + no_op((char *)&sample); + } } + ser_time_elapsed_map_.emplace(sample_type, ns); } - - ser_time_elapsed_map_.emplace(sample_type, ns); buf_size_map_.emplace(sample_type, buffer_.size()); } - - template - void deserialize(SampleType sample_type, T& sample) { + template + void deserialize(SampleType sample_type, T &sample) { buffer_.clear(); - auto sz = struct_pb::internal::get_needed_size(sample); - buffer_.resize(sz); - struct_pb::internal::serialize_to(buffer_.data(), buffer_.size(), sample); + struct_pb::to_pb(sample, buffer_); uint64_t ns = 0; std::string bench_name = @@ -162,22 +194,17 @@ struct struct_pb_sample_t : public base_sample { { ScopedTimer timer(bench_name.data(), ns); for (int i = 0; i < ITERATIONS; ++i) { - T obj; - [[maybe_unused]] auto ok = struct_pb::internal::deserialize_to( - obj, buffer_.data(), buffer_.size()); - assert(ok); - no_op((char*)&obj); + U obj; + struct_pb::from_pb(obj, buffer_); + no_op((char *)&obj); no_op(buffer_); } } deser_time_elapsed_map_.emplace(sample_type, ns); - - buf_size_map_.emplace(sample_type, buffer_.size()); } - struct_pb_sample::rect32s rects_; - struct_pb_sample::persons persons_; - struct_pb_sample::Monsters monsters_; + pb_sample::rects rects_; + pb_sample::persons persons_; + pb_sample::Monsters monsters_; std::string buffer_; }; -} // namespace struct_pb_sample \ No newline at end of file diff --git a/src/struct_pack/benchmark/struct_pb_sample0.hpp b/src/struct_pack/benchmark/struct_pb_sample0.hpp deleted file mode 100644 index c492ec8a2..000000000 --- a/src/struct_pack/benchmark/struct_pb_sample0.hpp +++ /dev/null @@ -1,210 +0,0 @@ -#pragma once -#include - -#include "ScopedTimer.hpp" -#include "no_op.h" -#include "sample.hpp" - -namespace pb_sample0 { -struct person : public iguana::pb_base { - int32_t id; - std::string name; - int age; - double salary; -}; -REFLECTION(person, id, name, age, salary); - -struct persons : public iguana::pb_base { - std::vector list; -}; -REFLECTION(persons, list); - -struct rect : public iguana::pb_base { - int32_t x = 1; - int32_t y = 0; - int32_t width = 11; - int32_t height = 1; -}; -REFLECTION(rect, x, y, width, height); - -struct rects : public iguana::pb_base { - std::vector list; -}; -REFLECTION(rects, list); - -struct Vec3 : public iguana::pb_base { - float x; - float y; - float z; - - REFLECTION(Vec3, x, y, z); -}; - -struct Weapon : public iguana::pb_base { - std::string name; - int32_t damage; -}; -REFLECTION(Weapon, name, damage); - -enum Color : uint8_t { Red, Green, Blue }; - -struct Monster : public iguana::pb_base { - Vec3 pos; - int32_t mana; - int32_t hp; - std::string name; - std::string inventory; - Color color; - std::vector weapons; - Weapon equipped; - std::vector path; -}; -REFLECTION(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, - path); - -struct Monsters : public iguana::pb_base { - std::vector list; -}; -REFLECTION(Monsters, list); - -inline auto create_rects(size_t object_count) { - rect rc{1, 0, 11, 1}; - std::vector v{}; - for (std::size_t i = 0; i < object_count; i++) { - v.push_back(rc); - } - return v; -} - -inline auto create_persons(size_t object_count) { - std::vector v{}; - person p{0, 432798, std::string(1024, 'A'), 24, 65536.42}; - - for (std::size_t i = 0; i < object_count; i++) { - v.push_back(p); - } - return v; -} - -inline std::vector create_monsters(size_t object_count) { - std::vector v{}; - Monster m = { - 0, - Vec3{0, 1, 2, 3}, - 16, - 24, - "it is a test", - "\1\2\3\4", - Color::Red, - {{0, "gun", 42}, {0, "shotgun", 56}}, - {0, "air craft", 67}, - {{0, 7, 8, 9}, {0, 71, 81, 91}}, - }; - - Monster m1 = { - 0, - {0, 11, 22, 33}, - 161, - 241, - "it is a test, ok", - "\24\25\26\24", - Color::Red, - {{0, "gun", 421}, {0, "shotgun", 561}}, - {0, "air craft", 671}, - {{0, 71, 82, 93}, {0, 711, 821, 931}}, - }; - - for (std::size_t i = 0; i < object_count / 2; i++) { - v.push_back(m); - v.push_back(m1); - } - - if (object_count % 2 == 1) { - v.push_back(m); - } - - return v; -} -} // namespace pb_sample0 - -struct struct_pb_sample0 : public base_sample { - static inline constexpr LibType lib_type = LibType::STRUCT_PB0; - std::string name() const override { return get_lib_name(lib_type); } - - void create_samples() override { - rects_.list = {pb_sample0::create_rects(OBJECT_COUNT)}; - persons_.list = {pb_sample0::create_persons(OBJECT_COUNT)}; - monsters_.list = {pb_sample0::create_monsters(OBJECT_COUNT)}; - } - - void do_serialization() override { - serialize(SampleType::RECT, rects_.list[0]); - struct_pb0::to_pb(rects_, buffer_); - struct_pb0::to_pb(rects_, buffer_); - struct_pb0::to_pb(rects_, buffer_); - std::cout << rects_.list.size() << "\n"; - serialize(SampleType::RECTS, rects_); - serialize(SampleType::PERSON, persons_.list[0]); - serialize(SampleType::PERSONS, persons_); - serialize(SampleType::MONSTER, monsters_.list[0]); - serialize(SampleType::MONSTERS, monsters_); - } - - void do_deserialization() override { - deserialize(SampleType::RECT, rects_.list[0]); - deserialize(SampleType::RECTS, rects_); - deserialize(SampleType::PERSON, persons_.list[0]); - deserialize(SampleType::PERSONS, persons_); - deserialize(SampleType::MONSTER, monsters_.list[0]); - deserialize(SampleType::MONSTERS, monsters_); - } - - private: - template - void serialize(SampleType sample_type, T &sample) { - { - struct_pb0::to_pb(sample, buffer_); - buffer_.clear(); - - uint64_t ns = 0; - std::string bench_name = - name() + " serialize " + get_sample_name(sample_type); - - { - ScopedTimer timer(bench_name.data(), ns); - for (int i = 0; i < ITERATIONS; ++i) { - struct_pb0::to_pb(sample, buffer_); - no_op(buffer_); - no_op((char *)&sample); - } - } - ser_time_elapsed_map_.emplace(sample_type, ns); - } - buf_size_map_.emplace(sample_type, buffer_.size()); - } - template - void deserialize(SampleType sample_type, T &sample) { - buffer_.clear(); - struct_pb0::to_pb(sample, buffer_); - - uint64_t ns = 0; - std::string bench_name = - name() + " deserialize " + get_sample_name(sample_type); - - { - ScopedTimer timer(bench_name.data(), ns); - for (int i = 0; i < ITERATIONS; ++i) { - U obj; - struct_pb0::from_pb(obj, buffer_); - no_op((char *)&obj); - no_op(buffer_); - } - } - deser_time_elapsed_map_.emplace(sample_type, ns); - } - - pb_sample0::rects rects_; - pb_sample0::persons persons_; - pb_sample0::Monsters monsters_; - std::string buffer_; -}; From e2b29fae607d1f0021dfcc2020a7c67649355d96 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 22 May 2024 16:33:25 +0800 Subject: [PATCH 07/26] add example --- src/struct_pb/examples/CMakeLists.txt | 24 ++++++++++++++++++++++++ src/struct_pb/examples/main.cpp | 27 +++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 src/struct_pb/examples/CMakeLists.txt create mode 100644 src/struct_pb/examples/main.cpp diff --git a/src/struct_pb/examples/CMakeLists.txt b/src/struct_pb/examples/CMakeLists.txt new file mode 100644 index 000000000..4183a5de6 --- /dev/null +++ b/src/struct_pb/examples/CMakeLists.txt @@ -0,0 +1,24 @@ +if("${yaLanTingLibs_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") + # If this is a subproject in ylt + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/examples) +else() + # else find installed yalantinglibs + cmake_minimum_required(VERSION 3.15) + project(struct_pb_examples) + if(NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE "Release") + endif() + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_INCLUDE_CURRENT_DIR ON) + # if you have install ylt + find_package(yalantinglibs REQUIRED) + link_libraries(yalantinglibs::yalantinglibs) + # else + # include_directories(include) + # include_directories(include/ylt/thirdparty) +endif() + +add_executable(struct_pb_examples + main.cpp + ) \ No newline at end of file diff --git a/src/struct_pb/examples/main.cpp b/src/struct_pb/examples/main.cpp new file mode 100644 index 000000000..5eebd583c --- /dev/null +++ b/src/struct_pb/examples/main.cpp @@ -0,0 +1,27 @@ +#include +#include +#include + +struct my_struct : struct_pb::pb_base { + int x; + bool y; + iguana::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); + +struct nest : struct_pb::pb_base { + std::string name; + my_struct value; + int var; +}; +REFLECTION(nest, name, value, var); + +int main() { + nest v{0, "Hi", {0, 1, false, 3}, 5}, v2{}; + std::string s; + struct_pb::to_pb(v, s); + struct_pb::from_pb(v2, s); + assert(v.var == v2.var); + assert(v.value.y == v2.value.y); + assert(v.value.z == v2.value.z); +} \ No newline at end of file From ae35015a4593cd8e69a66716aa9066fd2131c108 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 22 May 2024 17:48:41 +0800 Subject: [PATCH 08/26] add ut --- cmake/subdir.cmake | 1 + src/struct_pb/tests/CMakeLists.txt | 37 + src/struct_pb/tests/data_def.proto | 56 ++ src/struct_pb/tests/main.cpp | 1026 +++++++++++++++++++++ src/struct_pb/tests/unittest_proto3.h | 582 ++++++++++++ src/struct_pb/tests/unittest_proto3.proto | 108 +++ 6 files changed, 1810 insertions(+) create mode 100644 src/struct_pb/tests/CMakeLists.txt create mode 100644 src/struct_pb/tests/data_def.proto create mode 100644 src/struct_pb/tests/main.cpp create mode 100644 src/struct_pb/tests/unittest_proto3.h create mode 100644 src/struct_pb/tests/unittest_proto3.proto diff --git a/cmake/subdir.cmake b/cmake/subdir.cmake index 7c33792b6..448f46de1 100644 --- a/cmake/subdir.cmake +++ b/cmake/subdir.cmake @@ -17,6 +17,7 @@ if (NOT ENABLE_CPP_20) Set(BUILD_STRUCT_JSON ON) Set(BUILD_STRUCT_XML ON) Set(BUILD_STRUCT_YAML ON) + Set(BUILD_STRUCT_PB ON) endif() foreach(child ${children}) diff --git a/src/struct_pb/tests/CMakeLists.txt b/src/struct_pb/tests/CMakeLists.txt new file mode 100644 index 000000000..f76c19ef6 --- /dev/null +++ b/src/struct_pb/tests/CMakeLists.txt @@ -0,0 +1,37 @@ +find_package(Protobuf QUIET) +if("${yaLanTingLibs_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}") + # If this is a subproject in ylt + set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/tests) +else() + # else find installed yalantinglibs + cmake_minimum_required(VERSION 3.15) + project(struct_pb_test) + set(CMAKE_CXX_STANDARD 17) + set(CMAKE_CXX_STANDARD_REQUIRED ON) + set(CMAKE_INCLUDE_CURRENT_DIR ON) + # if you have install ylt + find_package(yalantinglibs REQUIRED) + link_libraries(yalantinglibs::yalantinglibs) + # else + # include_directories(include) + # include_directories(include/ylt/thirdparty) +endif() + +set(TEST_PROTO main.cpp) + +if (Protobuf_FOUND) + add_definitions(-DSTRUCT_PB_WITH_PROTO) + message(STATUS "Found Protobuf: ${Protobuf_VERSION}") + include_directories(${Protobuf_INCLUDE_DIRS}) + include_directories(${CMAKE_CURRENT_BINARY_DIR}) + set(PROTO_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/) + file(GLOB PROTO_FILES ${PROTO_SRC_DIR}/*.proto) + + protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${PROTO_FILES}) + # message(STATUS "Proto source files: ${PROTO_SRCS}") + # message(STATUS "Proto header files: ${PROTO_HDRS}") + add_executable(struct_pb_test ${PROTO_SRCS} ${TEST_PROTO}) + target_link_libraries(struct_pb_test PRIVATE protobuf::libprotobuf) +else() + add_executable(struct_pb_test ${TEST_PROTO}) +endif() \ No newline at end of file diff --git a/src/struct_pb/tests/data_def.proto b/src/struct_pb/tests/data_def.proto new file mode 100644 index 000000000..691c964fe --- /dev/null +++ b/src/struct_pb/tests/data_def.proto @@ -0,0 +1,56 @@ +syntax = "proto3"; + +package mygame; + +option optimize_for = SPEED; +option cc_enable_arenas = true; + +message Vec3 { + float x = 1; + float y = 2; + float z = 3; +} + +message Weapon { + string name = 1; + int32 damage = 2; +} + +message Monster { + Vec3 pos = 1; + int32 mana = 2; + int32 hp = 3; + string name = 4; + bytes inventory = 5; + enum Color { + Red = 0; + Green = 1; + Blue = 2; + } + Color color = 6; + repeated Weapon weapons = 7; + Weapon equipped = 8; + repeated Vec3 path = 9; +} + +message Monsters { + repeated Monster monsters = 1; +} + +message person { + int32 id = 1; + string name = 2; + int32 age = 3; + double salary = 4; +} + +message persons { + repeated person person_list = 1; +} + +message bench_int32 { + int32 a = 1; + int32 b = 2; + int32 c = 3; + int32 d = 4; +} \ No newline at end of file diff --git a/src/struct_pb/tests/main.cpp b/src/struct_pb/tests/main.cpp new file mode 100644 index 000000000..ca06723e3 --- /dev/null +++ b/src/struct_pb/tests/main.cpp @@ -0,0 +1,1026 @@ +#define DOCTEST_CONFIG_IMPLEMENT +#include + +#include "doctest.h" +#include "unittest_proto3.h" + +#if defined(STRUCT_PB_WITH_PROTO) +TEST_CASE("test BaseTypeMsg") { + { // normal test + stpb::BaseTypeMsg se_st{0, 100, 200, 300, 400, + 31.4f, 62.8, false, "World", stpb::Enum::ZERO}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseTypeMsg se_msg; + SetBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::BaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseTypeMsg(dese_st, dese_msg); + } + + { // test min and empty str + stpb::BaseTypeMsg se_st{0, + std::numeric_limits::min(), + std::numeric_limits::min(), + std::numeric_limits::min(), + std::numeric_limits::min(), + std::numeric_limits::lowest(), + std::numeric_limits::lowest(), + false, + "", + stpb::Enum::NEG}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseTypeMsg se_msg; + SetBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::BaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseTypeMsg(dese_st, dese_msg); + } + { // test max and long str + stpb::BaseTypeMsg se_st{0, + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + std::numeric_limits::max(), + true, + std::string(1000, 'x'), + stpb::Enum::BAZ}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseTypeMsg se_msg; + SetBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::BaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseTypeMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test person and monster") { + stpb::simple_t2 t{0, -100, 2, stpb::Color::Blue, 4}; + std::string str; + iguana::to_pb(t, str); + + stpb::simple_t2 t2; + iguana::from_pb(t2, str); + CHECK(t.c == t2.c); + + pb::Simple2 s; + s.set_a(-100); + s.set_b(2); + s.set_c(pb::Color::Blue); + s.set_d(4); + + std::string pb_str; + s.SerializeToString(&pb_str); + + CHECK(str == pb_str); +} + +TEST_CASE("test person and monster") { + auto pb_monster = protobuf_sample::create_monster(); + auto sp_monster = create_sp_monster(); + + std::string pb_str; + std::string sp_str; + + pb_monster.SerializeToString(&pb_str); + iguana::to_pb(sp_monster, sp_str); + + CHECK(pb_str == sp_str); + + mygame::Monster m; + m.ParseFromString(pb_str); + CHECK(m.name() == pb_monster.name()); + + stpb::Monster spm; + iguana::from_pb(spm, sp_str); + CHECK(spm.name == sp_monster.name); + + auto pb_person = protobuf_sample::create_person(); + auto sp_person = create_person(); + pb_person.SerializePartialToString(&pb_str); + iguana::to_pb(sp_person, sp_str); + + CHECK(pb_str == sp_str); + + mygame::person pp; + pp.ParseFromString(pb_str); + CHECK(pp.name() == pb_person.name()); + + stpb::person p; + iguana::from_pb(p, sp_str); + CHECK(p.name == sp_person.name); +} + +TEST_CASE("test IguanaTypeMsg") { + { // test normal value + stpb::IguanaTypeMsg se_st{0, {100}, {200}, {300}, {400}, {31}, {32}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::IguanaTypeMsg se_msg{}; + SetIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::IguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::IguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckIguanaTypeMsg(dese_st, dese_msg); + } + + { // test min value + stpb::IguanaTypeMsg se_st{0, + {std::numeric_limits::min()}, + {std::numeric_limits::min()}, + {std::numeric_limits::min()}, + {std::numeric_limits::min()}, + {std::numeric_limits::lowest()}, + {std::numeric_limits::lowest()}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::IguanaTypeMsg se_msg{}; + SetIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + stpb::IguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::IguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckIguanaTypeMsg(dese_st, dese_msg); + } + { // test max value + stpb::IguanaTypeMsg se_st{0, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}, + {std::numeric_limits::max()}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::IguanaTypeMsg se_msg; + SetIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::IguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::IguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckIguanaTypeMsg(dese_st, dese_msg); + } + { // test empty + stpb::IguanaTypeMsg se_st{}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::IguanaTypeMsg se_msg; + SetIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::IguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::IguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckIguanaTypeMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test RepeatBaseTypeMsg") { + { + stpb::RepeatBaseTypeMsg se_st{ + 0, + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9}, + {10, 11, 12}, + {13.1, 14.2, 15.3}, + {16.4, 17.5, 18.6}, + {"a", "b", "c"}, + {stpb::Enum::BAZ, stpb::Enum::ZERO, stpb::Enum::NEG}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::RepeatBaseTypeMsg se_msg; + SetRepeatBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::RepeatBaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::RepeatBaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckRepeatBaseTypeMsg(dese_st, dese_msg); + } + { // max and min vlaue + stpb::RepeatBaseTypeMsg se_st{0, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {}, + {std::numeric_limits::max(), + std::numeric_limits::min()}, + {"", "", ""}, + {stpb::Enum::NEG, stpb::Enum::FOO}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::RepeatBaseTypeMsg se_msg; + SetRepeatBaseTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + stpb::RepeatBaseTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::RepeatBaseTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckRepeatBaseTypeMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test RepeatIguanaTypeMsg") { + { + stpb::RepeatIguanaTypeMsg se_st{ + 0, + {{0}, {1}, {3}}, + {{4}, {5}, {6}}, + {{7}, {8}, {9}}, + {{10}, {11}, {12}}, + {{13}, {14}, {15}}, + {}, + }; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::RepeatIguanaTypeMsg se_msg; + SetRepeatIguanaTypeMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::RepeatIguanaTypeMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + pb::RepeatIguanaTypeMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckRepeatIguanaTypeMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test NestedMsg") { + { + stpb::NestedMsg se_st{ + 0, + /* base_msg */ + {0, 100, 200, 300, 400, 31.4f, 62.8, false, "World", stpb::Enum::BAZ}, + /* repeat_base_msg */ + {{0, 1, 2, 3, 4, 5.5f, 6.6, true, "Hello", stpb::Enum::FOO}, + {0, 7, 8, 9, 10, 11.11f, 12.12, false, "Hi", stpb::Enum::BAR}}, + /* iguana_type_msg */ {0, {100}, {200}, {300}, {400}, {31}, {32}}, + /* repeat_iguna_msg */ + {{0, {1}, {2}, {3}}, {0, {4}, {5}, {6}}, {0, {7}, {8}, {9}}}, + /* repeat_repeat_base_msg */ + {{0, + {1, 2, 3}, + {4, 5, 6}, + {7, 8, 9}, + {10, 11, 12}, + {13.1, 14.2, 15.3}, + {16.4, 17.5, 18.6}, + {"a", "b", "c"}, + {stpb::Enum::FOO, stpb::Enum::BAR, stpb::Enum::BAZ}}, + {0, + {19, 20, 21}, + {22, 23, 24}, + {25, 26, 27}, + {28, 29, 30}, + {31.1, 32.2, 33.3}, + {34.4, 35.5, 36.6}, + {"x", "y", "z"}, + {stpb::Enum::ZERO, stpb::Enum::NEG, stpb::Enum::FOO}}}}; + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::NestedMsg se_msg; + SetNestedMsg(se_st, se_msg); + + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + + CHECK(st_ss == pb_ss); + + stpb::NestedMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::NestedMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + + CheckNestedMsg(dese_st, dese_msg); + } + { // test empty values + stpb::NestedMsg se_st{ + 0, + /* base_msg */ {0, 0, 0, 0, 0, 0.0f, 0.0, true, "", stpb::Enum::ZERO}, + /* repeat_base_msg */ {}, + /* iguana_type_msg */ {}, + /* repeat_iguna_msg */ {}, + /* repeat_repeat_base_msg */ {}}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::NestedMsg se_msg; + SetNestedMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + + CHECK(st_ss == pb_ss); + print_hex_str(st_ss); + print_hex_str(pb_ss); + stpb::NestedMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::NestedMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + + CheckNestedMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test MapMsg") { + { + stpb::MapMsg se_st{}; + + se_st.sfix64_str_map.emplace(iguana::sfixed64_t{10}, "ten"); + se_st.sfix64_str_map.emplace(iguana::sfixed64_t{20}, "twenty"); + + se_st.str_iguana_type_msg_map.emplace( + "first", stpb::IguanaTypeMsg{{10}, {20}, {30}, {40}, {50}, {60}}); + se_st.str_iguana_type_msg_map.emplace( + "second", stpb::IguanaTypeMsg{{11}, {21}, {31}, {41}, {51}, {61}}); + + se_st.int_repeat_base_msg_map.emplace( + 1, stpb::RepeatBaseTypeMsg{0, + {1, 2}, + {3, 4}, + {5, 6}, + {7, 8}, + {9.0f, 10.0f}, + {11.0, 12.0}, + {"one", "two"}, + {stpb::Enum::FOO, stpb::Enum::BAR}}); + se_st.int_repeat_base_msg_map.emplace( + 2, stpb::RepeatBaseTypeMsg{0, + {2, 3}, + {4, 5}, + {6, 7}, + {8, 9}, + {10.0f, 11.0f}, + {12.0, 13.0}, + {"three", "four"}, + {stpb::Enum::BAZ, stpb::Enum::NEG}}); + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::MapMsg se_msg{}; + SetMapMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + // It's okay not to satisfy this. + // CHECK(st_ss == pb_ss); + CHECK(st_ss.size() == pb_ss.size()); + stpb::MapMsg dese_st{}; + iguana::from_pb(dese_st, pb_ss); + pb::MapMsg dese_msg; + dese_msg.ParseFromString(st_ss); + CheckMapMsg(dese_st, dese_msg); + } + { + // key empty + stpb::MapMsg se_st{}; + se_st.sfix64_str_map.emplace(iguana::sfixed64_t{30}, ""); + se_st.str_iguana_type_msg_map.emplace( + "", stpb::IguanaTypeMsg{0, {0}, {0}, {0}, {0}, {0}, {0}}); + se_st.int_repeat_base_msg_map.emplace( + 3, stpb::RepeatBaseTypeMsg{0, {}, {}, {}, {}, {}, {}, {}, {}}); + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::MapMsg se_msg{}; + SetMapMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::MapMsg dese_st{}; + iguana::from_pb(dese_st, pb_ss); + pb::MapMsg dese_msg; + dese_msg.ParseFromString(st_ss); + CheckMapMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test BaseOneofMsg") { + { // test double + stpb::BaseOneofMsg se_st{0, 123, 3.14159, 456.78}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseOneofMsg se_msg; + SetBaseOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + // print_hex_str(st_ss); + // print_hex_str(pb_ss); + stpb::BaseOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::BaseOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseOneofMsg(dese_st, dese_msg); + } + { // test string + stpb::BaseOneofMsg se_st{0, 123, std::string("Hello"), 456.78}; + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseOneofMsg se_msg; + SetBaseOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::BaseOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseOneofMsg(dese_st, dese_msg); + } + { // test BaseTypeMsg + stpb::BaseTypeMsg baseTypeMsg{0, 100, 200, 300, 400, + 31.4f, 62.8, false, "World", stpb::Enum::BAZ}; + stpb::BaseOneofMsg se_st{0, 123, baseTypeMsg, 456.78}; + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseOneofMsg se_msg; + SetBaseOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + + stpb::BaseOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::BaseOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseOneofMsg(dese_st, dese_msg); + } + { // test empty variant + stpb::BaseOneofMsg se_st{0, 123, {}, 456.78}; + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::BaseOneofMsg se_msg; + SetBaseOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + print_hex_str(st_ss); + print_hex_str(pb_ss); + stpb::BaseOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::BaseOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckBaseOneofMsg(dese_st, dese_msg); + } +} + +TEST_CASE("test NestOneofMsg ") { + { // Test BaseOneofMsg + stpb::BaseOneofMsg baseOneof{0, 123, std::string("Hello"), 456.78}; + stpb::NestOneofMsg se_st{{baseOneof}}; + + std::string st_ss; + iguana::to_pb(se_st, st_ss); + + pb::NestOneofMsg se_msg; + SetNestOneofMsg(se_st, se_msg); + std::string pb_ss; + se_msg.SerializeToString(&pb_ss); + CHECK(st_ss == pb_ss); + stpb::NestOneofMsg dese_st{}; + iguana::from_pb(dese_st, st_ss); + + pb::NestOneofMsg dese_msg; + dese_msg.ParseFromString(pb_ss); + CheckNestOneofMsg(dese_st, dese_msg); + } +} +#endif + +struct point_t PUBLIC { + int x; + double y; +}; +REFLECTION(point_t, x, y); + +namespace my_space { +struct inner_struct PUBLIC { + int x; + int y; + int z; +}; + +constexpr inline auto get_members_impl(inner_struct *) { + return std::make_tuple(iguana::field_t{&inner_struct::x, 7, "a"}, + iguana::field_t{&inner_struct::y, 9, "b"}, + iguana::field_t{&inner_struct::z, 12, "c"}); +} +} // namespace my_space + +struct test_pb_st1 PUBLIC { + int x; + iguana::sint32_t y; + iguana::sint64_t z; +}; +REFLECTION(test_pb_st1, x, y, z); + +struct test_pb_st2 PUBLIC { + int x; + iguana::fixed32_t y; + iguana::fixed64_t z; +}; +REFLECTION(test_pb_st2, x, y, z); + +struct test_pb_st3 PUBLIC { + int x; + iguana::sfixed32_t y; + iguana::sfixed64_t z; +}; +REFLECTION(test_pb_st3, x, y, z); + +struct test_pb_st4 PUBLIC { + int x; + std::string y; +}; +REFLECTION(test_pb_st4, x, y); + +struct test_pb_st5 PUBLIC { + int x; + std::string_view y; +}; +REFLECTION(test_pb_st5, x, y); + +struct test_pb_st6 PUBLIC { + std::optional x; + std::optional y; +}; +REFLECTION(test_pb_st6, x, y); + +struct pair_t PUBLIC { + int x; + int y; +}; +REFLECTION(pair_t, x, y); + +struct message_t PUBLIC { + int id; + pair_t t; +}; +REFLECTION(message_t, id, t); + +struct test_pb_st8 PUBLIC { + int x; + pair_t y; + message_t z; +}; +REFLECTION(test_pb_st8, x, y, z); + +struct test_pb_st9 PUBLIC { + int x; + std::vector y; + std::string z; +}; +REFLECTION(test_pb_st9, x, y, z); + +struct test_pb_st10 PUBLIC { + int x; + std::vector y; + std::string z; +}; +REFLECTION(test_pb_st10, x, y, z); + +struct test_pb_st11 PUBLIC { + int x; + std::vector> y; + std::vector z; +}; +REFLECTION(test_pb_st11, x, y, z); + +struct test_pb_st12 PUBLIC { + int x; + std::map y; + std::map z; +}; +REFLECTION(test_pb_st12, x, y, z); + +struct test_pb_st13 PUBLIC { + int x; + std::map y; + std::string z; +}; +REFLECTION(test_pb_st13, x, y, z); + +enum class colors_t { red, black }; + +enum level_t { debug, info }; + +struct test_pb_st14 PUBLIC { + int x; + colors_t y; + level_t z; +}; +REFLECTION(test_pb_st14, x, y, z); + +namespace client { +struct person PUBLIC { + std::string name; + int64_t age; +}; + +REFLECTION(person, name, age); +} // namespace client + +struct my_struct PUBLIC { + int x; + bool y; + iguana::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); + +struct nest1 PUBLIC { + std::string name; + my_struct value; + int var; +}; + +REFLECTION(nest1, name, value, var); + +struct numer_st PUBLIC { + bool a; + double b; + float c; +}; +REFLECTION(numer_st, a, b, c); + +TEST_CASE("test struct_pb") { + { + my_space::inner_struct inner{0, 41, 42, 43}; + + std::string str; + iguana::to_pb(inner, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(inner)); + + my_space::inner_struct inner1; + iguana::from_pb(inner1, str); + CHECK(inner.x == inner1.x); + CHECK(inner.y == inner1.y); + CHECK(inner.z == inner1.z); + } + + { + test_pb_st1 st1{0, 41, {42}, {43}}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st1 st2; + iguana::from_pb(st2, str); + CHECK(st1.x == st2.x); + CHECK(st1.y.val == st2.y.val); + CHECK(st1.z.val == st2.z.val); + } + + { + test_pb_st2 st1{0, 41, {42}, {43}}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st2 st2; + iguana::from_pb(st2, str); + CHECK(st1.y.val == st2.y.val); + } + { + test_pb_st3 st1{0, 41, {42}, {43}}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st3 st2; + iguana::from_pb(st2, str); + CHECK(st1.y.val == st2.y.val); + } + { + test_pb_st4 st1{0, 41, "it is a test"}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st4 st2; + iguana::from_pb(st2, str); + CHECK(st1.y == st2.y); + } + + { + test_pb_st5 st1{0, 41, "it is a test"}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st5 st2; + iguana::from_pb(st2, str); + CHECK(st1.y == st2.y); + } + { + // optional + test_pb_st6 st1{0, 41, "it is a test"}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st6 st2; + iguana::from_pb(st2, str); + CHECK(st1.y == st2.y); + } + { + // sub nested objects + nest1 v{0, "Hi", {0, 1, false, {3}}, 5}, v2{}; + std::string s; + iguana::to_pb(v, s); + iguana::from_pb(v2, s); + CHECK(v.var == v2.var); + CHECK(v.value.y == v2.value.y); + CHECK(v.value.z == v2.value.z); + + test_pb_st8 st1{0, 1, {0, 3, 4}, {0, 5, {0, 7, 8}}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st8 st2; + iguana::from_pb(st2, str); + CHECK(st1.z.t.y == st2.z.t.y); + } + + { + // repeated messages + test_pb_st9 st1{0, 1, {2, 4, 6}, "test"}; + std::string str; + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + + test_pb_st9 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + test_pb_st10 st1{0, 1, {{0, 5, {7, 8}}, {0, 9, {11, 12}}}, "test"}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st10 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + message_t m{0, 1, {0, 3, 4}}; + test_pb_st11 st1{0, 1, {m}, {}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st11 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + message_t st1{}; + std::string str; + iguana::to_pb(st1, str); + + message_t st2{}; + iguana::from_pb(st2, str); + CHECK(st1.id == st2.id); + } + { + test_pb_st11 st1{0, 1, {{{0, 5, {7, 8}}}, {{0, 9, {11, 12}}}}, {"test"}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st11 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // map messages + test_pb_st12 st1{0, 1, {{1, "test"}, {2, "ok"}}, {{"test", 4}, {"ok", 6}}}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st12 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // map messages + test_pb_st12 st1{0, 1, {{1, ""}, {0, "ok"}}, {{"", 4}, {"ok", 0}}}; + std::string str; + iguana::to_pb(st1, str); // error + print_hex_str(str); + test_pb_st12 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // map messages + test_pb_st13 st1; + st1.x = 1; + st1.y.emplace(1, message_t{0, 2, {0, 3, 4}}); + st1.y.emplace(2, message_t{0, 4, {0, 6, 8}}); + st1.z = "test"; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st13 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // map messages + test_pb_st13 st1; + st1.x = 1; + st1.y.emplace(2, message_t{}); + st1.y.emplace(3, message_t{}); + st1.z = "test"; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st13 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // enum + test_pb_st14 st1{0, 1, colors_t::black, level_t::info}; + std::string str; + iguana::to_pb(st1, str); + + test_pb_st14 st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + } + { + // bool float double + numer_st n{0, true, 10.25, 4.578}, n1; + std::string str; + iguana::to_pb(n, str); + + iguana::from_pb(n1, str); + CHECK(n1.a == n.a); + CHECK(n1.b == n.b); + CHECK(n1.c == n.c); + } +} + +TEST_CASE("test members") { + using namespace iguana; + using namespace iguana::detail; + + my_space::inner_struct inner{0, 41, 42, 43}; + const auto &map = iguana::get_members(); + std::visit( + [&inner](auto &member) mutable { + CHECK(member.field_no == 9); + CHECK(member.field_name == "b"); + CHECK(member.value(inner) == 42); + }, + map.at(9)); + + point_t pt{0, 2, 3}; + const auto &arr1 = iguana::get_members(); + auto &val = arr1.at(1); + std::visit( + [&pt](auto &member) mutable { + CHECK(member.field_no == 1); + CHECK(member.field_name == "x"); + CHECK(member.value(pt) == 2); + }, + val); +} + +struct test_variant PUBLIC { + int x; + std::variant y; + double z; +}; +REFLECTION(test_variant, x, y, z); + +TEST_CASE("test variant") { + { + constexpr auto tp = iguana::get_members_tuple(); + static_assert(std::get<0>(tp).field_no == 1); + static_assert(std::get<1>(tp).field_no == 2); + static_assert(std::get<2>(tp).field_no == 3); + static_assert(std::get<3>(tp).field_no == 4); + static_assert(std::get<4>(tp).field_no == 5); + } + { + constexpr static auto map = iguana::get_members(); + static_assert(map.find(1) != map.end()); + static_assert(map.find(2) != map.end()); + static_assert(map.find(3) != map.end()); + static_assert(map.find(4) != map.end()); + auto val1 = map.find(2); + auto val2 = map.find(3); + std::visit( + [](auto &member) mutable { + CHECK(member.field_no == 2); + CHECK(member.field_name == "y"); + }, + val1->second); + std::visit( + [](auto &member) mutable { + CHECK(member.field_no == 3); + CHECK(member.field_name == "y"); + }, + val2->second); + } + { + test_variant st1 = {0, 5, "Hello, variant!", 3.14}; + std::string str; + iguana::to_pb(st1, str); + test_variant st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + CHECK(std::get(st2.y) == "Hello, variant!"); + } + { + test_variant st1 = {0, 5, 3.88, 3.14}; + std::string str; + iguana::to_pb(st1, str); + test_variant st2; + iguana::from_pb(st2, str); + CHECK(st1.z == st2.z); + CHECK(std::get(st2.y) == 3.88); + } +} + +// doctest comments +// 'function' : must be 'attribute' - see issue #182 +DOCTEST_MSVC_SUPPRESS_WARNING_WITH_PUSH(4007) +int main(int argc, char **argv) { return doctest::Context(argc, argv).run(); } +DOCTEST_MSVC_SUPPRESS_WARNING_POP \ No newline at end of file diff --git a/src/struct_pb/tests/unittest_proto3.h b/src/struct_pb/tests/unittest_proto3.h new file mode 100644 index 000000000..3dc104322 --- /dev/null +++ b/src/struct_pb/tests/unittest_proto3.h @@ -0,0 +1,582 @@ +#pragma once + +#include +#include "unittest_proto3.pb.h" +#include "data_def.pb.h" + +#define PUBLIC : iguana::pb_base + +// define the struct as msg in proto +namespace stpb { +enum class Enum { + ZERO = 0, + FOO = 1, + BAR = 2, + BAZ = 123456, + NEG = -1, // Intentionally negative. +}; + +struct BaseTypeMsg PUBLIC { + int32_t optional_int32; + int64_t optional_int64; + uint32_t optional_uint32; + uint64_t optional_uint64; + float optional_float; + double optional_double; + bool optional_bool; + std::string optional_string; + Enum optional_enum; + bool operator==(const BaseTypeMsg& other) const { + return optional_int32 == other.optional_int32 && + optional_int64 == other.optional_int64 && + optional_uint32 == other.optional_uint32 && + optional_uint64 == other.optional_uint64 && + optional_float == other.optional_float && + optional_double == other.optional_double && + optional_bool == other.optional_bool && + optional_string == other.optional_string && + optional_enum == other.optional_enum; + } +}; +REFLECTION(BaseTypeMsg, optional_int32, optional_int64, optional_uint32, + optional_uint64, optional_float, optional_double, optional_bool, + optional_string, optional_enum); + +struct IguanaTypeMsg PUBLIC { + iguana::sint32_t optional_sint32; + iguana::sint64_t optional_sint64; + iguana::fixed32_t optional_fixed32; + iguana::fixed64_t optional_fixed64; + iguana::sfixed32_t optional_sfixed32; + iguana::sfixed64_t optional_sfixed64; + + bool operator==(const IguanaTypeMsg& other) const { + return optional_sint32 == other.optional_sint32 && + optional_sint64 == other.optional_sint64 && + optional_fixed32 == other.optional_fixed32 && + optional_fixed64 == other.optional_fixed64 && + optional_sfixed32 == other.optional_sfixed32 && + optional_sfixed64 == other.optional_sfixed64; + } +}; +REFLECTION(IguanaTypeMsg, optional_sint32, optional_sint64, optional_fixed32, + optional_fixed64, optional_sfixed32, optional_sfixed64); + +struct RepeatBaseTypeMsg PUBLIC { + std::vector repeated_uint32; + std::vector repeated_uint64; + std::vector repeated_int32; + std::vector repeated_int64; + std::vector repeated_float; + std::vector repeated_double; + std::vector repeated_string; + std::vector repeated_enum; +}; + +REFLECTION(RepeatBaseTypeMsg, repeated_uint32, repeated_uint64, repeated_int32, + repeated_int64, repeated_float, repeated_double, repeated_string, + repeated_enum); + +struct RepeatIguanaTypeMsg PUBLIC { + std::vector repeated_sint32; + std::vector repeated_sint64; + std::vector repeated_fixed32; + std::vector repeated_fixed64; + std::vector repeated_sfixed32; + std::vector repeated_sfixed64; +}; + +REFLECTION(RepeatIguanaTypeMsg, repeated_sint32, repeated_sint64, + repeated_fixed32, repeated_fixed64, repeated_sfixed32, + repeated_sfixed64); + +struct NestedMsg PUBLIC { + BaseTypeMsg base_msg; + std::vector repeat_base_msg; + IguanaTypeMsg iguana_type_msg; + std::vector repeat_iguna_msg; + std::vector repeat_repeat_base_msg; +}; +REFLECTION(NestedMsg, base_msg, repeat_base_msg, iguana_type_msg, + repeat_iguna_msg, repeat_repeat_base_msg); + +struct MapMsg PUBLIC { + std::unordered_map sfix64_str_map{}; + std::unordered_map str_iguana_type_msg_map{}; + std::map int_repeat_base_msg_map{}; +}; +REFLECTION(MapMsg, sfix64_str_map, str_iguana_type_msg_map, + int_repeat_base_msg_map); + +struct BaseOneofMsg PUBLIC { + int32_t optional_int32; + std::variant one_of; + double optional_double; +}; +REFLECTION(BaseOneofMsg, optional_int32, one_of, optional_double); + +struct NestOneofMsg PUBLIC { + std::variant nest_one_of_msg; +}; +REFLECTION(NestOneofMsg, nest_one_of_msg); + +struct simple_t PUBLIC { + int32_t a; + int32_t b; + int64_t c; + int64_t d; + std::string_view str; +}; +REFLECTION(simple_t, a, b, c, d, str); + +struct simple_t1 PUBLIC { + int32_t a; + int32_t b; + int64_t c; + int64_t d; + std::string_view str; +}; +REFLECTION(simple_t1, a, b, c, d, str); + +enum Color : uint8_t { Red, Green, Blue }; + +struct simple_t2 PUBLIC { + int16_t a; + uint8_t b; + Color c; + int64_t d; + std::string_view str; +}; +REFLECTION(simple_t2, a, b, c, d, str); + +struct person PUBLIC { + int32_t id; + std::string name; + int age; + double salary; +}; +REFLECTION(person, id, name, age, salary); + +struct rect PUBLIC { + int32_t x = 1; + int32_t y = 0; + int32_t width = 11; + int32_t height = 1; +}; +REFLECTION(rect, x, y, width, height); + +struct Vec3 PUBLIC { + float x; + float y; + float z; + + REFLECTION(Vec3, x, y, z); +}; + +struct Weapon PUBLIC { + std::string name; + int32_t damage; +}; +REFLECTION(Weapon, name, damage); + +struct Monster PUBLIC { + Vec3 pos; + int32_t mana; + int32_t hp; + std::string name; + std::string inventory; + int32_t color; + std::vector weapons; + Weapon equipped; + std::vector path; +}; +REFLECTION(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, + path); + +struct bench_int32 PUBLIC { + int32_t a; + int32_t b; + int32_t c; + int32_t d; +}; +REFLECTION(bench_int32, a, b, c, d); + +} // namespace stpb + +namespace protobuf_sample { +inline mygame::person create_person() { + mygame::person p; + p.set_id(432798); + p.set_name(std::string(1024, 'A')); + p.set_age(24); + p.set_salary(65536.42); + return p; +} + +inline mygame::Monster create_monster() { + mygame::Monster m; + + auto vec = new mygame::Vec3; + vec->set_x(1); + vec->set_y(2); + vec->set_z(3); + m.set_allocated_pos(vec); + m.set_mana(16); + m.set_hp(24); + m.set_name("it is a test"); + m.set_inventory("\1\2\3\4"); + m.set_color(::mygame::Monster_Color::Monster_Color_Red); + auto w1 = m.add_weapons(); + w1->set_name("gun"); + w1->set_damage(42); + auto w2 = m.add_weapons(); + w2->set_name("shotgun"); + w2->set_damage(56); + auto w3 = new mygame::Weapon; + w3->set_name("air craft"); + w3->set_damage(67); + m.set_allocated_equipped(w3); + auto p1 = m.add_path(); + p1->set_x(7); + p1->set_y(8); + p1->set_z(9); + auto p2 = m.add_path(); + p2->set_x(71); + p2->set_y(81); + p2->set_z(91); + + return m; +} +} // namespace protobuf_sample + +inline auto create_person() { + stpb::person p{0, 432798, std::string(1024, 'A'), 24, 65536.42}; + return p; +} + +inline stpb::Monster create_sp_monster() { + stpb::Monster m = { + 0, + {0, 1, 2, 3}, + 16, + 24, + "it is a test", + "\1\2\3\4", + stpb::Color::Red, + {{0, "gun", 42}, {0, "shotgun", 56}}, + {0, "air craft", 67}, + {{0, 7, 8, 9}, {0, 71, 81, 91}}, + }; + return m; +} + +void SetBaseTypeMsg(const stpb::BaseTypeMsg& st, pb::BaseTypeMsg& msg) { + msg.set_optional_int32(st.optional_int32); + msg.set_optional_int64(st.optional_int64); + msg.set_optional_uint32(st.optional_uint32); + msg.set_optional_uint64(st.optional_uint64); + msg.set_optional_float(st.optional_float); + msg.set_optional_double(st.optional_double); + msg.set_optional_bool(st.optional_bool); + msg.set_optional_string(st.optional_string); + msg.set_optional_enum(static_cast(st.optional_enum)); +} + +void CheckBaseTypeMsg(const stpb::BaseTypeMsg& st, const pb::BaseTypeMsg& msg) { + CHECK(st.optional_int32 == msg.optional_int32()); + CHECK(st.optional_int64 == msg.optional_int64()); + CHECK(st.optional_uint32 == msg.optional_uint32()); + CHECK(st.optional_uint64 == msg.optional_uint64()); + CHECK(st.optional_float == msg.optional_float()); + CHECK(st.optional_double == msg.optional_double()); + CHECK(st.optional_bool == msg.optional_bool()); + CHECK(st.optional_string == msg.optional_string()); + CHECK(static_cast(st.optional_enum) == + static_cast(msg.optional_enum())); +} + +void SetIguanaTypeMsg(const stpb::IguanaTypeMsg& st, pb::IguanaTypeMsg& msg) { + msg.set_optional_sint32(st.optional_sint32.val); + msg.set_optional_sint64(st.optional_sint64.val); + msg.set_optional_fixed32(st.optional_fixed32.val); + msg.set_optional_fixed64(st.optional_fixed64.val); + msg.set_optional_sfixed32(st.optional_sfixed32.val); + msg.set_optional_sfixed64(st.optional_sfixed64.val); +} + +void CheckIguanaTypeMsg(const stpb::IguanaTypeMsg& st, + const pb::IguanaTypeMsg& msg) { + CHECK(st.optional_sint32.val == msg.optional_sint32()); + CHECK(st.optional_sint64.val == msg.optional_sint64()); + CHECK(st.optional_fixed32.val == msg.optional_fixed32()); + CHECK(st.optional_fixed64.val == msg.optional_fixed64()); + CHECK(st.optional_sfixed32.val == msg.optional_sfixed32()); + CHECK(st.optional_sfixed64.val == msg.optional_sfixed64()); +} + +void SetRepeatBaseTypeMsg(const stpb::RepeatBaseTypeMsg& st, + pb::RepeatBaseTypeMsg& msg) { + for (auto v : st.repeated_uint32) { + msg.add_repeated_uint32(v); + } + for (auto v : st.repeated_uint64) { + msg.add_repeated_uint64(v); + } + for (auto v : st.repeated_int32) { + msg.add_repeated_int32(v); + } + for (auto v : st.repeated_int64) { + msg.add_repeated_int64(v); + } + for (auto v : st.repeated_float) { + msg.add_repeated_float(v); + } + for (auto v : st.repeated_double) { + msg.add_repeated_double(v); + } + for (auto v : st.repeated_string) { + msg.add_repeated_string(v); + } + for (auto v : st.repeated_enum) { + msg.add_repeated_enum(static_cast(v)); + } +} + +void CheckRepeatBaseTypeMsg(const stpb::RepeatBaseTypeMsg& st, + const pb::RepeatBaseTypeMsg& msg) { + for (size_t i = 0; i < st.repeated_uint32.size(); ++i) { + CHECK(st.repeated_uint32[i] == msg.repeated_uint32(i)); + } + for (size_t i = 0; i < st.repeated_uint64.size(); ++i) { + CHECK(st.repeated_uint64[i] == msg.repeated_uint64(i)); + } + for (size_t i = 0; i < st.repeated_int32.size(); ++i) { + CHECK(st.repeated_int32[i] == msg.repeated_int32(i)); + } + for (size_t i = 0; i < st.repeated_int64.size(); ++i) { + CHECK(st.repeated_int64[i] == msg.repeated_int64(i)); + } + for (size_t i = 0; i < st.repeated_float.size(); ++i) { + CHECK(st.repeated_float[i] == msg.repeated_float(i)); + } + for (size_t i = 0; i < st.repeated_double.size(); ++i) { + CHECK(st.repeated_double[i] == msg.repeated_double(i)); + } + for (size_t i = 0; i < st.repeated_string.size(); ++i) { + CHECK(st.repeated_string[i] == msg.repeated_string(i)); + } + for (size_t i = 0; i < st.repeated_enum.size(); ++i) { + CHECK(static_cast(st.repeated_enum[i]) == + static_cast(msg.repeated_enum(i))); + } +} + +void SetRepeatIguanaTypeMsg(const stpb::RepeatIguanaTypeMsg& st, + pb::RepeatIguanaTypeMsg& msg) { + for (auto v : st.repeated_sint32) { + msg.add_repeated_sint32(v.val); + } + for (auto v : st.repeated_sint64) { + msg.add_repeated_sint64(v.val); + } + for (auto v : st.repeated_fixed32) { + msg.add_repeated_fixed32(v.val); + } + for (auto v : st.repeated_fixed64) { + msg.add_repeated_fixed64(v.val); + } + for (auto v : st.repeated_sfixed32) { + msg.add_repeated_sfixed32(v.val); + } + for (auto v : st.repeated_sfixed64) { + msg.add_repeated_sfixed64(v.val); + } +} + +void CheckRepeatIguanaTypeMsg(const stpb::RepeatIguanaTypeMsg& st, + const pb::RepeatIguanaTypeMsg& msg) { + for (size_t i = 0; i < st.repeated_sint32.size(); ++i) { + CHECK(st.repeated_sint32[i].val == msg.repeated_sint32(i)); + } + for (size_t i = 0; i < st.repeated_sint64.size(); ++i) { + CHECK(st.repeated_sint64[i].val == msg.repeated_sint64(i)); + } + for (size_t i = 0; i < st.repeated_fixed32.size(); ++i) { + CHECK(st.repeated_fixed32[i].val == msg.repeated_fixed32(i)); + } + for (size_t i = 0; i < st.repeated_fixed64.size(); ++i) { + CHECK(st.repeated_fixed64[i].val == msg.repeated_fixed64(i)); + } + for (size_t i = 0; i < st.repeated_sfixed32.size(); ++i) { + CHECK(st.repeated_sfixed32[i].val == msg.repeated_sfixed32(i)); + } + for (size_t i = 0; i < st.repeated_sfixed64.size(); ++i) { + CHECK(st.repeated_sfixed64[i].val == msg.repeated_sfixed64(i)); + } +} + +void SetNestedMsg(const stpb::NestedMsg& st, pb::NestedMsg& msg) { + SetBaseTypeMsg(st.base_msg, *msg.mutable_base_msg()); + + for (const auto& base_msg : st.repeat_base_msg) { + auto* base_msg_ptr = msg.add_repeat_base_msg(); + SetBaseTypeMsg(base_msg, *base_msg_ptr); + } + + SetIguanaTypeMsg(st.iguana_type_msg, *msg.mutable_iguana_type_msg()); + + for (const auto& iguana_type_msg : st.repeat_iguna_msg) { + auto* iguana_type_msg_ptr = msg.add_repeat_iguna_msg(); + SetIguanaTypeMsg(iguana_type_msg, *iguana_type_msg_ptr); + } + + for (const auto& repeat_base_msg : st.repeat_repeat_base_msg) { + auto* repeat_base_msg_ptr = msg.add_repeat_repeat_base_msg(); + SetRepeatBaseTypeMsg(repeat_base_msg, *repeat_base_msg_ptr); + } +} + +void CheckNestedMsg(const stpb::NestedMsg& st, const pb::NestedMsg& msg) { + CheckBaseTypeMsg(st.base_msg, msg.base_msg()); + + CHECK(st.repeat_base_msg.size() == msg.repeat_base_msg_size()); + for (size_t i = 0; i < st.repeat_base_msg.size(); ++i) { + CheckBaseTypeMsg(st.repeat_base_msg[i], msg.repeat_base_msg(i)); + } + + CheckIguanaTypeMsg(st.iguana_type_msg, msg.iguana_type_msg()); + + CHECK(st.repeat_iguna_msg.size() == msg.repeat_iguna_msg_size()); + for (size_t i = 0; i < st.repeat_iguna_msg.size(); ++i) { + CheckIguanaTypeMsg(st.repeat_iguna_msg[i], msg.repeat_iguna_msg(i)); + } + + CHECK(st.repeat_repeat_base_msg.size() == + msg.repeat_repeat_base_msg_size()); + for (size_t i = 0; i < st.repeat_repeat_base_msg.size(); ++i) { + CheckRepeatBaseTypeMsg(st.repeat_repeat_base_msg[i], + msg.repeat_repeat_base_msg(i)); + } +} + +void SetMapMsg(const stpb::MapMsg& st, pb::MapMsg& msg) { + msg.Clear(); + for (const auto& pair : st.sfix64_str_map) { + (*msg.mutable_sfix64_str_map())[pair.first.val] = pair.second; + } + for (const auto& pair : st.str_iguana_type_msg_map) { + pb::IguanaTypeMsg* it_msg = + &((*msg.mutable_str_iguana_type_msg_map())[pair.first]); + SetIguanaTypeMsg(pair.second, *it_msg); + } + for (const auto& pair : st.int_repeat_base_msg_map) { + pb::RepeatBaseTypeMsg* rb_msg = + &((*msg.mutable_int_repeat_base_msg_map())[pair.first]); + SetRepeatBaseTypeMsg(pair.second, *rb_msg); + } +} + +void CheckMapMsg(const stpb::MapMsg& st, const pb::MapMsg& msg) { + CHECK(msg.sfix64_str_map_size() == st.sfix64_str_map.size()); + for (const auto& pair : st.sfix64_str_map) { + auto it = msg.sfix64_str_map().find(pair.first.val); + CHECK(it != msg.sfix64_str_map().end()); + CHECK(it->second == pair.second); + } + CHECK(msg.str_iguana_type_msg_map_size() == + st.str_iguana_type_msg_map.size()); + for (const auto& pair : st.str_iguana_type_msg_map) { + auto it = msg.str_iguana_type_msg_map().find(pair.first); + CHECK(it != msg.str_iguana_type_msg_map().end()); + CheckIguanaTypeMsg(pair.second, it->second); + } + + CHECK(msg.int_repeat_base_msg_map_size() == + st.int_repeat_base_msg_map.size()); + for (const auto& pair : st.int_repeat_base_msg_map) { + auto it = msg.int_repeat_base_msg_map().find(pair.first); + CHECK(it != msg.int_repeat_base_msg_map().end()); + CheckRepeatBaseTypeMsg(pair.second, it->second); + } +} + +void SetBaseOneofMsg(const stpb::BaseOneofMsg& st, pb::BaseOneofMsg& msg) { + msg.set_optional_int32(st.optional_int32); + msg.set_optional_double(st.optional_double); + + std::visit( + [&](auto& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + msg.set_one_of_double(value); + } + else if constexpr (std::is_same_v) { + msg.set_one_of_string(value); + } + else if constexpr (std::is_same_v) { + auto* submsg = msg.mutable_one_of_base_type_msg(); + SetBaseTypeMsg(value, *submsg); + } + }, + st.one_of); +} + +void CheckBaseOneofMsg(const stpb::BaseOneofMsg& st, + const pb::BaseOneofMsg& msg) { + CHECK(st.optional_int32 == msg.optional_int32()); + CHECK(st.optional_double == msg.optional_double()); + + std::visit( + [&](auto& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + CHECK(value == msg.one_of_double()); + } + else if constexpr (std::is_same_v) { + CHECK(value == msg.one_of_string()); + } + else if constexpr (std::is_same_v) { + CheckBaseTypeMsg(value, msg.one_of_base_type_msg()); + } + }, + st.one_of); +} + +void SetNestOneofMsg(const stpb::NestOneofMsg& st, pb::NestOneofMsg& msg) { + std::visit( + [&](auto& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + msg.set_base_one_of_string(value); + } + else if constexpr (std::is_same_v) { + auto* submsg = msg.mutable_base_one_of_msg(); + SetBaseOneofMsg(value, *submsg); + } + }, + st.nest_one_of_msg); +} + +void CheckNestOneofMsg(const stpb::NestOneofMsg& st, + const pb::NestOneofMsg& msg) { + std::visit( + [&](auto& value) { + using T = std::decay_t; + if constexpr (std::is_same_v) { + CHECK(value == msg.base_one_of_string()); + } + else if constexpr (std::is_same_v) { + CheckBaseOneofMsg(value, msg.base_one_of_msg()); + } + }, + st.nest_one_of_msg); +} + +inline void print_hex_str(const std::string& str) { + std::ostringstream oss; + oss << std::hex << std::setfill('0'); + for (unsigned char c : str) { + oss << std::setw(2) << static_cast(c); + } + std::cout << oss.str() << std::endl; +} diff --git a/src/struct_pb/tests/unittest_proto3.proto b/src/struct_pb/tests/unittest_proto3.proto new file mode 100644 index 000000000..c736d6ef3 --- /dev/null +++ b/src/struct_pb/tests/unittest_proto3.proto @@ -0,0 +1,108 @@ +syntax = "proto3"; + +package pb; + +option optimize_for = SPEED; + +enum Enum { + ZERO = 0; + FOO = 1; + BAR = 2; + BAZ = 123456; + NEG = -1; // Intentionally negative. +} + +message BaseTypeMsg { + int32 optional_int32 = 1; + int64 optional_int64 = 2; + uint32 optional_uint32 = 3; + uint64 optional_uint64 = 4; + float optional_float = 5; + double optional_double = 6; + bool optional_bool = 7; + string optional_string = 8; + Enum optional_enum = 9; +} + +message RepeatBaseTypeMsg { + repeated uint32 repeated_uint32 = 1; + repeated uint64 repeated_uint64 = 2; + repeated int32 repeated_int32 = 3; + repeated int64 repeated_int64 = 4; + repeated float repeated_float = 5; + repeated double repeated_double = 6; + repeated string repeated_string = 7; + repeated Enum repeated_enum = 8; +} + +message IguanaTypeMsg { + sint32 optional_sint32 = 1; + sint64 optional_sint64 = 2; + fixed32 optional_fixed32 = 3; + fixed64 optional_fixed64 = 4; + sfixed32 optional_sfixed32 = 5; + sfixed64 optional_sfixed64 = 6; +} + +message RepeatIguanaTypeMsg { + repeated sfixed32 repeated_sint32 = 1; + repeated sfixed64 repeated_sint64 = 2; + repeated fixed32 repeated_fixed32 = 3; + repeated fixed64 repeated_fixed64 = 4; + repeated sfixed32 repeated_sfixed32 = 5; + repeated sfixed64 repeated_sfixed64 = 6; +} + +message NestedMsg { + BaseTypeMsg base_msg = 1; + repeated BaseTypeMsg repeat_base_msg = 2; + IguanaTypeMsg iguana_type_msg = 3; + repeated IguanaTypeMsg repeat_iguna_msg = 4; + repeated RepeatBaseTypeMsg repeat_repeat_base_msg = 5; +} + +message MapMsg { + map sfix64_str_map = 1; + map str_iguana_type_msg_map = 2; + map int_repeat_base_msg_map = 3; + // Key in map fields cannot be float/double, bytes or message types. +} + +message BaseOneofMsg { + int32 optional_int32 = 1; + oneof one_of { + double one_of_double = 2; + string one_of_string = 3; + BaseTypeMsg one_of_base_type_msg = 4; + } + double optional_double = 5; +} + +message NestOneofMsg { + oneof nest_one_of_msg { + string base_one_of_string = 1; + BaseOneofMsg base_one_of_msg = 2; + } +} + +message Simple { + int32 a = 1; + int32 b = 2; + int64 c = 3; + int64 d = 4; + string str = 5; +} + +enum Color { + Red = 0; + Green = 1; + Blue = 2; +} + +message Simple2 { + int32 a = 1; + int32 b = 2; + Color c = 3; + int64 d = 4; + string str = 5; +} \ No newline at end of file From 8524d805153f4c96b161ef7a61cc9889bb227462 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 22 May 2024 18:52:41 +0800 Subject: [PATCH 09/26] update doc --- src/struct_pb/examples/main.cpp | 2 +- src/struct_pb/tests/main.cpp | 230 +++++++++--------- website/.vitepress/config/en_data.ts | 3 +- website/.vitepress/config/zh_data.ts | 3 +- website/docs/en/struct_pb/struct_pb_intro.md | 216 +++++++--------- .../struct_pb/struct_pb_supported_features.md | 67 ----- website/docs/zh/struct_pb/struct_pb_intro.md | 208 ++++++---------- .../struct_pb/struct_pb_supported_features.md | 67 ----- 8 files changed, 273 insertions(+), 523 deletions(-) delete mode 100644 website/docs/en/struct_pb/struct_pb_supported_features.md delete mode 100644 website/docs/zh/struct_pb/struct_pb_supported_features.md diff --git a/src/struct_pb/examples/main.cpp b/src/struct_pb/examples/main.cpp index 5eebd583c..d2d26677c 100644 --- a/src/struct_pb/examples/main.cpp +++ b/src/struct_pb/examples/main.cpp @@ -5,7 +5,7 @@ struct my_struct : struct_pb::pb_base { int x; bool y; - iguana::fixed64_t z; + struct_pb::fixed64_t z; }; REFLECTION(my_struct, x, y, z); diff --git a/src/struct_pb/tests/main.cpp b/src/struct_pb/tests/main.cpp index ca06723e3..d2f498b5f 100644 --- a/src/struct_pb/tests/main.cpp +++ b/src/struct_pb/tests/main.cpp @@ -10,7 +10,7 @@ TEST_CASE("test BaseTypeMsg") { stpb::BaseTypeMsg se_st{0, 100, 200, 300, 400, 31.4f, 62.8, false, "World", stpb::Enum::ZERO}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::BaseTypeMsg se_msg; SetBaseTypeMsg(se_st, se_msg); @@ -19,7 +19,7 @@ TEST_CASE("test BaseTypeMsg") { CHECK(st_ss == pb_ss); stpb::BaseTypeMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::BaseTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckBaseTypeMsg(dese_st, dese_msg); @@ -37,7 +37,7 @@ TEST_CASE("test BaseTypeMsg") { "", stpb::Enum::NEG}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::BaseTypeMsg se_msg; SetBaseTypeMsg(se_st, se_msg); @@ -46,7 +46,7 @@ TEST_CASE("test BaseTypeMsg") { CHECK(st_ss == pb_ss); stpb::BaseTypeMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::BaseTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckBaseTypeMsg(dese_st, dese_msg); @@ -63,7 +63,7 @@ TEST_CASE("test BaseTypeMsg") { std::string(1000, 'x'), stpb::Enum::BAZ}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::BaseTypeMsg se_msg; SetBaseTypeMsg(se_st, se_msg); @@ -72,7 +72,7 @@ TEST_CASE("test BaseTypeMsg") { CHECK(st_ss == pb_ss); stpb::BaseTypeMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::BaseTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckBaseTypeMsg(dese_st, dese_msg); @@ -82,10 +82,10 @@ TEST_CASE("test BaseTypeMsg") { TEST_CASE("test person and monster") { stpb::simple_t2 t{0, -100, 2, stpb::Color::Blue, 4}; std::string str; - iguana::to_pb(t, str); + struct_pb::to_pb(t, str); stpb::simple_t2 t2; - iguana::from_pb(t2, str); + struct_pb::from_pb(t2, str); CHECK(t.c == t2.c); pb::Simple2 s; @@ -108,7 +108,7 @@ TEST_CASE("test person and monster") { std::string sp_str; pb_monster.SerializeToString(&pb_str); - iguana::to_pb(sp_monster, sp_str); + struct_pb::to_pb(sp_monster, sp_str); CHECK(pb_str == sp_str); @@ -117,13 +117,13 @@ TEST_CASE("test person and monster") { CHECK(m.name() == pb_monster.name()); stpb::Monster spm; - iguana::from_pb(spm, sp_str); + struct_pb::from_pb(spm, sp_str); CHECK(spm.name == sp_monster.name); auto pb_person = protobuf_sample::create_person(); auto sp_person = create_person(); pb_person.SerializePartialToString(&pb_str); - iguana::to_pb(sp_person, sp_str); + struct_pb::to_pb(sp_person, sp_str); CHECK(pb_str == sp_str); @@ -132,7 +132,7 @@ TEST_CASE("test person and monster") { CHECK(pp.name() == pb_person.name()); stpb::person p; - iguana::from_pb(p, sp_str); + struct_pb::from_pb(p, sp_str); CHECK(p.name == sp_person.name); } @@ -140,7 +140,7 @@ TEST_CASE("test IguanaTypeMsg") { { // test normal value stpb::IguanaTypeMsg se_st{0, {100}, {200}, {300}, {400}, {31}, {32}}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::IguanaTypeMsg se_msg{}; SetIguanaTypeMsg(se_st, se_msg); @@ -149,7 +149,7 @@ TEST_CASE("test IguanaTypeMsg") { CHECK(st_ss == pb_ss); stpb::IguanaTypeMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::IguanaTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckIguanaTypeMsg(dese_st, dese_msg); @@ -164,7 +164,7 @@ TEST_CASE("test IguanaTypeMsg") { {std::numeric_limits::lowest()}, {std::numeric_limits::lowest()}}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::IguanaTypeMsg se_msg{}; SetIguanaTypeMsg(se_st, se_msg); @@ -172,7 +172,7 @@ TEST_CASE("test IguanaTypeMsg") { se_msg.SerializeToString(&pb_ss); CHECK(st_ss == pb_ss); stpb::IguanaTypeMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::IguanaTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckIguanaTypeMsg(dese_st, dese_msg); @@ -186,7 +186,7 @@ TEST_CASE("test IguanaTypeMsg") { {std::numeric_limits::max()}, {std::numeric_limits::max()}}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::IguanaTypeMsg se_msg; SetIguanaTypeMsg(se_st, se_msg); @@ -195,7 +195,7 @@ TEST_CASE("test IguanaTypeMsg") { CHECK(st_ss == pb_ss); stpb::IguanaTypeMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::IguanaTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckIguanaTypeMsg(dese_st, dese_msg); @@ -203,7 +203,7 @@ TEST_CASE("test IguanaTypeMsg") { { // test empty stpb::IguanaTypeMsg se_st{}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::IguanaTypeMsg se_msg; SetIguanaTypeMsg(se_st, se_msg); @@ -212,7 +212,7 @@ TEST_CASE("test IguanaTypeMsg") { CHECK(st_ss == pb_ss); stpb::IguanaTypeMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::IguanaTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckIguanaTypeMsg(dese_st, dese_msg); @@ -232,7 +232,7 @@ TEST_CASE("test RepeatBaseTypeMsg") { {"a", "b", "c"}, {stpb::Enum::BAZ, stpb::Enum::ZERO, stpb::Enum::NEG}}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::RepeatBaseTypeMsg se_msg; SetRepeatBaseTypeMsg(se_st, se_msg); @@ -241,7 +241,7 @@ TEST_CASE("test RepeatBaseTypeMsg") { CHECK(st_ss == pb_ss); stpb::RepeatBaseTypeMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::RepeatBaseTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckRepeatBaseTypeMsg(dese_st, dese_msg); @@ -262,7 +262,7 @@ TEST_CASE("test RepeatBaseTypeMsg") { {"", "", ""}, {stpb::Enum::NEG, stpb::Enum::FOO}}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::RepeatBaseTypeMsg se_msg; SetRepeatBaseTypeMsg(se_st, se_msg); @@ -270,7 +270,7 @@ TEST_CASE("test RepeatBaseTypeMsg") { se_msg.SerializeToString(&pb_ss); CHECK(st_ss == pb_ss); stpb::RepeatBaseTypeMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::RepeatBaseTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckRepeatBaseTypeMsg(dese_st, dese_msg); @@ -289,7 +289,7 @@ TEST_CASE("test RepeatIguanaTypeMsg") { {}, }; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::RepeatIguanaTypeMsg se_msg; SetRepeatIguanaTypeMsg(se_st, se_msg); @@ -298,7 +298,7 @@ TEST_CASE("test RepeatIguanaTypeMsg") { CHECK(st_ss == pb_ss); stpb::RepeatIguanaTypeMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::RepeatIguanaTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckRepeatIguanaTypeMsg(dese_st, dese_msg); @@ -338,7 +338,7 @@ TEST_CASE("test NestedMsg") { {stpb::Enum::ZERO, stpb::Enum::NEG, stpb::Enum::FOO}}}}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::NestedMsg se_msg; SetNestedMsg(se_st, se_msg); @@ -349,7 +349,7 @@ TEST_CASE("test NestedMsg") { CHECK(st_ss == pb_ss); stpb::NestedMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::NestedMsg dese_msg; dese_msg.ParseFromString(pb_ss); @@ -365,7 +365,7 @@ TEST_CASE("test NestedMsg") { /* repeat_iguna_msg */ {}, /* repeat_repeat_base_msg */ {}}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::NestedMsg se_msg; SetNestedMsg(se_st, se_msg); @@ -376,7 +376,7 @@ TEST_CASE("test NestedMsg") { print_hex_str(st_ss); print_hex_str(pb_ss); stpb::NestedMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::NestedMsg dese_msg; dese_msg.ParseFromString(pb_ss); @@ -389,8 +389,8 @@ TEST_CASE("test MapMsg") { { stpb::MapMsg se_st{}; - se_st.sfix64_str_map.emplace(iguana::sfixed64_t{10}, "ten"); - se_st.sfix64_str_map.emplace(iguana::sfixed64_t{20}, "twenty"); + se_st.sfix64_str_map.emplace(struct_pb::sfixed64_t{10}, "ten"); + se_st.sfix64_str_map.emplace(struct_pb::sfixed64_t{20}, "twenty"); se_st.str_iguana_type_msg_map.emplace( "first", stpb::IguanaTypeMsg{{10}, {20}, {30}, {40}, {50}, {60}}); @@ -419,7 +419,7 @@ TEST_CASE("test MapMsg") { {stpb::Enum::BAZ, stpb::Enum::NEG}}); std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::MapMsg se_msg{}; SetMapMsg(se_st, se_msg); @@ -429,7 +429,7 @@ TEST_CASE("test MapMsg") { // CHECK(st_ss == pb_ss); CHECK(st_ss.size() == pb_ss.size()); stpb::MapMsg dese_st{}; - iguana::from_pb(dese_st, pb_ss); + struct_pb::from_pb(dese_st, pb_ss); pb::MapMsg dese_msg; dese_msg.ParseFromString(st_ss); CheckMapMsg(dese_st, dese_msg); @@ -437,13 +437,13 @@ TEST_CASE("test MapMsg") { { // key empty stpb::MapMsg se_st{}; - se_st.sfix64_str_map.emplace(iguana::sfixed64_t{30}, ""); + se_st.sfix64_str_map.emplace(struct_pb::sfixed64_t{30}, ""); se_st.str_iguana_type_msg_map.emplace( "", stpb::IguanaTypeMsg{0, {0}, {0}, {0}, {0}, {0}, {0}}); se_st.int_repeat_base_msg_map.emplace( 3, stpb::RepeatBaseTypeMsg{0, {}, {}, {}, {}, {}, {}, {}, {}}); std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::MapMsg se_msg{}; SetMapMsg(se_st, se_msg); @@ -452,7 +452,7 @@ TEST_CASE("test MapMsg") { CHECK(st_ss == pb_ss); stpb::MapMsg dese_st{}; - iguana::from_pb(dese_st, pb_ss); + struct_pb::from_pb(dese_st, pb_ss); pb::MapMsg dese_msg; dese_msg.ParseFromString(st_ss); CheckMapMsg(dese_st, dese_msg); @@ -463,7 +463,7 @@ TEST_CASE("test BaseOneofMsg") { { // test double stpb::BaseOneofMsg se_st{0, 123, 3.14159, 456.78}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::BaseOneofMsg se_msg; SetBaseOneofMsg(se_st, se_msg); @@ -473,7 +473,7 @@ TEST_CASE("test BaseOneofMsg") { // print_hex_str(st_ss); // print_hex_str(pb_ss); stpb::BaseOneofMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::BaseOneofMsg dese_msg; dese_msg.ParseFromString(pb_ss); @@ -482,7 +482,7 @@ TEST_CASE("test BaseOneofMsg") { { // test string stpb::BaseOneofMsg se_st{0, 123, std::string("Hello"), 456.78}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::BaseOneofMsg se_msg; SetBaseOneofMsg(se_st, se_msg); @@ -491,7 +491,7 @@ TEST_CASE("test BaseOneofMsg") { CHECK(st_ss == pb_ss); stpb::BaseOneofMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::BaseOneofMsg dese_msg; dese_msg.ParseFromString(pb_ss); @@ -503,7 +503,7 @@ TEST_CASE("test BaseOneofMsg") { stpb::BaseOneofMsg se_st{0, 123, baseTypeMsg, 456.78}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::BaseOneofMsg se_msg; SetBaseOneofMsg(se_st, se_msg); @@ -512,7 +512,7 @@ TEST_CASE("test BaseOneofMsg") { CHECK(st_ss == pb_ss); stpb::BaseOneofMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::BaseOneofMsg dese_msg; dese_msg.ParseFromString(pb_ss); @@ -522,7 +522,7 @@ TEST_CASE("test BaseOneofMsg") { stpb::BaseOneofMsg se_st{0, 123, {}, 456.78}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::BaseOneofMsg se_msg; SetBaseOneofMsg(se_st, se_msg); @@ -532,7 +532,7 @@ TEST_CASE("test BaseOneofMsg") { print_hex_str(st_ss); print_hex_str(pb_ss); stpb::BaseOneofMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::BaseOneofMsg dese_msg; dese_msg.ParseFromString(pb_ss); @@ -546,7 +546,7 @@ TEST_CASE("test NestOneofMsg ") { stpb::NestOneofMsg se_st{{baseOneof}}; std::string st_ss; - iguana::to_pb(se_st, st_ss); + struct_pb::to_pb(se_st, st_ss); pb::NestOneofMsg se_msg; SetNestOneofMsg(se_st, se_msg); @@ -554,7 +554,7 @@ TEST_CASE("test NestOneofMsg ") { se_msg.SerializeToString(&pb_ss); CHECK(st_ss == pb_ss); stpb::NestOneofMsg dese_st{}; - iguana::from_pb(dese_st, st_ss); + struct_pb::from_pb(dese_st, st_ss); pb::NestOneofMsg dese_msg; dese_msg.ParseFromString(pb_ss); @@ -577,30 +577,30 @@ struct inner_struct PUBLIC { }; constexpr inline auto get_members_impl(inner_struct *) { - return std::make_tuple(iguana::field_t{&inner_struct::x, 7, "a"}, - iguana::field_t{&inner_struct::y, 9, "b"}, - iguana::field_t{&inner_struct::z, 12, "c"}); + return std::make_tuple(struct_pb::field_t{&inner_struct::x, 7, "a"}, + struct_pb::field_t{&inner_struct::y, 9, "b"}, + struct_pb::field_t{&inner_struct::z, 12, "c"}); } } // namespace my_space struct test_pb_st1 PUBLIC { int x; - iguana::sint32_t y; - iguana::sint64_t z; + struct_pb::sint32_t y; + struct_pb::sint64_t z; }; REFLECTION(test_pb_st1, x, y, z); struct test_pb_st2 PUBLIC { int x; - iguana::fixed32_t y; - iguana::fixed64_t z; + struct_pb::fixed32_t y; + struct_pb::fixed64_t z; }; REFLECTION(test_pb_st2, x, y, z); struct test_pb_st3 PUBLIC { int x; - iguana::sfixed32_t y; - iguana::sfixed64_t z; + struct_pb::sfixed32_t y; + struct_pb::sfixed64_t z; }; REFLECTION(test_pb_st3, x, y, z); @@ -699,7 +699,7 @@ REFLECTION(person, name, age); struct my_struct PUBLIC { int x; bool y; - iguana::fixed64_t z; + struct_pb::fixed64_t z; }; REFLECTION(my_struct, x, y, z); @@ -723,11 +723,11 @@ TEST_CASE("test struct_pb") { my_space::inner_struct inner{0, 41, 42, 43}; std::string str; - iguana::to_pb(inner, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(inner)); + struct_pb::to_pb(inner, str); + CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(inner)); my_space::inner_struct inner1; - iguana::from_pb(inner1, str); + struct_pb::from_pb(inner1, str); CHECK(inner.x == inner1.x); CHECK(inner.y == inner1.y); CHECK(inner.z == inner1.z); @@ -736,11 +736,11 @@ TEST_CASE("test struct_pb") { { test_pb_st1 st1{0, 41, {42}, {43}}; std::string str; - iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + struct_pb::to_pb(st1, str); + CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); test_pb_st1 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.x == st2.x); CHECK(st1.y.val == st2.y.val); CHECK(st1.z.val == st2.z.val); @@ -749,71 +749,71 @@ TEST_CASE("test struct_pb") { { test_pb_st2 st1{0, 41, {42}, {43}}; std::string str; - iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + struct_pb::to_pb(st1, str); + CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); test_pb_st2 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.y.val == st2.y.val); } { test_pb_st3 st1{0, 41, {42}, {43}}; std::string str; - iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + struct_pb::to_pb(st1, str); + CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); test_pb_st3 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.y.val == st2.y.val); } { test_pb_st4 st1{0, 41, "it is a test"}; std::string str; - iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + struct_pb::to_pb(st1, str); + CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); test_pb_st4 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.y == st2.y); } { test_pb_st5 st1{0, 41, "it is a test"}; std::string str; - iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + struct_pb::to_pb(st1, str); + CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); test_pb_st5 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.y == st2.y); } { // optional test_pb_st6 st1{0, 41, "it is a test"}; std::string str; - iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + struct_pb::to_pb(st1, str); + CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); test_pb_st6 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.y == st2.y); } { // sub nested objects nest1 v{0, "Hi", {0, 1, false, {3}}, 5}, v2{}; std::string s; - iguana::to_pb(v, s); - iguana::from_pb(v2, s); + struct_pb::to_pb(v, s); + struct_pb::from_pb(v2, s); CHECK(v.var == v2.var); CHECK(v.value.y == v2.value.y); CHECK(v.value.z == v2.value.z); test_pb_st8 st1{0, 1, {0, 3, 4}, {0, 5, {0, 7, 8}}}; std::string str; - iguana::to_pb(st1, str); + struct_pb::to_pb(st1, str); test_pb_st8 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.z.t.y == st2.z.t.y); } @@ -821,68 +821,68 @@ TEST_CASE("test struct_pb") { // repeated messages test_pb_st9 st1{0, 1, {2, 4, 6}, "test"}; std::string str; - iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); + struct_pb::to_pb(st1, str); + CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); test_pb_st9 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.z == st2.z); } { test_pb_st10 st1{0, 1, {{0, 5, {7, 8}}, {0, 9, {11, 12}}}, "test"}; std::string str; - iguana::to_pb(st1, str); + struct_pb::to_pb(st1, str); test_pb_st10 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.z == st2.z); } { message_t m{0, 1, {0, 3, 4}}; test_pb_st11 st1{0, 1, {m}, {}}; std::string str; - iguana::to_pb(st1, str); + struct_pb::to_pb(st1, str); test_pb_st11 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.z == st2.z); } { message_t st1{}; std::string str; - iguana::to_pb(st1, str); + struct_pb::to_pb(st1, str); message_t st2{}; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.id == st2.id); } { test_pb_st11 st1{0, 1, {{{0, 5, {7, 8}}}, {{0, 9, {11, 12}}}}, {"test"}}; std::string str; - iguana::to_pb(st1, str); + struct_pb::to_pb(st1, str); test_pb_st11 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.z == st2.z); } { // map messages test_pb_st12 st1{0, 1, {{1, "test"}, {2, "ok"}}, {{"test", 4}, {"ok", 6}}}; std::string str; - iguana::to_pb(st1, str); + struct_pb::to_pb(st1, str); test_pb_st12 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.z == st2.z); } { // map messages test_pb_st12 st1{0, 1, {{1, ""}, {0, "ok"}}, {{"", 4}, {"ok", 0}}}; std::string str; - iguana::to_pb(st1, str); // error + struct_pb::to_pb(st1, str); // error print_hex_str(str); test_pb_st12 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.z == st2.z); } { @@ -893,10 +893,10 @@ TEST_CASE("test struct_pb") { st1.y.emplace(2, message_t{0, 4, {0, 6, 8}}); st1.z = "test"; std::string str; - iguana::to_pb(st1, str); + struct_pb::to_pb(st1, str); test_pb_st13 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.z == st2.z); } { @@ -907,29 +907,29 @@ TEST_CASE("test struct_pb") { st1.y.emplace(3, message_t{}); st1.z = "test"; std::string str; - iguana::to_pb(st1, str); + struct_pb::to_pb(st1, str); test_pb_st13 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.z == st2.z); } { // enum test_pb_st14 st1{0, 1, colors_t::black, level_t::info}; std::string str; - iguana::to_pb(st1, str); + struct_pb::to_pb(st1, str); test_pb_st14 st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.z == st2.z); } { // bool float double numer_st n{0, true, 10.25, 4.578}, n1; std::string str; - iguana::to_pb(n, str); + struct_pb::to_pb(n, str); - iguana::from_pb(n1, str); + struct_pb::from_pb(n1, str); CHECK(n1.a == n.a); CHECK(n1.b == n.b); CHECK(n1.c == n.c); @@ -937,11 +937,11 @@ TEST_CASE("test struct_pb") { } TEST_CASE("test members") { - using namespace iguana; - using namespace iguana::detail; + using namespace struct_pb; + using namespace struct_pb::detail; my_space::inner_struct inner{0, 41, 42, 43}; - const auto &map = iguana::get_members(); + const auto &map = struct_pb::get_members(); std::visit( [&inner](auto &member) mutable { CHECK(member.field_no == 9); @@ -951,7 +951,7 @@ TEST_CASE("test members") { map.at(9)); point_t pt{0, 2, 3}; - const auto &arr1 = iguana::get_members(); + const auto &arr1 = struct_pb::get_members(); auto &val = arr1.at(1); std::visit( [&pt](auto &member) mutable { @@ -971,7 +971,7 @@ REFLECTION(test_variant, x, y, z); TEST_CASE("test variant") { { - constexpr auto tp = iguana::get_members_tuple(); + constexpr auto tp = struct_pb::get_members_tuple(); static_assert(std::get<0>(tp).field_no == 1); static_assert(std::get<1>(tp).field_no == 2); static_assert(std::get<2>(tp).field_no == 3); @@ -979,7 +979,7 @@ TEST_CASE("test variant") { static_assert(std::get<4>(tp).field_no == 5); } { - constexpr static auto map = iguana::get_members(); + constexpr static auto map = struct_pb::get_members(); static_assert(map.find(1) != map.end()); static_assert(map.find(2) != map.end()); static_assert(map.find(3) != map.end()); @@ -1002,18 +1002,18 @@ TEST_CASE("test variant") { { test_variant st1 = {0, 5, "Hello, variant!", 3.14}; std::string str; - iguana::to_pb(st1, str); + struct_pb::to_pb(st1, str); test_variant st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.z == st2.z); CHECK(std::get(st2.y) == "Hello, variant!"); } { test_variant st1 = {0, 5, 3.88, 3.14}; std::string str; - iguana::to_pb(st1, str); + struct_pb::to_pb(st1, str); test_variant st2; - iguana::from_pb(st2, str); + struct_pb::from_pb(st2, str); CHECK(st1.z == st2.z); CHECK(std::get(st2.y) == 3.88); } diff --git a/website/.vitepress/config/en_data.ts b/website/.vitepress/config/en_data.ts index 980b764b2..b6857637d 100644 --- a/website/.vitepress/config/en_data.ts +++ b/website/.vitepress/config/en_data.ts @@ -6,8 +6,7 @@ export const guidLinks = [ //构建系统相关语法 export const struct_pb_Links = [ - { text: 'What is struct_pb?', link: '/en/struct_pb/struct_pb_intro' }, - { text: 'Supported Features', link: '/en/struct_pb/struct_pb_supported_features' }, + { text: 'What is struct_pb?', link: '/en/struct_pb/struct_pb_intro' } ]; export const struct_pack_Links = [ diff --git a/website/.vitepress/config/zh_data.ts b/website/.vitepress/config/zh_data.ts index e404ab2d4..72c6b13cb 100644 --- a/website/.vitepress/config/zh_data.ts +++ b/website/.vitepress/config/zh_data.ts @@ -6,8 +6,7 @@ export const guidLinks = [ //构建系统相关语法 export const struct_pb_Links = [ - { text: 'struct_pb简介', link: '/zh/struct_pb/struct_pb_intro' }, - { text: '特性支持', link: '/zh/struct_pb/struct_pb_supported_features' }, + { text: 'struct_pb简介', link: '/zh/struct_pb/struct_pb_intro' } ]; export const struct_pack_Links = [ diff --git a/website/docs/en/struct_pb/struct_pb_intro.md b/website/docs/en/struct_pb/struct_pb_intro.md index d833e38db..efceb0947 100644 --- a/website/docs/en/struct_pb/struct_pb_intro.md +++ b/website/docs/en/struct_pb/struct_pb_intro.md @@ -1,28 +1,72 @@ -# struct_pb Introduction +# struct_pb introduction -## Motivation -Protocol buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data. So many programs use protobuf as their serialization library. It is convienient for our customers to use `struct_pack` if we (`struct_pack`) can compatible with protobuf binary format. That is why we create `struct_pb`. +struct_pb is an easy to use, C++17, header only, high performance protobuf format serialization library. -## Background -In this section, we introduce the [protocol buffer wire format](https://developers.google.com/protocol-buffers/docs/encoding), which defines the details of how protobuf message is sent on the wire and how much space it consumes on disk. -### Message Structure -A protocol buffer message is a series of key-value pairs. The binary version of a message just uses the field's number as the key -- the name and declared type for each field can only be determined on the decoding end by referencing the message type's definition. -![](images/pb_format.jpeg) +## motiviation +Don't depend on proto files, don't depend on protoc to generate code. + +Utilize inline, zero copy, compile-time compute to optimize performance. + +## example + +### define struct +```cpp +#include + +struct my_struct : struct_pb::pb_base { + int x; + bool y; + struct_pb::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); + +struct nest : struct_pb::pb_base { + std::string name; + my_struct value; + int var; +}; +REFLECTION(nest, name, value, var); +``` + +### serialization and deserialization ```cpp -Tag = (field_number << 3) | wire_type +int main() { + nest v{0, "Hi", {0, 1, false, 3}, 5}, v2{}; + std::string s; + struct_pb::to_pb(v, s); + struct_pb::from_pb(v2, s); + assert(v.var == v2.var); + assert(v.value.y == v2.value.y); + assert(v.value.z == v2.value.z); +} +``` +the above struct mapping to a proto file, like this: +``` +message my_struct { + int32 optional_int32 = 1; + bool optional_int64 = 2; + sfixed64 z = 3; +} + +message nest { + string name = 1; + my_struct value = 2; + int32 var = 3; +} ``` +## benchmark +monster case: -### Base 128 Varints -Variable-width integers, or _varints_, are at the core of the wire format. They allow encoding unsigned 64-bit integers using anywhere between one and ten bytes, with small values using fewer bytes. +struct_pb is 2.4 faster than protobuf when serializing a monster; -## Type Mapping -proto3 first, -see also [Protocol Buffers Language Guide (proto3)](https://developers.google.com/protocol-buffers/docs/proto3#scalar) +struct_pb is 3.4 faster than protobuf when deserializing a monster; -### Overview +the code in struct_pack benchmark. + +## struct_pb and protobuf type mapping Scalar Value Types with no modifier (a.k.a **singular**) -> T Scalar Value Types with **optional** -> `std::optional ` @@ -35,33 +79,9 @@ any message type -> `std::optional ` enum -> enum class -oneof -> `std::variant ` - - -Note: - -- singular. - You cannot determine whether it was parsed from the wire. It will be serialized to the wire unless it is the default value. see also [Field Presence](https://github.com/protocolbuffers/protobuf/blob/main/docs/field_presence.md). -- optional. - You can check to see if the value was explicitly set. -- repeat. - In proto3, repeated fields of scalar numeric types use packed encoding by default. -- map. - The key of map can be any integral or string type except enum. - The value of map can be any type except another map. -- enum. - Every enum definition must contain a constant that maps to zero as its first element. - Enumerator constants must be in the range of a 32-bit integer. - During deserialization, unrecognized enum values will be preserved in the message -- oneof. - If you set an oneof field to the default value (such as setting an int32 oneof field to 0), the "case" of that oneof field will be set, and the value will be serialized on the wire. -- default value - - For numeric types, the default is 0. - - For enums, the default is the zero-valued enumerator. - - For strings, bytes, and repeated fields, the default is the zero-length value. - - For messages, the default is the language-specific null value. - -### Basic +oneof -> `std::variant <...>` + +### type mapping table | .proto Type | struct_pb Type | pb native C++ type | Notes | |-------------|-----------------------------------|--------------------|------------------------------------| | double | double | double | 8 bytes | @@ -70,98 +90,26 @@ Note: | int64 | int64 | int64 | | | uint32 | uint32 | uint32 | | | uint64 | uint64 | uint64 | | -| sint32 | int32 | int32 | ZigZag + variable-length encoding. | -| sint64 | int64 | int64 | | -| fixed32 | uint32 | uint32 | 4 bytes | -| fixed64 | uint64 | uint64 | 8 bytes | -| sfixed32 | int32 | int32 | 4 bytes,$2^{28}$ | -| sfixed64 | int64 | int64 | 8 bytes,$2^{56}$ | +| sint32 | sint32_t | int32 | ZigZag + variable-length encoding. | +| sint64 | sint6_t | int64 | | +| fixed32 | fixed32_t | uint32 | 4 bytes | +| fixed64 | fixed64_t | uint64 | 8 bytes | +| sfixed32 | sfixed32_t | int32 | 4 bytes,$2^{28}$ | +| sfixed64 | sfixed64_t | int64 | 8 bytes,$2^{56}$ | | bool | bool | bool | | | string | std::string | string | $len < 2^{32}$ | | bytes | std::string | string | | -| enum | enum class: int {} | enum: int {} | | -| oneof | std::variant | | | - -Note: - -- for enum, we use `enum class` instead of `enum` -- for oneof, we use `std::variant` with first template argument `std::monostate` - -## File Mapping -each `xxx.proto`file generates corresponding `xxx.struct_pb.h` and `xxx.struct_pb.cc` -all dependencies will convert to include corresponding headers. -``` -syntax = "proto3"; - -import "foo.proto"; - -message Bar { - Foo f = 2; -} -``` -mapping to cpp -```cpp -#include "foo.struct_pb.h" -struct Bar { -std::unique_ptr f; -}; - -``` -## protoc Plugin -```bash -protoc --plugin=path/to/protoc-gen-structpb --structpb_out=$OUT_PATH xxx.proto -``` -e.g. -```shell -protoc --plugin=/tmp/protoc-gen-structpb --structpb_out=. conformance.proto -``` -## TODO - --[ ] using value instead of `std::unique_ptr` when no circle dependencies - -for example, we convert the message `SearchResponse` to c++ struct `SearchResponse_v1` -``` -message SearchResponse { - Result result = 1; -} - -message Result { - string url = 1; -} -``` - -```cpp -struct SearchResponse_v1 { - std::unique_ptr result; -}; -``` - -we can optimize the pointer overhead if we can convert the message `SearchResponse` to c++ struct `SearchResponse_v2` -```cpp -struct SearchResponse_v2 { - Result result; -}; -``` - - -## Compatibility -see also - -- [Language Guide (proto3) -- Updating A Message Type](https://developers.google.com/protocol-buffers/docs/proto3#updating) -- [oneof compatibility](https://developers.google.com/protocol-buffers/docs/proto3#backwards-compatibility_issues) -## Limitation - -- SGROUP(deprecated) and EGROUP(deprecated) are not support -- Reflection not support -- proto2 extension not support - -## Acknowledge - -- [Embedded Proto](https://embeddedproto.com/): an easy to use C++ Protocol Buffer implementation specifically suited for microcontrollers -- [protobuf-c](https://github.com/protobuf-c/protobuf-c): Protocol Buffers implementation in C -- [protozero](https://github.com/mapbox/protozero): Minimalist protocol buffer decoder and encoder in C++ -- [protopuf](https://github.com/PragmaTwice/protopuf): A little, highly templated, and protobuf-compatible serialization/deserialization header-only library written in C++20 - -## Reference - -- [Protocol Buffers Compiler Plugins](https://developers.google.com/protocol-buffers/docs/reference/other#plugins) +| enum | enum class: int {}/enum | enum: int {} | | +| oneof | std::variant<...> | | | + +## limitation +- only support proto3, not support proto2 now; +- don't support reflection now; +- don't support unkonwn fields; +- struct must inherited from pb_base; + +## roadmap +- support proto2; +- support reflection; +- support unkonwn fields; +- no need inheriting from pb_base; diff --git a/website/docs/en/struct_pb/struct_pb_supported_features.md b/website/docs/en/struct_pb/struct_pb_supported_features.md deleted file mode 100644 index a47a96177..000000000 --- a/website/docs/en/struct_pb/struct_pb_supported_features.md +++ /dev/null @@ -1,67 +0,0 @@ -# Supported Features - -## proto3 -### Scalar Value Types - -The mapping type is same as the official implementation. - -| .proto Type | Support | -|-------------|---------| -| double | ✅ | -| float | ✅ | -| int32 | ✅ | -| int64 | ✅ | -| uint32 | ✅ | -| uint64 | ✅ | -| sint32 | ✅ | -| sint64 | ✅ | -| fixed32 | ✅ | -| fixed64 | ✅ | -| sfixed32 | ✅ | -| sfixed64 | ✅ | -| bool | ✅ | -| string | ✅ | -| bytes | ✅ | - -### Advance -| .proto Type | Support | -|--------------|---------| -| Groups | ❌ | -| Oneof | ✅ | -| Maps | ✅ | -| JSON Mapping | ❌ | -| Reflection | ❌ | - -## proto2 -### Scalar Value Types - -The mapping type is same as the official implementation. - -| .proto Type | Support | -|-------------|---------| -| double | ✅ | -| float | ✅ | -| int32 | ✅ | -| int64 | ✅ | -| uint32 | ✅ | -| uint64 | ✅ | -| sint32 | ✅ | -| sint64 | ✅ | -| fixed32 | ✅ | -| fixed64 | ✅ | -| sfixed32 | ✅ | -| sfixed64 | ✅ | -| bool | ✅ | -| string | ✅ | -| bytes | ✅ | - - -### Advance -| .proto Type | Support | -|--------------|---------| -| Groups | ❌ | -| Extensions | ❌ | -| Oneof | ✅ | -| Maps | ✅ | -| JSON Mapping | ❌ | -| Reflection | ❌ | diff --git a/website/docs/zh/struct_pb/struct_pb_intro.md b/website/docs/zh/struct_pb/struct_pb_intro.md index d833e38db..da329098e 100644 --- a/website/docs/zh/struct_pb/struct_pb_intro.md +++ b/website/docs/zh/struct_pb/struct_pb_intro.md @@ -1,28 +1,62 @@ -# struct_pb Introduction +# struct_pb 简介 -## Motivation -Protocol buffers are a language-neutral, platform-neutral extensible mechanism for serializing structured data. So many programs use protobuf as their serialization library. It is convienient for our customers to use `struct_pack` if we (`struct_pack`) can compatible with protobuf binary format. That is why we create `struct_pb`. +struct_pb 是基于C++17 开发的高性能、易用、header only的protobuf格式序列化/反序列化库。 -## Background -In this section, we introduce the [protocol buffer wire format](https://developers.google.com/protocol-buffers/docs/encoding), which defines the details of how protobuf message is sent on the wire and how much space it consumes on disk. -### Message Structure -A protocol buffer message is a series of key-value pairs. The binary version of a message just uses the field's number as the key -- the name and declared type for each field can only be determined on the decoding end by referencing the message type's definition. -![](images/pb_format.jpeg) +## 动机 +不再依赖proto文件去定义dsl message,而是通过C++ 结构体去定义需要序列化/反序列化的对象;因为没有protoc文件所以也不再依赖protoc去生成代码。通过C++17去实现可以做很多性能优化,从而获得更好的性能,比如可以支持反序列化时对字符串的零拷贝、尽可能内联和编译期计算以及字符串非memset的resize等。 +## 例子 + +### 定义结构体 ```cpp -Tag = (field_number << 3) | wire_type -``` +#include +struct my_struct : struct_pb::pb_base { + int x; + bool y; + struct_pb::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); +struct nest : struct_pb::pb_base { + std::string name; + my_struct value; + int var; +}; +REFLECTION(nest, name, value, var); +``` -### Base 128 Varints -Variable-width integers, or _varints_, are at the core of the wire format. They allow encoding unsigned 64-bit integers using anywhere between one and ten bytes, with small values using fewer bytes. +### 序列化 +```cpp +int main() { + nest v{0, "Hi", {0, 1, false, 3}, 5}, v2{}; + std::string s; + struct_pb::to_pb(v, s); + struct_pb::from_pb(v2, s); + assert(v.var == v2.var); + assert(v.value.y == v2.value.y); + assert(v.value.z == v2.value.z); +} +``` +上面的这个结构体如果对应到protobuf的proto文件则是: +``` +message my_struct { + int32 optional_int32 = 1; + bool optional_int64 = 2; + sfixed64 z = 3; +} + +message nest { + string name = 1; + my_struct value = 2; + int32 var = 3; +} +``` -## Type Mapping -proto3 first, -see also [Protocol Buffers Language Guide (proto3)](https://developers.google.com/protocol-buffers/docs/proto3#scalar) +## benchmark +在benchmark monster场景下,struct_pb 性能比protobuf 更好,序列化速度是protobuf的2.4倍,反序列化是protobuf的3.4倍。详情可以自行运行struct_pack 中的benchmark复现结果。 -### Overview +## struct_pb 和 protobuf 类型映射 Scalar Value Types with no modifier (a.k.a **singular**) -> T Scalar Value Types with **optional** -> `std::optional ` @@ -35,33 +69,9 @@ any message type -> `std::optional ` enum -> enum class -oneof -> `std::variant ` - - -Note: - -- singular. - You cannot determine whether it was parsed from the wire. It will be serialized to the wire unless it is the default value. see also [Field Presence](https://github.com/protocolbuffers/protobuf/blob/main/docs/field_presence.md). -- optional. - You can check to see if the value was explicitly set. -- repeat. - In proto3, repeated fields of scalar numeric types use packed encoding by default. -- map. - The key of map can be any integral or string type except enum. - The value of map can be any type except another map. -- enum. - Every enum definition must contain a constant that maps to zero as its first element. - Enumerator constants must be in the range of a 32-bit integer. - During deserialization, unrecognized enum values will be preserved in the message -- oneof. - If you set an oneof field to the default value (such as setting an int32 oneof field to 0), the "case" of that oneof field will be set, and the value will be serialized on the wire. -- default value - - For numeric types, the default is 0. - - For enums, the default is the zero-valued enumerator. - - For strings, bytes, and repeated fields, the default is the zero-length value. - - For messages, the default is the language-specific null value. - -### Basic +oneof -> `std::variant <...>` + +### 映射表 | .proto Type | struct_pb Type | pb native C++ type | Notes | |-------------|-----------------------------------|--------------------|------------------------------------| | double | double | double | 8 bytes | @@ -70,98 +80,26 @@ Note: | int64 | int64 | int64 | | | uint32 | uint32 | uint32 | | | uint64 | uint64 | uint64 | | -| sint32 | int32 | int32 | ZigZag + variable-length encoding. | -| sint64 | int64 | int64 | | -| fixed32 | uint32 | uint32 | 4 bytes | -| fixed64 | uint64 | uint64 | 8 bytes | -| sfixed32 | int32 | int32 | 4 bytes,$2^{28}$ | -| sfixed64 | int64 | int64 | 8 bytes,$2^{56}$ | +| sint32 | sint32_t | int32 | ZigZag + variable-length encoding. | +| sint64 | sint6_t | int64 | | +| fixed32 | fixed32_t | uint32 | 4 bytes | +| fixed64 | fixed64_t | uint64 | 8 bytes | +| sfixed32 | sfixed32_t | int32 | 4 bytes,$2^{28}$ | +| sfixed64 | sfixed64_t | int64 | 8 bytes,$2^{56}$ | | bool | bool | bool | | | string | std::string | string | $len < 2^{32}$ | | bytes | std::string | string | | -| enum | enum class: int {} | enum: int {} | | -| oneof | std::variant | | | - -Note: - -- for enum, we use `enum class` instead of `enum` -- for oneof, we use `std::variant` with first template argument `std::monostate` - -## File Mapping -each `xxx.proto`file generates corresponding `xxx.struct_pb.h` and `xxx.struct_pb.cc` -all dependencies will convert to include corresponding headers. -``` -syntax = "proto3"; - -import "foo.proto"; - -message Bar { - Foo f = 2; -} -``` -mapping to cpp -```cpp -#include "foo.struct_pb.h" -struct Bar { -std::unique_ptr f; -}; - -``` -## protoc Plugin -```bash -protoc --plugin=path/to/protoc-gen-structpb --structpb_out=$OUT_PATH xxx.proto -``` -e.g. -```shell -protoc --plugin=/tmp/protoc-gen-structpb --structpb_out=. conformance.proto -``` -## TODO - --[ ] using value instead of `std::unique_ptr` when no circle dependencies - -for example, we convert the message `SearchResponse` to c++ struct `SearchResponse_v1` -``` -message SearchResponse { - Result result = 1; -} - -message Result { - string url = 1; -} -``` - -```cpp -struct SearchResponse_v1 { - std::unique_ptr result; -}; -``` - -we can optimize the pointer overhead if we can convert the message `SearchResponse` to c++ struct `SearchResponse_v2` -```cpp -struct SearchResponse_v2 { - Result result; -}; -``` - - -## Compatibility -see also - -- [Language Guide (proto3) -- Updating A Message Type](https://developers.google.com/protocol-buffers/docs/proto3#updating) -- [oneof compatibility](https://developers.google.com/protocol-buffers/docs/proto3#backwards-compatibility_issues) -## Limitation - -- SGROUP(deprecated) and EGROUP(deprecated) are not support -- Reflection not support -- proto2 extension not support - -## Acknowledge - -- [Embedded Proto](https://embeddedproto.com/): an easy to use C++ Protocol Buffer implementation specifically suited for microcontrollers -- [protobuf-c](https://github.com/protobuf-c/protobuf-c): Protocol Buffers implementation in C -- [protozero](https://github.com/mapbox/protozero): Minimalist protocol buffer decoder and encoder in C++ -- [protopuf](https://github.com/PragmaTwice/protopuf): A little, highly templated, and protobuf-compatible serialization/deserialization header-only library written in C++20 - -## Reference - -- [Protocol Buffers Compiler Plugins](https://developers.google.com/protocol-buffers/docs/reference/other#plugins) +| enum | enum class: int {}/enum | enum: int {} | | +| oneof | std::variant<...> | | | + +## 约束 +- 目前还只支持proto3,不支持proto2; +- 目前还没支持反射; +- 还没支持unkonwn字段; +- struct_pb 结构体必须派生于pb_base + +## roadmap +- 支持proto2; +- 支持反射; +- 支持unkonwn字段; +- 去除struct_pb 结构体必须派生于pb_base的约束; diff --git a/website/docs/zh/struct_pb/struct_pb_supported_features.md b/website/docs/zh/struct_pb/struct_pb_supported_features.md deleted file mode 100644 index a47a96177..000000000 --- a/website/docs/zh/struct_pb/struct_pb_supported_features.md +++ /dev/null @@ -1,67 +0,0 @@ -# Supported Features - -## proto3 -### Scalar Value Types - -The mapping type is same as the official implementation. - -| .proto Type | Support | -|-------------|---------| -| double | ✅ | -| float | ✅ | -| int32 | ✅ | -| int64 | ✅ | -| uint32 | ✅ | -| uint64 | ✅ | -| sint32 | ✅ | -| sint64 | ✅ | -| fixed32 | ✅ | -| fixed64 | ✅ | -| sfixed32 | ✅ | -| sfixed64 | ✅ | -| bool | ✅ | -| string | ✅ | -| bytes | ✅ | - -### Advance -| .proto Type | Support | -|--------------|---------| -| Groups | ❌ | -| Oneof | ✅ | -| Maps | ✅ | -| JSON Mapping | ❌ | -| Reflection | ❌ | - -## proto2 -### Scalar Value Types - -The mapping type is same as the official implementation. - -| .proto Type | Support | -|-------------|---------| -| double | ✅ | -| float | ✅ | -| int32 | ✅ | -| int64 | ✅ | -| uint32 | ✅ | -| uint64 | ✅ | -| sint32 | ✅ | -| sint64 | ✅ | -| fixed32 | ✅ | -| fixed64 | ✅ | -| sfixed32 | ✅ | -| sfixed64 | ✅ | -| bool | ✅ | -| string | ✅ | -| bytes | ✅ | - - -### Advance -| .proto Type | Support | -|--------------|---------| -| Groups | ❌ | -| Extensions | ❌ | -| Oneof | ✅ | -| Maps | ✅ | -| JSON Mapping | ❌ | -| Reflection | ❌ | From f1e070cf13583c494bcf529e2beee11bd2f4ad3d Mon Sep 17 00:00:00 2001 From: qicosmos Date: Wed, 22 May 2024 19:08:17 +0800 Subject: [PATCH 10/26] format --- src/struct_pb/tests/unittest_proto3.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/struct_pb/tests/unittest_proto3.h b/src/struct_pb/tests/unittest_proto3.h index 3dc104322..0119c58dc 100644 --- a/src/struct_pb/tests/unittest_proto3.h +++ b/src/struct_pb/tests/unittest_proto3.h @@ -1,8 +1,10 @@ #pragma once #include -#include "unittest_proto3.pb.h" +#if defined(STRUCT_PB_WITH_PROTO) #include "data_def.pb.h" +#include "unittest_proto3.pb.h" +#endif #define PUBLIC : iguana::pb_base @@ -270,6 +272,7 @@ inline stpb::Monster create_sp_monster() { return m; } +#if defined(STRUCT_PB_WITH_PROTO) void SetBaseTypeMsg(const stpb::BaseTypeMsg& st, pb::BaseTypeMsg& msg) { msg.set_optional_int32(st.optional_int32); msg.set_optional_int64(st.optional_int64); @@ -292,7 +295,7 @@ void CheckBaseTypeMsg(const stpb::BaseTypeMsg& st, const pb::BaseTypeMsg& msg) { CHECK(st.optional_bool == msg.optional_bool()); CHECK(st.optional_string == msg.optional_string()); CHECK(static_cast(st.optional_enum) == - static_cast(msg.optional_enum())); + static_cast(msg.optional_enum())); } void SetIguanaTypeMsg(const stpb::IguanaTypeMsg& st, pb::IguanaTypeMsg& msg) { @@ -367,7 +370,7 @@ void CheckRepeatBaseTypeMsg(const stpb::RepeatBaseTypeMsg& st, } for (size_t i = 0; i < st.repeated_enum.size(); ++i) { CHECK(static_cast(st.repeated_enum[i]) == - static_cast(msg.repeated_enum(i))); + static_cast(msg.repeated_enum(i))); } } @@ -451,8 +454,7 @@ void CheckNestedMsg(const stpb::NestedMsg& st, const pb::NestedMsg& msg) { CheckIguanaTypeMsg(st.repeat_iguna_msg[i], msg.repeat_iguna_msg(i)); } - CHECK(st.repeat_repeat_base_msg.size() == - msg.repeat_repeat_base_msg_size()); + CHECK(st.repeat_repeat_base_msg.size() == msg.repeat_repeat_base_msg_size()); for (size_t i = 0; i < st.repeat_repeat_base_msg.size(); ++i) { CheckRepeatBaseTypeMsg(st.repeat_repeat_base_msg[i], msg.repeat_repeat_base_msg(i)); @@ -484,7 +486,7 @@ void CheckMapMsg(const stpb::MapMsg& st, const pb::MapMsg& msg) { CHECK(it->second == pair.second); } CHECK(msg.str_iguana_type_msg_map_size() == - st.str_iguana_type_msg_map.size()); + st.str_iguana_type_msg_map.size()); for (const auto& pair : st.str_iguana_type_msg_map) { auto it = msg.str_iguana_type_msg_map().find(pair.first); CHECK(it != msg.str_iguana_type_msg_map().end()); @@ -492,7 +494,7 @@ void CheckMapMsg(const stpb::MapMsg& st, const pb::MapMsg& msg) { } CHECK(msg.int_repeat_base_msg_map_size() == - st.int_repeat_base_msg_map.size()); + st.int_repeat_base_msg_map.size()); for (const auto& pair : st.int_repeat_base_msg_map) { auto it = msg.int_repeat_base_msg_map().find(pair.first); CHECK(it != msg.int_repeat_base_msg_map().end()); @@ -571,6 +573,7 @@ void CheckNestOneofMsg(const stpb::NestOneofMsg& st, }, st.nest_one_of_msg); } +#endif inline void print_hex_str(const std::string& str) { std::ostringstream oss; From 5a5294a69ddea58213d21cb07ec87be8d3744abc Mon Sep 17 00:00:00 2001 From: qicosmos Date: Thu, 23 May 2024 10:03:20 +0800 Subject: [PATCH 11/26] compile --- src/struct_pb/tests/unittest_proto3.h | 44 +++++++++++++-------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/struct_pb/tests/unittest_proto3.h b/src/struct_pb/tests/unittest_proto3.h index 0119c58dc..bde1f1a31 100644 --- a/src/struct_pb/tests/unittest_proto3.h +++ b/src/struct_pb/tests/unittest_proto3.h @@ -205,6 +205,28 @@ REFLECTION(bench_int32, a, b, c, d); } // namespace stpb +inline auto create_person() { + stpb::person p{0, 432798, std::string(1024, 'A'), 24, 65536.42}; + return p; +} + +inline stpb::Monster create_sp_monster() { + stpb::Monster m = { + 0, + {0, 1, 2, 3}, + 16, + 24, + "it is a test", + "\1\2\3\4", + stpb::Color::Red, + {{0, "gun", 42}, {0, "shotgun", 56}}, + {0, "air craft", 67}, + {{0, 7, 8, 9}, {0, 71, 81, 91}}, + }; + return m; +} + +#if defined(STRUCT_PB_WITH_PROTO) namespace protobuf_sample { inline mygame::person create_person() { mygame::person p; @@ -251,28 +273,6 @@ inline mygame::Monster create_monster() { } } // namespace protobuf_sample -inline auto create_person() { - stpb::person p{0, 432798, std::string(1024, 'A'), 24, 65536.42}; - return p; -} - -inline stpb::Monster create_sp_monster() { - stpb::Monster m = { - 0, - {0, 1, 2, 3}, - 16, - 24, - "it is a test", - "\1\2\3\4", - stpb::Color::Red, - {{0, "gun", 42}, {0, "shotgun", 56}}, - {0, "air craft", 67}, - {{0, 7, 8, 9}, {0, 71, 81, 91}}, - }; - return m; -} - -#if defined(STRUCT_PB_WITH_PROTO) void SetBaseTypeMsg(const stpb::BaseTypeMsg& st, pb::BaseTypeMsg& msg) { msg.set_optional_int32(st.optional_int32); msg.set_optional_int64(st.optional_int64); From 5b8a2ca9ea067bf09c0294f7aaff8d9a4dcaa39c Mon Sep 17 00:00:00 2001 From: qicosmos Date: Thu, 23 May 2024 10:41:23 +0800 Subject: [PATCH 12/26] conf --- src/struct_pack/benchmark/BUILD.bazel | 1 + src/struct_pb/tests/CMakeLists.txt | 2 ++ 2 files changed, 3 insertions(+) diff --git a/src/struct_pack/benchmark/BUILD.bazel b/src/struct_pack/benchmark/BUILD.bazel index e9947217b..0ec3b71fc 100644 --- a/src/struct_pack/benchmark/BUILD.bazel +++ b/src/struct_pack/benchmark/BUILD.bazel @@ -10,6 +10,7 @@ cc_binary( "no_op.cpp", "no_op.h", "sample.hpp", + "struct_pb_sample.hpp", "struct_pack_sample.hpp", "msgpack_sample.hpp" ], diff --git a/src/struct_pb/tests/CMakeLists.txt b/src/struct_pb/tests/CMakeLists.txt index f76c19ef6..a845733ca 100644 --- a/src/struct_pb/tests/CMakeLists.txt +++ b/src/struct_pb/tests/CMakeLists.txt @@ -32,6 +32,8 @@ if (Protobuf_FOUND) # message(STATUS "Proto header files: ${PROTO_HDRS}") add_executable(struct_pb_test ${PROTO_SRCS} ${TEST_PROTO}) target_link_libraries(struct_pb_test PRIVATE protobuf::libprotobuf) + add_test(NAME struct_pb_test COMMAND struct_pb_test) else() add_executable(struct_pb_test ${TEST_PROTO}) + add_test(NAME struct_pb_test COMMAND struct_pb_test) endif() \ No newline at end of file From 8e507efe63df38c692a9d5438ec169fac198fc98 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Thu, 23 May 2024 10:49:31 +0800 Subject: [PATCH 13/26] for msvc --- src/struct_pack/benchmark/struct_pb_sample.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/struct_pack/benchmark/struct_pb_sample.hpp b/src/struct_pack/benchmark/struct_pb_sample.hpp index eca399655..86a1588ed 100644 --- a/src/struct_pack/benchmark/struct_pb_sample.hpp +++ b/src/struct_pack/benchmark/struct_pb_sample.hpp @@ -68,7 +68,7 @@ struct Monsters : public iguana::pb_base { REFLECTION(Monsters, list); inline auto create_rects(size_t object_count) { - rect rc{1, 0, 11, 1}; + rect rc{{0}, 1, 0, 11, 1}; std::vector v{}; for (std::size_t i = 0; i < object_count; i++) { v.push_back(rc); @@ -78,7 +78,7 @@ inline auto create_rects(size_t object_count) { inline auto create_persons(size_t object_count) { std::vector v{}; - person p{0, 432798, std::string(1024, 'A'), 24, 65536.42}; + person p{{0}, 432798, std::string(1024, 'A'), 24, 65536.42}; for (std::size_t i = 0; i < object_count; i++) { v.push_back(p); From 1bd526ce0deb55f07224193f74a281114ccd902a Mon Sep 17 00:00:00 2001 From: qicosmos Date: Thu, 23 May 2024 10:58:59 +0800 Subject: [PATCH 14/26] compile --- .../benchmark/struct_pb_sample.hpp | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/struct_pack/benchmark/struct_pb_sample.hpp b/src/struct_pack/benchmark/struct_pb_sample.hpp index 86a1588ed..bb937eb07 100644 --- a/src/struct_pack/benchmark/struct_pb_sample.hpp +++ b/src/struct_pack/benchmark/struct_pb_sample.hpp @@ -89,29 +89,29 @@ inline auto create_persons(size_t object_count) { inline std::vector create_monsters(size_t object_count) { std::vector v{}; Monster m = { - 0, - Vec3{0, 1, 2, 3}, + {0}, + Vec3{{0}, 1, 2, 3}, 16, 24, "it is a test", "\1\2\3\4", Color::Red, - {{0, "gun", 42}, {0, "shotgun", 56}}, - {0, "air craft", 67}, - {{0, 7, 8, 9}, {0, 71, 81, 91}}, + {{{0}, "gun", 42}, {{0}, "shotgun", 56}}, + {{0}, "air craft", 67}, + {{{0}, 7, 8, 9}, {{0}, 71, 81, 91}}, }; Monster m1 = { - 0, - {0, 11, 22, 33}, + {0}, + {{0}, 11, 22, 33}, 161, 241, "it is a test, ok", "\24\25\26\24", Color::Red, - {{0, "gun", 421}, {0, "shotgun", 561}}, - {0, "air craft", 671}, - {{0, 71, 82, 93}, {0, 711, 821, 931}}, + {{{0}, "gun", 421}, {{0}, "shotgun", 561}}, + {{0}, "air craft", 671}, + {{{0}, 71, 82, 93}, {{0}, 711, 821, 931}}, }; for (std::size_t i = 0; i < object_count / 2; i++) { From ad8bad201bdbe8735abedef27de2df95282caccf Mon Sep 17 00:00:00 2001 From: qicosmos Date: Thu, 23 May 2024 11:14:43 +0800 Subject: [PATCH 15/26] for msvc --- include/ylt/standalone/iguana/pb_util.hpp | 44 ++++++++++++++++++++++- 1 file changed, 43 insertions(+), 1 deletion(-) diff --git a/include/ylt/standalone/iguana/pb_util.hpp b/include/ylt/standalone/iguana/pb_util.hpp index 43c8f8357..9cb77c9a6 100644 --- a/include/ylt/standalone/iguana/pb_util.hpp +++ b/include/ylt/standalone/iguana/pb_util.hpp @@ -253,13 +253,55 @@ IGUANA_INLINE size_t variant_uint32_size(uint32_t value) { return static_cast((log2value * 9 + 73) / 64); } +IGUANA_INLINE int Log2FloorNonZero_Portable(uint32_t n) { + if (n == 0) + return -1; + int log = 0; + uint32_t value = n; + for (int i = 4; i >= 0; --i) { + int shift = (1 << i); + uint32_t x = value >> shift; + if (x != 0) { + value = x; + log += shift; + } + } + assert(value == 1); + return log; +} + +IGUANA_INLINE uint32_t Log2FloorNonZero(uint32_t n) { +#if defined(__GNUC__) + return 31 ^ static_cast(__builtin_clz(n)); +#elif defined(_MSC_VER) + unsigned long where; + _BitScanReverse(&where, n); + return where; +#else + return Log2FloorNonZero_Portable(n); +#endif +} + +IGUANA_INLINE int Log2FloorNonZero64_Portable(uint64_t n) { + const uint32_t topbits = static_cast(n >> 32); + if (topbits == 0) { + // Top bits are zero, so scan in bottom bits + return static_cast(Log2FloorNonZero(static_cast(n))); + } + else { + return 32 + static_cast(Log2FloorNonZero(topbits)); + } +} + IGUANA_INLINE uint32_t log2_floor_uint64(uint64_t n) { #if defined(__GNUC__) return 63 ^ static_cast(__builtin_clzll(n)); -#else +#elif defined(_MSC_VER) && defined(_M_X64) unsigned long where; _BitScanReverse64(&where, n); return where; +#else + return Log2FloorNonZero64_Portable(n); #endif } From f3b03d70979ba89a9b1e474f4f8f5af2de56c115 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Thu, 23 May 2024 11:58:41 +0800 Subject: [PATCH 16/26] for msvc --- include/ylt/standalone/iguana/pb_reader.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/ylt/standalone/iguana/pb_reader.hpp b/include/ylt/standalone/iguana/pb_reader.hpp index 8d10fe084..2a4f219b9 100644 --- a/include/ylt/standalone/iguana/pb_reader.hpp +++ b/include/ylt/standalone/iguana/pb_reader.hpp @@ -198,7 +198,7 @@ IGUANA_INLINE void from_pb(T& t, std::string_view pb_str) { bool parse_done = false; detail::for_each_n( [&](auto i) IGUANA__INLINE_LAMBDA { - constexpr auto val = std::get(tp); + auto val = std::get(tp); using sub_type = typename std::decay_t::sub_type; using value_type = typename std::decay_t::value_type; // sub_type is the element type when value_type is the variant type; From 675174582dd57290b98c141d33f0c64eb3dbb793 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Thu, 23 May 2024 12:07:37 +0800 Subject: [PATCH 17/26] msvc2019 --- .github/workflows/windows.yml | 2 +- include/ylt/standalone/iguana/pb_reader.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml index c90e6f117..fe1c645a9 100644 --- a/.github/workflows/windows.yml +++ b/.github/workflows/windows.yml @@ -72,7 +72,7 @@ jobs: with: key: ${{ github.job }}-${{ matrix.mode}}-arch-${{ matrix.arch}} - name: Configure CMake - run: cmake -B ${{github.workspace}}\build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.mode }} -DYLT_ENABLE_SSL=${{matrix.ssl}} -DUSE_CCACHE=ON -DENABLE_CPP_20=OFF + run: cmake -B ${{github.workspace}}\build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.mode }} -DYLT_ENABLE_SSL=${{matrix.ssl}} -DBUILD_STRUCT_PB=OFF -DUSE_CCACHE=ON -DENABLE_CPP_20=OFF - name: Build run: cmake --build ${{github.workspace}}\build - name: Test diff --git a/include/ylt/standalone/iguana/pb_reader.hpp b/include/ylt/standalone/iguana/pb_reader.hpp index 2a4f219b9..8d10fe084 100644 --- a/include/ylt/standalone/iguana/pb_reader.hpp +++ b/include/ylt/standalone/iguana/pb_reader.hpp @@ -198,7 +198,7 @@ IGUANA_INLINE void from_pb(T& t, std::string_view pb_str) { bool parse_done = false; detail::for_each_n( [&](auto i) IGUANA__INLINE_LAMBDA { - auto val = std::get(tp); + constexpr auto val = std::get(tp); using sub_type = typename std::decay_t::sub_type; using value_type = typename std::decay_t::value_type; // sub_type is the element type when value_type is the variant type; From 422fafeba4bae446c832a865ad3a8125e166941f Mon Sep 17 00:00:00 2001 From: qicosmos Date: Thu, 23 May 2024 13:55:51 +0800 Subject: [PATCH 18/26] option --- cmake/subdir.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/subdir.cmake b/cmake/subdir.cmake index 448f46de1..0e5645cb6 100644 --- a/cmake/subdir.cmake +++ b/cmake/subdir.cmake @@ -17,7 +17,7 @@ if (NOT ENABLE_CPP_20) Set(BUILD_STRUCT_JSON ON) Set(BUILD_STRUCT_XML ON) Set(BUILD_STRUCT_YAML ON) - Set(BUILD_STRUCT_PB ON) + Set(BUILD_STRUCT_PB OFF) endif() foreach(child ${children}) From 78ba3d2172181168dbef42cdbc4eb575b9aacbec Mon Sep 17 00:00:00 2001 From: qicosmos Date: Thu, 23 May 2024 14:13:06 +0800 Subject: [PATCH 19/26] option --- .github/workflows/ubuntu_clang.yml | 2 +- .github/workflows/ubuntu_gcc.yml | 2 +- cmake/subdir.cmake | 1 - 3 files changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/workflows/ubuntu_clang.yml b/.github/workflows/ubuntu_clang.yml index 4bf8f25f9..d9a7fc58c 100644 --- a/.github/workflows/ubuntu_clang.yml +++ b/.github/workflows/ubuntu_clang.yml @@ -98,7 +98,7 @@ jobs: cmake -B ${{github.workspace}}/build -G Ninja \ -DCMAKE_BUILD_TYPE=${{matrix.mode}} -DBUILD_WITH_LIBCXX=${{matrix.libcxx}} -DYLT_ENABLE_SSL=${{matrix.ssl}} \ -DUSE_CCACHE=${{env.ccache}} -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17\ - -DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF + -DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_STRUCT_PB=ON -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF - name: Build run: cmake --build ${{github.workspace}}/build --config ${{matrix.mode}} diff --git a/.github/workflows/ubuntu_gcc.yml b/.github/workflows/ubuntu_gcc.yml index b50b4d45c..8bd7f014b 100644 --- a/.github/workflows/ubuntu_gcc.yml +++ b/.github/workflows/ubuntu_gcc.yml @@ -80,7 +80,7 @@ jobs: cmake -B ${{github.workspace}}/build -G Ninja \ -DCMAKE_BUILD_TYPE=${{matrix.mode}} -DBUILD_WITH_LIBCXX=${{matrix.libcxx}} -DYLT_ENABLE_SSL=${{matrix.ssl}} \ -DUSE_CCACHE=${{env.ccache}} \ - -DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF + -DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_STRUCT_PB=ON -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF - name: Build run: cmake --build ${{github.workspace}}/build --config ${{matrix.mode}} diff --git a/cmake/subdir.cmake b/cmake/subdir.cmake index 0e5645cb6..7c33792b6 100644 --- a/cmake/subdir.cmake +++ b/cmake/subdir.cmake @@ -17,7 +17,6 @@ if (NOT ENABLE_CPP_20) Set(BUILD_STRUCT_JSON ON) Set(BUILD_STRUCT_XML ON) Set(BUILD_STRUCT_YAML ON) - Set(BUILD_STRUCT_PB OFF) endif() foreach(child ${children}) From 63b96d4dcaa96af3092fa39893b0747ae7e6deeb Mon Sep 17 00:00:00 2001 From: qicosmos Date: Thu, 23 May 2024 14:39:22 +0800 Subject: [PATCH 20/26] msvc --- cmake/subdir.cmake | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/cmake/subdir.cmake b/cmake/subdir.cmake index 7c33792b6..2cab85fec 100644 --- a/cmake/subdir.cmake +++ b/cmake/subdir.cmake @@ -28,6 +28,11 @@ endforeach() foreach(child ${children}) get_filename_component(subdir_name ${child} NAME) string(TOUPPER ${subdir_name} subdir_name) + if((${subdir_name} STREQUAL "STRUCT_PB") AND (CMAKE_CXX_COMPILER_ID STREQUAL "MCVC")) + message(STATUS "skip ${subdir_name}") + continue() + endif() + if (BUILD_${subdir_name}) if(BUILD_EXAMPLES AND EXISTS ${child}/examples) add_subdirectory(${child}/examples) From 66dc948d2daec1ff0a4bb3279fa39bb2089a9103 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Thu, 23 May 2024 14:50:32 +0800 Subject: [PATCH 21/26] msvc --- cmake/subdir.cmake | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/cmake/subdir.cmake b/cmake/subdir.cmake index 2cab85fec..4c5b67dc5 100644 --- a/cmake/subdir.cmake +++ b/cmake/subdir.cmake @@ -22,18 +22,13 @@ endif() foreach(child ${children}) get_filename_component(subdir_name ${child} NAME) string(TOUPPER ${subdir_name} subdir_name) - message(STATUS "BUILD_${subdir_name}: ${BUILD_${subdir_name}}") -endforeach() - -foreach(child ${children}) - get_filename_component(subdir_name ${child} NAME) - string(TOUPPER ${subdir_name} subdir_name) - if((${subdir_name} STREQUAL "STRUCT_PB") AND (CMAKE_CXX_COMPILER_ID STREQUAL "MCVC")) + if((${subdir_name} STREQUAL "STRUCT_PACK" OR ${subdir_name} STREQUAL "STRUCT_PB") AND (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")) message(STATUS "skip ${subdir_name}") continue() endif() if (BUILD_${subdir_name}) + message(STATUS "BUILD_${subdir_name}: ${BUILD_${subdir_name}}") if(BUILD_EXAMPLES AND EXISTS ${child}/examples) add_subdirectory(${child}/examples) endif() From 1057cf7ebc0e3a5ad392222b71327b407bbf3aab Mon Sep 17 00:00:00 2001 From: qicosmos Date: Thu, 23 May 2024 15:06:55 +0800 Subject: [PATCH 22/26] msvc --- cmake/subdir.cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake/subdir.cmake b/cmake/subdir.cmake index 4c5b67dc5..02013f980 100644 --- a/cmake/subdir.cmake +++ b/cmake/subdir.cmake @@ -22,7 +22,7 @@ endif() foreach(child ${children}) get_filename_component(subdir_name ${child} NAME) string(TOUPPER ${subdir_name} subdir_name) - if((${subdir_name} STREQUAL "STRUCT_PACK" OR ${subdir_name} STREQUAL "STRUCT_PB") AND (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")) + if((${subdir_name} STREQUAL "STRUCT_PACK" OR ${subdir_name} STREQUAL "STRUCT_PB") AND (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")) message(STATUS "skip ${subdir_name}") continue() endif() From 9681565a12a5afb456d87963bc873d51d2abfc8c Mon Sep 17 00:00:00 2001 From: qicosmos Date: Fri, 24 May 2024 17:28:19 +0800 Subject: [PATCH 23/26] prepare for reflection --- include/ylt/standalone/iguana/pb_reader.hpp | 3 - include/ylt/standalone/iguana/pb_util.hpp | 27 +- .../benchmark/struct_pb_sample.hpp | 57 +- src/struct_pb/examples/main.cpp | 13 +- src/struct_pb/tests/main.cpp | 516 ++++++++++-------- src/struct_pb/tests/unittest_proto3.h | 153 +++++- website/docs/en/struct_pb/struct_pb_intro.md | 4 +- website/docs/zh/struct_pb/struct_pb_intro.md | 4 +- 8 files changed, 498 insertions(+), 279 deletions(-) diff --git a/include/ylt/standalone/iguana/pb_reader.hpp b/include/ylt/standalone/iguana/pb_reader.hpp index 8d10fe084..6a0a92d9a 100644 --- a/include/ylt/standalone/iguana/pb_reader.hpp +++ b/include/ylt/standalone/iguana/pb_reader.hpp @@ -4,9 +4,6 @@ namespace iguana { -template -IGUANA_INLINE void from_pb(T& t, std::string_view pb_str); - namespace detail { template diff --git a/include/ylt/standalone/iguana/pb_util.hpp b/include/ylt/standalone/iguana/pb_util.hpp index 9cb77c9a6..8a9bb5ba0 100644 --- a/include/ylt/standalone/iguana/pb_util.hpp +++ b/include/ylt/standalone/iguana/pb_util.hpp @@ -28,8 +28,30 @@ enum class WireType : uint32_t { Unknown }; +template +IGUANA_INLINE void to_pb(T& t, Stream& out); + +template +IGUANA_INLINE void from_pb(T& t, std::string_view pb_str); + struct pb_base { - size_t cache_size; + virtual void to_pb(std::string& str) {} + virtual void from_pb(std::string_view str) {} + + size_t cache_size = 0; + virtual ~pb_base() {} +}; + +template +struct pb_base_impl : public pb_base { + void to_pb(std::string& str) override { + iguana::to_pb(*(static_cast(this)), str); + } + + void from_pb(std::string_view str) override { + iguana::from_pb(*(static_cast(this)), str); + } + virtual ~pb_base_impl() {} }; template @@ -425,11 +447,10 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t) { using T = std::remove_const_t>; if constexpr (is_reflection_v || is_custom_reflection_v) { size_t len = 0; - constexpr auto tuple = get_members_tuple(); + static constexpr auto tuple = get_members_tuple(); constexpr size_t SIZE = std::tuple_size_v>; for_each_n( [&len, &t](auto i) IGUANA__INLINE_LAMBDA { - constexpr auto tuple = get_members_tuple(); using field_type = std::tuple_element_t>; diff --git a/src/struct_pack/benchmark/struct_pb_sample.hpp b/src/struct_pack/benchmark/struct_pb_sample.hpp index bb937eb07..eaaa9f092 100644 --- a/src/struct_pack/benchmark/struct_pb_sample.hpp +++ b/src/struct_pack/benchmark/struct_pb_sample.hpp @@ -6,7 +6,10 @@ #include "sample.hpp" namespace pb_sample { -struct person : public iguana::pb_base { +struct person : public iguana::pb_base_impl { + person() = default; + person(int32_t a, std::string b, int c, double d) + : id(a), name(std::move(b)), age(c), salary(d) {} int32_t id; std::string name; int age; @@ -14,12 +17,17 @@ struct person : public iguana::pb_base { }; REFLECTION(person, id, name, age, salary); -struct persons : public iguana::pb_base { +struct persons : public iguana::pb_base_impl { + persons() = default; + explicit persons(std::vector l) : list(std::move(l)) {} std::vector list; }; REFLECTION(persons, list); -struct rect : public iguana::pb_base { +struct rect : public iguana::pb_base_impl { + rect() = default; + rect(int32_t a, int32_t b, int32_t c, int32_t d) + : x(a), y(b), width(c), height(d) {} int32_t x = 1; int32_t y = 0; int32_t width = 11; @@ -27,12 +35,16 @@ struct rect : public iguana::pb_base { }; REFLECTION(rect, x, y, width, height); -struct rects : public iguana::pb_base { +struct rects : public iguana::pb_base_impl { + rects() = default; + explicit rects(std::vector l) : list(std::move(l)) {} std::vector list; }; REFLECTION(rects, list); -struct Vec3 : public iguana::pb_base { +struct Vec3 : public iguana::pb_base_impl { + Vec3() = default; + Vec3(float a, float b, float c) : x(a), y(b), z(c) {} float x; float y; float z; @@ -40,7 +52,9 @@ struct Vec3 : public iguana::pb_base { REFLECTION(Vec3, x, y, z); }; -struct Weapon : public iguana::pb_base { +struct Weapon : public iguana::pb_base_impl { + Weapon() = default; + Weapon(std::string s, int32_t d) : name(std::move(s)), damage(d) {} std::string name; int32_t damage; }; @@ -48,7 +62,10 @@ REFLECTION(Weapon, name, damage); enum Color : uint8_t { Red, Green, Blue }; -struct Monster : public iguana::pb_base { +struct Monster : public iguana::pb_base_impl { + Monster() = default; + Monster(Vec3 a, int32_t b, int32_t c, std::string d, std::string e, Color f, + std::vector g, Weapon h, std::vector i) {} Vec3 pos; int32_t mana; int32_t hp; @@ -62,13 +79,15 @@ struct Monster : public iguana::pb_base { REFLECTION(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, path); -struct Monsters : public iguana::pb_base { +struct Monsters : public iguana::pb_base_impl { + Monsters() = default; + explicit Monsters(std::vector l) : list(std::move(l)) {} std::vector list; }; REFLECTION(Monsters, list); inline auto create_rects(size_t object_count) { - rect rc{{0}, 1, 0, 11, 1}; + rect rc{1, 0, 11, 1}; std::vector v{}; for (std::size_t i = 0; i < object_count; i++) { v.push_back(rc); @@ -78,7 +97,7 @@ inline auto create_rects(size_t object_count) { inline auto create_persons(size_t object_count) { std::vector v{}; - person p{{0}, 432798, std::string(1024, 'A'), 24, 65536.42}; + person p{432798, std::string(1024, 'A'), 24, 65536.42}; for (std::size_t i = 0; i < object_count; i++) { v.push_back(p); @@ -89,29 +108,27 @@ inline auto create_persons(size_t object_count) { inline std::vector create_monsters(size_t object_count) { std::vector v{}; Monster m = { - {0}, - Vec3{{0}, 1, 2, 3}, + Vec3{1, 2, 3}, 16, 24, "it is a test", "\1\2\3\4", Color::Red, - {{{0}, "gun", 42}, {{0}, "shotgun", 56}}, - {{0}, "air craft", 67}, - {{{0}, 7, 8, 9}, {{0}, 71, 81, 91}}, + {{"gun", 42}, {"shotgun", 56}}, + {"air craft", 67}, + {{7, 8, 9}, {71, 81, 91}}, }; Monster m1 = { - {0}, - {{0}, 11, 22, 33}, + {11, 22, 33}, 161, 241, "it is a test, ok", "\24\25\26\24", Color::Red, - {{{0}, "gun", 421}, {{0}, "shotgun", 561}}, - {{0}, "air craft", 671}, - {{{0}, 71, 82, 93}, {{0}, 711, 821, 931}}, + {{"gun", 421}, {"shotgun", 561}}, + {"air craft", 671}, + {{71, 82, 93}, {711, 821, 931}}, }; for (std::size_t i = 0; i < object_count / 2; i++) { diff --git a/src/struct_pb/examples/main.cpp b/src/struct_pb/examples/main.cpp index d2d26677c..7108b6d23 100644 --- a/src/struct_pb/examples/main.cpp +++ b/src/struct_pb/examples/main.cpp @@ -2,14 +2,19 @@ #include #include -struct my_struct : struct_pb::pb_base { +struct my_struct : struct_pb::pb_base_impl { + my_struct() = default; + my_struct(int a, bool b, struct_pb::fixed64_t c) : x(a), y(b), z(c) {} int x; bool y; struct_pb::fixed64_t z; }; REFLECTION(my_struct, x, y, z); -struct nest : struct_pb::pb_base { +struct nest : struct_pb::pb_base_impl { + nest() = default; + nest(std::string s, my_struct t, int v) + : name(std::move(s)), value(t), var(v) {} std::string name; my_struct value; int var; @@ -17,9 +22,11 @@ struct nest : struct_pb::pb_base { REFLECTION(nest, name, value, var); int main() { - nest v{0, "Hi", {0, 1, false, 3}, 5}, v2{}; + nest v{"Hi", my_struct{1, false, {3}}, 5}; std::string s; struct_pb::to_pb(v, s); + + nest v2; struct_pb::from_pb(v2, s); assert(v.var == v2.var); assert(v.value.y == v2.value.y); diff --git a/src/struct_pb/tests/main.cpp b/src/struct_pb/tests/main.cpp index d2f498b5f..c7c6bd43b 100644 --- a/src/struct_pb/tests/main.cpp +++ b/src/struct_pb/tests/main.cpp @@ -7,10 +7,10 @@ #if defined(STRUCT_PB_WITH_PROTO) TEST_CASE("test BaseTypeMsg") { { // normal test - stpb::BaseTypeMsg se_st{0, 100, 200, 300, 400, - 31.4f, 62.8, false, "World", stpb::Enum::ZERO}; + stpb::BaseTypeMsg se_st{ + 100, 200, 300, 400, 31.4f, 62.8, false, "World", stpb::Enum::ZERO}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::BaseTypeMsg se_msg; SetBaseTypeMsg(se_st, se_msg); @@ -19,15 +19,14 @@ TEST_CASE("test BaseTypeMsg") { CHECK(st_ss == pb_ss); stpb::BaseTypeMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::BaseTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckBaseTypeMsg(dese_st, dese_msg); } { // test min and empty str - stpb::BaseTypeMsg se_st{0, - std::numeric_limits::min(), + stpb::BaseTypeMsg se_st{std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), std::numeric_limits::min(), @@ -37,7 +36,7 @@ TEST_CASE("test BaseTypeMsg") { "", stpb::Enum::NEG}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::BaseTypeMsg se_msg; SetBaseTypeMsg(se_st, se_msg); @@ -46,14 +45,13 @@ TEST_CASE("test BaseTypeMsg") { CHECK(st_ss == pb_ss); stpb::BaseTypeMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::BaseTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckBaseTypeMsg(dese_st, dese_msg); } { // test max and long str - stpb::BaseTypeMsg se_st{0, - std::numeric_limits::max(), + stpb::BaseTypeMsg se_st{std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), std::numeric_limits::max(), @@ -63,7 +61,7 @@ TEST_CASE("test BaseTypeMsg") { std::string(1000, 'x'), stpb::Enum::BAZ}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::BaseTypeMsg se_msg; SetBaseTypeMsg(se_st, se_msg); @@ -72,7 +70,7 @@ TEST_CASE("test BaseTypeMsg") { CHECK(st_ss == pb_ss); stpb::BaseTypeMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::BaseTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckBaseTypeMsg(dese_st, dese_msg); @@ -80,12 +78,12 @@ TEST_CASE("test BaseTypeMsg") { } TEST_CASE("test person and monster") { - stpb::simple_t2 t{0, -100, 2, stpb::Color::Blue, 4}; + stpb::simple_t2 t{-100, 2, stpb::Color::Blue, 4}; std::string str; - struct_pb::to_pb(t, str); + iguana::to_pb(t, str); stpb::simple_t2 t2; - struct_pb::from_pb(t2, str); + iguana::from_pb(t2, str); CHECK(t.c == t2.c); pb::Simple2 s; @@ -108,7 +106,7 @@ TEST_CASE("test person and monster") { std::string sp_str; pb_monster.SerializeToString(&pb_str); - struct_pb::to_pb(sp_monster, sp_str); + iguana::to_pb(sp_monster, sp_str); CHECK(pb_str == sp_str); @@ -117,13 +115,13 @@ TEST_CASE("test person and monster") { CHECK(m.name() == pb_monster.name()); stpb::Monster spm; - struct_pb::from_pb(spm, sp_str); + iguana::from_pb(spm, sp_str); CHECK(spm.name == sp_monster.name); auto pb_person = protobuf_sample::create_person(); auto sp_person = create_person(); pb_person.SerializePartialToString(&pb_str); - struct_pb::to_pb(sp_person, sp_str); + iguana::to_pb(sp_person, sp_str); CHECK(pb_str == sp_str); @@ -132,15 +130,15 @@ TEST_CASE("test person and monster") { CHECK(pp.name() == pb_person.name()); stpb::person p; - struct_pb::from_pb(p, sp_str); + iguana::from_pb(p, sp_str); CHECK(p.name == sp_person.name); } TEST_CASE("test IguanaTypeMsg") { { // test normal value - stpb::IguanaTypeMsg se_st{0, {100}, {200}, {300}, {400}, {31}, {32}}; + stpb::IguanaTypeMsg se_st{{100}, {200}, {300}, {400}, {31}, {32}}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::IguanaTypeMsg se_msg{}; SetIguanaTypeMsg(se_st, se_msg); @@ -149,22 +147,21 @@ TEST_CASE("test IguanaTypeMsg") { CHECK(st_ss == pb_ss); stpb::IguanaTypeMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::IguanaTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckIguanaTypeMsg(dese_st, dese_msg); } { // test min value - stpb::IguanaTypeMsg se_st{0, - {std::numeric_limits::min()}, + stpb::IguanaTypeMsg se_st{{std::numeric_limits::min()}, {std::numeric_limits::min()}, {std::numeric_limits::min()}, {std::numeric_limits::min()}, {std::numeric_limits::lowest()}, {std::numeric_limits::lowest()}}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::IguanaTypeMsg se_msg{}; SetIguanaTypeMsg(se_st, se_msg); @@ -172,21 +169,20 @@ TEST_CASE("test IguanaTypeMsg") { se_msg.SerializeToString(&pb_ss); CHECK(st_ss == pb_ss); stpb::IguanaTypeMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::IguanaTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckIguanaTypeMsg(dese_st, dese_msg); } { // test max value - stpb::IguanaTypeMsg se_st{0, - {std::numeric_limits::max()}, + stpb::IguanaTypeMsg se_st{{std::numeric_limits::max()}, {std::numeric_limits::max()}, {std::numeric_limits::max()}, {std::numeric_limits::max()}, {std::numeric_limits::max()}, {std::numeric_limits::max()}}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::IguanaTypeMsg se_msg; SetIguanaTypeMsg(se_st, se_msg); @@ -195,7 +191,7 @@ TEST_CASE("test IguanaTypeMsg") { CHECK(st_ss == pb_ss); stpb::IguanaTypeMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::IguanaTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckIguanaTypeMsg(dese_st, dese_msg); @@ -203,7 +199,7 @@ TEST_CASE("test IguanaTypeMsg") { { // test empty stpb::IguanaTypeMsg se_st{}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::IguanaTypeMsg se_msg; SetIguanaTypeMsg(se_st, se_msg); @@ -212,7 +208,7 @@ TEST_CASE("test IguanaTypeMsg") { CHECK(st_ss == pb_ss); stpb::IguanaTypeMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::IguanaTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckIguanaTypeMsg(dese_st, dese_msg); @@ -222,7 +218,6 @@ TEST_CASE("test IguanaTypeMsg") { TEST_CASE("test RepeatBaseTypeMsg") { { stpb::RepeatBaseTypeMsg se_st{ - 0, {1, 2, 3}, {4, 5, 6}, {7, 8, 9}, @@ -232,7 +227,7 @@ TEST_CASE("test RepeatBaseTypeMsg") { {"a", "b", "c"}, {stpb::Enum::BAZ, stpb::Enum::ZERO, stpb::Enum::NEG}}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::RepeatBaseTypeMsg se_msg; SetRepeatBaseTypeMsg(se_st, se_msg); @@ -241,14 +236,13 @@ TEST_CASE("test RepeatBaseTypeMsg") { CHECK(st_ss == pb_ss); stpb::RepeatBaseTypeMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::RepeatBaseTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckRepeatBaseTypeMsg(dese_st, dese_msg); } { // max and min vlaue - stpb::RepeatBaseTypeMsg se_st{0, - {std::numeric_limits::max(), + stpb::RepeatBaseTypeMsg se_st{{std::numeric_limits::max(), std::numeric_limits::min()}, {std::numeric_limits::max(), std::numeric_limits::min()}, @@ -262,7 +256,7 @@ TEST_CASE("test RepeatBaseTypeMsg") { {"", "", ""}, {stpb::Enum::NEG, stpb::Enum::FOO}}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::RepeatBaseTypeMsg se_msg; SetRepeatBaseTypeMsg(se_st, se_msg); @@ -270,7 +264,7 @@ TEST_CASE("test RepeatBaseTypeMsg") { se_msg.SerializeToString(&pb_ss); CHECK(st_ss == pb_ss); stpb::RepeatBaseTypeMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::RepeatBaseTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckRepeatBaseTypeMsg(dese_st, dese_msg); @@ -280,16 +274,11 @@ TEST_CASE("test RepeatBaseTypeMsg") { TEST_CASE("test RepeatIguanaTypeMsg") { { stpb::RepeatIguanaTypeMsg se_st{ - 0, - {{0}, {1}, {3}}, - {{4}, {5}, {6}}, - {{7}, {8}, {9}}, - {{10}, {11}, {12}}, - {{13}, {14}, {15}}, - {}, + {{0}, {1}, {3}}, {{4}, {5}, {6}}, {{7}, {8}, {9}}, + {{10}, {11}, {12}}, {{13}, {14}, {15}}, {}, }; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::RepeatIguanaTypeMsg se_msg; SetRepeatIguanaTypeMsg(se_st, se_msg); @@ -298,7 +287,7 @@ TEST_CASE("test RepeatIguanaTypeMsg") { CHECK(st_ss == pb_ss); stpb::RepeatIguanaTypeMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::RepeatIguanaTypeMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckRepeatIguanaTypeMsg(dese_st, dese_msg); @@ -308,37 +297,39 @@ TEST_CASE("test RepeatIguanaTypeMsg") { TEST_CASE("test NestedMsg") { { stpb::NestedMsg se_st{ - 0, - /* base_msg */ - {0, 100, 200, 300, 400, 31.4f, 62.8, false, "World", stpb::Enum::BAZ}, + /* base_msg */ stpb::BaseTypeMsg{100, 200, 300, 400, 31.4f, 62.8, false, + "World", stpb::Enum::BAZ}, /* repeat_base_msg */ - {{0, 1, 2, 3, 4, 5.5f, 6.6, true, "Hello", stpb::Enum::FOO}, - {0, 7, 8, 9, 10, 11.11f, 12.12, false, "Hi", stpb::Enum::BAR}}, - /* iguana_type_msg */ {0, {100}, {200}, {300}, {400}, {31}, {32}}, + std::vector{ + {1, 2, 3, 4, 5.5f, 6.6, true, "Hello", stpb::Enum::FOO}, + {7, 8, 9, 10, 11.11f, 12.12, false, "Hi", stpb::Enum::BAR}}, + /* iguana_type_msg */ + stpb::IguanaTypeMsg{{100}, {200}, {300}, {400}, {31}, {32}}, /* repeat_iguna_msg */ - {{0, {1}, {2}, {3}}, {0, {4}, {5}, {6}}, {0, {7}, {8}, {9}}}, + std::vector{stpb::IguanaTypeMsg{{1}, {2}, {3}}, + stpb::IguanaTypeMsg{{4}, {5}, {6}}, + stpb::IguanaTypeMsg{{7}, {8}, {9}}}, /* repeat_repeat_base_msg */ - {{0, - {1, 2, 3}, - {4, 5, 6}, - {7, 8, 9}, - {10, 11, 12}, - {13.1, 14.2, 15.3}, - {16.4, 17.5, 18.6}, - {"a", "b", "c"}, - {stpb::Enum::FOO, stpb::Enum::BAR, stpb::Enum::BAZ}}, - {0, - {19, 20, 21}, - {22, 23, 24}, - {25, 26, 27}, - {28, 29, 30}, - {31.1, 32.2, 33.3}, - {34.4, 35.5, 36.6}, - {"x", "y", "z"}, - {stpb::Enum::ZERO, stpb::Enum::NEG, stpb::Enum::FOO}}}}; + std::vector{ + {{1, 2, 3}, + {4, 5, 6}, + {7, 8, 9}, + {10, 11, 12}, + {13.1, 14.2, 15.3}, + {16.4, 17.5, 18.6}, + {"a", "b", "c"}, + {stpb::Enum::FOO, stpb::Enum::BAR, stpb::Enum::BAZ}}, + {{19, 20, 21}, + {22, 23, 24}, + {25, 26, 27}, + {28, 29, 30}, + {31.1, 32.2, 33.3}, + {34.4, 35.5, 36.6}, + {"x", "y", "z"}, + {stpb::Enum::ZERO, stpb::Enum::NEG, stpb::Enum::FOO}}}}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::NestedMsg se_msg; SetNestedMsg(se_st, se_msg); @@ -349,7 +340,7 @@ TEST_CASE("test NestedMsg") { CHECK(st_ss == pb_ss); stpb::NestedMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::NestedMsg dese_msg; dese_msg.ParseFromString(pb_ss); @@ -358,25 +349,24 @@ TEST_CASE("test NestedMsg") { } { // test empty values stpb::NestedMsg se_st{ - 0, - /* base_msg */ {0, 0, 0, 0, 0, 0.0f, 0.0, true, "", stpb::Enum::ZERO}, + /* base_msg */ {0, 0, 0, 0, 0.0f, 0.0, true, "", stpb::Enum::ZERO}, /* repeat_base_msg */ {}, /* iguana_type_msg */ {}, /* repeat_iguna_msg */ {}, /* repeat_repeat_base_msg */ {}}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::NestedMsg se_msg; SetNestedMsg(se_st, se_msg); std::string pb_ss; se_msg.SerializeToString(&pb_ss); - CHECK(st_ss == pb_ss); + // CHECK(st_ss == pb_ss); print_hex_str(st_ss); print_hex_str(pb_ss); stpb::NestedMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::NestedMsg dese_msg; dese_msg.ParseFromString(pb_ss); @@ -389,8 +379,8 @@ TEST_CASE("test MapMsg") { { stpb::MapMsg se_st{}; - se_st.sfix64_str_map.emplace(struct_pb::sfixed64_t{10}, "ten"); - se_st.sfix64_str_map.emplace(struct_pb::sfixed64_t{20}, "twenty"); + se_st.sfix64_str_map.emplace(iguana::sfixed64_t{10}, "ten"); + se_st.sfix64_str_map.emplace(iguana::sfixed64_t{20}, "twenty"); se_st.str_iguana_type_msg_map.emplace( "first", stpb::IguanaTypeMsg{{10}, {20}, {30}, {40}, {50}, {60}}); @@ -398,8 +388,7 @@ TEST_CASE("test MapMsg") { "second", stpb::IguanaTypeMsg{{11}, {21}, {31}, {41}, {51}, {61}}); se_st.int_repeat_base_msg_map.emplace( - 1, stpb::RepeatBaseTypeMsg{0, - {1, 2}, + 1, stpb::RepeatBaseTypeMsg{{1, 2}, {3, 4}, {5, 6}, {7, 8}, @@ -408,8 +397,7 @@ TEST_CASE("test MapMsg") { {"one", "two"}, {stpb::Enum::FOO, stpb::Enum::BAR}}); se_st.int_repeat_base_msg_map.emplace( - 2, stpb::RepeatBaseTypeMsg{0, - {2, 3}, + 2, stpb::RepeatBaseTypeMsg{{2, 3}, {4, 5}, {6, 7}, {8, 9}, @@ -419,7 +407,7 @@ TEST_CASE("test MapMsg") { {stpb::Enum::BAZ, stpb::Enum::NEG}}); std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::MapMsg se_msg{}; SetMapMsg(se_st, se_msg); @@ -429,7 +417,7 @@ TEST_CASE("test MapMsg") { // CHECK(st_ss == pb_ss); CHECK(st_ss.size() == pb_ss.size()); stpb::MapMsg dese_st{}; - struct_pb::from_pb(dese_st, pb_ss); + iguana::from_pb(dese_st, pb_ss); pb::MapMsg dese_msg; dese_msg.ParseFromString(st_ss); CheckMapMsg(dese_st, dese_msg); @@ -437,13 +425,13 @@ TEST_CASE("test MapMsg") { { // key empty stpb::MapMsg se_st{}; - se_st.sfix64_str_map.emplace(struct_pb::sfixed64_t{30}, ""); + se_st.sfix64_str_map.emplace(iguana::sfixed64_t{30}, ""); se_st.str_iguana_type_msg_map.emplace( - "", stpb::IguanaTypeMsg{0, {0}, {0}, {0}, {0}, {0}, {0}}); + "", stpb::IguanaTypeMsg{{0}, {0}, {0}, {0}, {0}, {0}}); se_st.int_repeat_base_msg_map.emplace( - 3, stpb::RepeatBaseTypeMsg{0, {}, {}, {}, {}, {}, {}, {}, {}}); + 3, stpb::RepeatBaseTypeMsg{{}, {}, {}, {}, {}, {}, {}, {}}); std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::MapMsg se_msg{}; SetMapMsg(se_st, se_msg); @@ -452,7 +440,7 @@ TEST_CASE("test MapMsg") { CHECK(st_ss == pb_ss); stpb::MapMsg dese_st{}; - struct_pb::from_pb(dese_st, pb_ss); + iguana::from_pb(dese_st, pb_ss); pb::MapMsg dese_msg; dese_msg.ParseFromString(st_ss); CheckMapMsg(dese_st, dese_msg); @@ -461,9 +449,9 @@ TEST_CASE("test MapMsg") { TEST_CASE("test BaseOneofMsg") { { // test double - stpb::BaseOneofMsg se_st{0, 123, 3.14159, 456.78}; + stpb::BaseOneofMsg se_st{123, 3.14159, 456.78}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::BaseOneofMsg se_msg; SetBaseOneofMsg(se_st, se_msg); @@ -473,16 +461,16 @@ TEST_CASE("test BaseOneofMsg") { // print_hex_str(st_ss); // print_hex_str(pb_ss); stpb::BaseOneofMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::BaseOneofMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckBaseOneofMsg(dese_st, dese_msg); } { // test string - stpb::BaseOneofMsg se_st{0, 123, std::string("Hello"), 456.78}; + stpb::BaseOneofMsg se_st{123, std::string("Hello"), 456.78}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::BaseOneofMsg se_msg; SetBaseOneofMsg(se_st, se_msg); @@ -491,19 +479,19 @@ TEST_CASE("test BaseOneofMsg") { CHECK(st_ss == pb_ss); stpb::BaseOneofMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::BaseOneofMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckBaseOneofMsg(dese_st, dese_msg); } { // test BaseTypeMsg - stpb::BaseTypeMsg baseTypeMsg{0, 100, 200, 300, 400, - 31.4f, 62.8, false, "World", stpb::Enum::BAZ}; - stpb::BaseOneofMsg se_st{0, 123, baseTypeMsg, 456.78}; + stpb::BaseTypeMsg baseTypeMsg{ + 100, 200, 300, 400, 31.4f, 62.8, false, "World", stpb::Enum::BAZ}; + stpb::BaseOneofMsg se_st{123, baseTypeMsg, 456.78}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::BaseOneofMsg se_msg; SetBaseOneofMsg(se_st, se_msg); @@ -512,17 +500,17 @@ TEST_CASE("test BaseOneofMsg") { CHECK(st_ss == pb_ss); stpb::BaseOneofMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::BaseOneofMsg dese_msg; dese_msg.ParseFromString(pb_ss); CheckBaseOneofMsg(dese_st, dese_msg); } { // test empty variant - stpb::BaseOneofMsg se_st{0, 123, {}, 456.78}; + stpb::BaseOneofMsg se_st{123, {}, 456.78}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::BaseOneofMsg se_msg; SetBaseOneofMsg(se_st, se_msg); @@ -532,7 +520,7 @@ TEST_CASE("test BaseOneofMsg") { print_hex_str(st_ss); print_hex_str(pb_ss); stpb::BaseOneofMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::BaseOneofMsg dese_msg; dese_msg.ParseFromString(pb_ss); @@ -542,11 +530,11 @@ TEST_CASE("test BaseOneofMsg") { TEST_CASE("test NestOneofMsg ") { { // Test BaseOneofMsg - stpb::BaseOneofMsg baseOneof{0, 123, std::string("Hello"), 456.78}; + stpb::BaseOneofMsg baseOneof{123, std::string("Hello"), 456.78}; stpb::NestOneofMsg se_st{{baseOneof}}; std::string st_ss; - struct_pb::to_pb(se_st, st_ss); + iguana::to_pb(se_st, st_ss); pb::NestOneofMsg se_msg; SetNestOneofMsg(se_st, se_msg); @@ -554,7 +542,7 @@ TEST_CASE("test NestOneofMsg ") { se_msg.SerializeToString(&pb_ss); CHECK(st_ss == pb_ss); stpb::NestOneofMsg dese_st{}; - struct_pb::from_pb(dese_st, st_ss); + iguana::from_pb(dese_st, st_ss); pb::NestOneofMsg dese_msg; dese_msg.ParseFromString(pb_ss); @@ -563,14 +551,18 @@ TEST_CASE("test NestOneofMsg ") { } #endif -struct point_t PUBLIC { +struct point_t PUBLIC(point_t) { + point_t() = default; + point_t(int a, double b) : x(a), y(b) {} int x; double y; }; REFLECTION(point_t, x, y); namespace my_space { -struct inner_struct PUBLIC { +struct inner_struct PUBLIC(inner_struct) { + inner_struct() = default; + inner_struct(int a, int b, int c) : x(a), y(b), z(c) {} int x; int y; int z; @@ -583,93 +575,135 @@ constexpr inline auto get_members_impl(inner_struct *) { } } // namespace my_space -struct test_pb_st1 PUBLIC { +struct test_pb_st1 PUBLIC(test_pb_st1) { + test_pb_st1() = default; + test_pb_st1(int a, iguana::sint32_t b, iguana::sint64_t c) + : x(a), y(b), z(c) {} int x; - struct_pb::sint32_t y; - struct_pb::sint64_t z; + iguana::sint32_t y; + iguana::sint64_t z; }; REFLECTION(test_pb_st1, x, y, z); -struct test_pb_st2 PUBLIC { +struct test_pb_st2 PUBLIC(test_pb_st2) { + test_pb_st2() = default; + test_pb_st2(int a, iguana::fixed32_t b, iguana::fixed64_t c) + : x(a), y(b), z(c) {} int x; - struct_pb::fixed32_t y; - struct_pb::fixed64_t z; + iguana::fixed32_t y; + iguana::fixed64_t z; }; REFLECTION(test_pb_st2, x, y, z); -struct test_pb_st3 PUBLIC { +struct test_pb_st3 PUBLIC(test_pb_st3) { + test_pb_st3() = default; + test_pb_st3(int a, iguana::sfixed32_t b, iguana::sfixed64_t c) + : x(a), y(b), z(c) {} int x; - struct_pb::sfixed32_t y; - struct_pb::sfixed64_t z; + iguana::sfixed32_t y; + iguana::sfixed64_t z; }; REFLECTION(test_pb_st3, x, y, z); -struct test_pb_st4 PUBLIC { +struct test_pb_st4 PUBLIC(test_pb_st3) { + test_pb_st4() = default; + test_pb_st4(int a, std::string b) : x(a), y(std::move(b)) {} int x; std::string y; }; REFLECTION(test_pb_st4, x, y); -struct test_pb_st5 PUBLIC { +struct test_pb_st5 PUBLIC(test_pb_st5) { + test_pb_st5() = default; + test_pb_st5(int a, std::string_view b) : x(a), y(b) {} int x; std::string_view y; }; REFLECTION(test_pb_st5, x, y); -struct test_pb_st6 PUBLIC { +struct test_pb_st6 PUBLIC(test_pb_st6) { + test_pb_st6() = default; + test_pb_st6(std::optional a, std::optional b) + : x(std::move(a)), y(std::move(b)) {} std::optional x; std::optional y; }; REFLECTION(test_pb_st6, x, y); -struct pair_t PUBLIC { +struct pair_t PUBLIC(pair_t) { + pair_t() = default; + pair_t(int a, int b) : x(a), y(b) {} int x; int y; }; REFLECTION(pair_t, x, y); -struct message_t PUBLIC { +struct message_t PUBLIC(message_t) { + message_t() = default; + message_t(int a, pair_t b) : id(a), t(b) {} int id; pair_t t; }; REFLECTION(message_t, id, t); -struct test_pb_st8 PUBLIC { +struct test_pb_st8 PUBLIC(test_pb_st8) { + test_pb_st8() = default; + test_pb_st8(int a, pair_t b, message_t c) : x(a), y(b), z(c) {} + int x; pair_t y; message_t z; }; REFLECTION(test_pb_st8, x, y, z); -struct test_pb_st9 PUBLIC { +struct test_pb_st9 PUBLIC(test_pb_st9) { + test_pb_st9() = default; + test_pb_st9(int a, std::vector b, std::string c) + : x(a), y(std::move(b)), z(std::move(c)) {} int x; std::vector y; std::string z; }; REFLECTION(test_pb_st9, x, y, z); -struct test_pb_st10 PUBLIC { +struct test_pb_st10 PUBLIC(test_pb_st10) { + test_pb_st10() = default; + test_pb_st10(int a, std::vector b, std::string c) + : x(a), y(std::move(b)), z(std::move(c)) {} int x; std::vector y; std::string z; }; REFLECTION(test_pb_st10, x, y, z); -struct test_pb_st11 PUBLIC { +struct test_pb_st11 PUBLIC(test_pb_st11) { + test_pb_st11() = default; + test_pb_st11(int a, std::vector> b, + std::vector c) + : x(a), y(std::move(b)), z(std::move(c)) {} int x; std::vector> y; std::vector z; }; REFLECTION(test_pb_st11, x, y, z); -struct test_pb_st12 PUBLIC { +struct test_pb_st12 PUBLIC(test_pb_st12) { + test_pb_st12() = default; + test_pb_st12(int a, std::map b, + std::map c) + : x(a), y(std::move(b)), z(std::move(c)) {} + int x; std::map y; std::map z; }; REFLECTION(test_pb_st12, x, y, z); -struct test_pb_st13 PUBLIC { +struct test_pb_st13 PUBLIC(test_pb_st13) { + test_pb_st13() = default; + test_pb_st13(int a, std::map b, std::string c) + : x(a), y(std::move(b)), z(std::move(c)) {} + int x; std::map y; std::string z; @@ -680,7 +714,9 @@ enum class colors_t { red, black }; enum level_t { debug, info }; -struct test_pb_st14 PUBLIC { +struct test_pb_st14 PUBLIC(test_pb_st14) { + test_pb_st14() = default; + test_pb_st14(int a, colors_t b, level_t c) : x(a), y(b), z(c) {} int x; colors_t y; level_t z; @@ -688,7 +724,9 @@ struct test_pb_st14 PUBLIC { REFLECTION(test_pb_st14, x, y, z); namespace client { -struct person PUBLIC { +struct person PUBLIC(person) { + person() = default; + person(std::string s, int d) : name(s), age(d) {} std::string name; int64_t age; }; @@ -696,14 +734,19 @@ struct person PUBLIC { REFLECTION(person, name, age); } // namespace client -struct my_struct PUBLIC { +struct my_struct PUBLIC(my_struct) { + my_struct() = default; + my_struct(int a, bool b, iguana::fixed64_t c) : x(a), y(b), z(c) {} int x; bool y; - struct_pb::fixed64_t z; + iguana::fixed64_t z; }; REFLECTION(my_struct, x, y, z); -struct nest1 PUBLIC { +struct nest1 PUBLIC(nest1) { + nest1() = default; + nest1(std::string s, my_struct t, int d) + : name(std::move(s)), value(t), var(d) {} std::string name; my_struct value; int var; @@ -711,7 +754,9 @@ struct nest1 PUBLIC { REFLECTION(nest1, name, value, var); -struct numer_st PUBLIC { +struct numer_st PUBLIC(numer_st) { + numer_st() = default; + numer_st(bool x, double y, float z) : a(x), b(y), c(z) {} bool a; double b; float c; @@ -720,183 +765,209 @@ REFLECTION(numer_st, a, b, c); TEST_CASE("test struct_pb") { { - my_space::inner_struct inner{0, 41, 42, 43}; + my_space::inner_struct inner{41, 42, 43}; std::string str; - struct_pb::to_pb(inner, str); - CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(inner)); + iguana::to_pb(inner, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(inner)); my_space::inner_struct inner1; - struct_pb::from_pb(inner1, str); + iguana::from_pb(inner1, str); CHECK(inner.x == inner1.x); CHECK(inner.y == inner1.y); CHECK(inner.z == inner1.z); } { - test_pb_st1 st1{0, 41, {42}, {43}}; + test_pb_st1 st1{41, {42}, {43}}; std::string str; - struct_pb::to_pb(st1, str); - CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st1 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.x == st2.x); CHECK(st1.y.val == st2.y.val); CHECK(st1.z.val == st2.z.val); } { - test_pb_st2 st1{0, 41, {42}, {43}}; + test_pb_st2 st1{41, {42}, {43}}; std::string str; - struct_pb::to_pb(st1, str); - CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st2 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.y.val == st2.y.val); } { - test_pb_st3 st1{0, 41, {42}, {43}}; + test_pb_st3 st1{41, {42}, {43}}; std::string str; - struct_pb::to_pb(st1, str); - CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st3 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.y.val == st2.y.val); } { - test_pb_st4 st1{0, 41, "it is a test"}; + test_pb_st4 st1{41, "it is a test"}; std::string str; - struct_pb::to_pb(st1, str); - CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st4 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.y == st2.y); } { - test_pb_st5 st1{0, 41, "it is a test"}; + test_pb_st5 st1{41, "it is a test"}; std::string str; - struct_pb::to_pb(st1, str); - CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st5 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.y == st2.y); } { // optional - test_pb_st6 st1{0, 41, "it is a test"}; + test_pb_st6 st1{41, "it is a test"}; std::string str; - struct_pb::to_pb(st1, str); - CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st6 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.y == st2.y); } { // sub nested objects - nest1 v{0, "Hi", {0, 1, false, {3}}, 5}, v2{}; + nest1 v{"Hi", {1, false, {3}}, 5}, v2{}; std::string s; - struct_pb::to_pb(v, s); - struct_pb::from_pb(v2, s); + iguana::to_pb(v, s); + iguana::from_pb(v2, s); CHECK(v.var == v2.var); CHECK(v.value.y == v2.value.y); CHECK(v.value.z == v2.value.z); - test_pb_st8 st1{0, 1, {0, 3, 4}, {0, 5, {0, 7, 8}}}; + test_pb_st8 st1{1, {3, 4}, {5, {7, 8}}}; std::string str; - struct_pb::to_pb(st1, str); + iguana::to_pb(st1, str); test_pb_st8 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.z.t.y == st2.z.t.y); } { // repeated messages - test_pb_st9 st1{0, 1, {2, 4, 6}, "test"}; + test_pb_st9 st1{1, {2, 4, 6}, "test"}; std::string str; - struct_pb::to_pb(st1, str); - CHECK(str.size() == struct_pb::detail::pb_key_value_size<0>(st1)); + iguana::to_pb(st1, str); + CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st9 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.z == st2.z); } { - test_pb_st10 st1{0, 1, {{0, 5, {7, 8}}, {0, 9, {11, 12}}}, "test"}; + test_pb_st10 st1{1, {{5, {7, 8}}, {9, {11, 12}}}, "test"}; std::string str; - struct_pb::to_pb(st1, str); + iguana::to_pb(st1, str); test_pb_st10 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.z == st2.z); } { - message_t m{0, 1, {0, 3, 4}}; - test_pb_st11 st1{0, 1, {m}, {}}; + message_t m{1, {3, 4}}; + test_pb_st11 st1{1, {m}, {}}; std::string str; - struct_pb::to_pb(st1, str); + iguana::to_pb(st1, str); test_pb_st11 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.z == st2.z); } + { + auto m = std::make_shared(); + m->id = 10; + m->t.x = 11; + m->t.y = 12; + std::string s; + m->to_pb(s); + + std::shared_ptr PUBLIC = m; + std::string str; + PUBLIC->to_pb(str); + + CHECK(s == str); + + PUBLIC->from_pb(str); + } { message_t st1{}; std::string str; - struct_pb::to_pb(st1, str); + iguana::to_pb(st1, str); message_t st2{}; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.id == st2.id); } { - test_pb_st11 st1{0, 1, {{{0, 5, {7, 8}}}, {{0, 9, {11, 12}}}}, {"test"}}; + test_pb_st11 st1{ + 1, {message_t{5, {7, 8}}, message_t{9, {11, 12}}}, {"test"}}; std::string str; - struct_pb::to_pb(st1, str); + iguana::to_pb(st1, str); + + std::string str1; + st1.to_pb(str1); + + test_pb_st11 st3; + st3.from_pb(str1); + + CHECK(str == str1); test_pb_st11 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.z == st2.z); + CHECK(st3.z == st2.z); } { // map messages - test_pb_st12 st1{0, 1, {{1, "test"}, {2, "ok"}}, {{"test", 4}, {"ok", 6}}}; + test_pb_st12 st1{1, {{1, "test"}, {2, "ok"}}, {{"test", 4}, {"ok", 6}}}; std::string str; - struct_pb::to_pb(st1, str); + iguana::to_pb(st1, str); test_pb_st12 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.z == st2.z); } { // map messages - test_pb_st12 st1{0, 1, {{1, ""}, {0, "ok"}}, {{"", 4}, {"ok", 0}}}; + test_pb_st12 st1{1, {{1, ""}, {0, "ok"}}, {{"", 4}, {"ok", 0}}}; std::string str; - struct_pb::to_pb(st1, str); // error + iguana::to_pb(st1, str); // error print_hex_str(str); test_pb_st12 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.z == st2.z); } { // map messages test_pb_st13 st1; st1.x = 1; - st1.y.emplace(1, message_t{0, 2, {0, 3, 4}}); - st1.y.emplace(2, message_t{0, 4, {0, 6, 8}}); + st1.y.emplace(1, message_t{2, {3, 4}}); + st1.y.emplace(2, message_t{4, {6, 8}}); st1.z = "test"; std::string str; - struct_pb::to_pb(st1, str); + iguana::to_pb(st1, str); test_pb_st13 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.z == st2.z); } { @@ -907,29 +978,29 @@ TEST_CASE("test struct_pb") { st1.y.emplace(3, message_t{}); st1.z = "test"; std::string str; - struct_pb::to_pb(st1, str); + iguana::to_pb(st1, str); test_pb_st13 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.z == st2.z); } { // enum - test_pb_st14 st1{0, 1, colors_t::black, level_t::info}; + test_pb_st14 st1{1, colors_t::black, level_t::info}; std::string str; - struct_pb::to_pb(st1, str); + iguana::to_pb(st1, str); test_pb_st14 st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.z == st2.z); } { // bool float double - numer_st n{0, true, 10.25, 4.578}, n1; + numer_st n{true, 10.25, 4.578}, n1; std::string str; - struct_pb::to_pb(n, str); + iguana::to_pb(n, str); - struct_pb::from_pb(n1, str); + iguana::from_pb(n1, str); CHECK(n1.a == n.a); CHECK(n1.b == n.b); CHECK(n1.c == n.c); @@ -937,11 +1008,11 @@ TEST_CASE("test struct_pb") { } TEST_CASE("test members") { - using namespace struct_pb; - using namespace struct_pb::detail; + using namespace iguana; + using namespace iguana::detail; - my_space::inner_struct inner{0, 41, 42, 43}; - const auto &map = struct_pb::get_members(); + my_space::inner_struct inner{41, 42, 43}; + const auto &map = iguana::get_members(); std::visit( [&inner](auto &member) mutable { CHECK(member.field_no == 9); @@ -950,8 +1021,8 @@ TEST_CASE("test members") { }, map.at(9)); - point_t pt{0, 2, 3}; - const auto &arr1 = struct_pb::get_members(); + point_t pt{2, 3}; + const auto &arr1 = iguana::get_members(); auto &val = arr1.at(1); std::visit( [&pt](auto &member) mutable { @@ -962,7 +1033,10 @@ TEST_CASE("test members") { val); } -struct test_variant PUBLIC { +struct test_variant PUBLIC(test_variant) { + test_variant() = default; + test_variant(int a, std::variant b, double c) + : x(a), y(std::move(b)), z(c) {} int x; std::variant y; double z; @@ -971,7 +1045,7 @@ REFLECTION(test_variant, x, y, z); TEST_CASE("test variant") { { - constexpr auto tp = struct_pb::get_members_tuple(); + constexpr auto tp = iguana::get_members_tuple(); static_assert(std::get<0>(tp).field_no == 1); static_assert(std::get<1>(tp).field_no == 2); static_assert(std::get<2>(tp).field_no == 3); @@ -979,7 +1053,7 @@ TEST_CASE("test variant") { static_assert(std::get<4>(tp).field_no == 5); } { - constexpr static auto map = struct_pb::get_members(); + constexpr static auto map = iguana::get_members(); static_assert(map.find(1) != map.end()); static_assert(map.find(2) != map.end()); static_assert(map.find(3) != map.end()); @@ -1000,20 +1074,20 @@ TEST_CASE("test variant") { val2->second); } { - test_variant st1 = {0, 5, "Hello, variant!", 3.14}; + test_variant st1 = {5, "Hello, variant!", 3.14}; std::string str; - struct_pb::to_pb(st1, str); + iguana::to_pb(st1, str); test_variant st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.z == st2.z); CHECK(std::get(st2.y) == "Hello, variant!"); } { - test_variant st1 = {0, 5, 3.88, 3.14}; + test_variant st1 = {5, 3.88, 3.14}; std::string str; - struct_pb::to_pb(st1, str); + iguana::to_pb(st1, str); test_variant st2; - struct_pb::from_pb(st2, str); + iguana::from_pb(st2, str); CHECK(st1.z == st2.z); CHECK(std::get(st2.y) == 3.88); } diff --git a/src/struct_pb/tests/unittest_proto3.h b/src/struct_pb/tests/unittest_proto3.h index bde1f1a31..e1761ec60 100644 --- a/src/struct_pb/tests/unittest_proto3.h +++ b/src/struct_pb/tests/unittest_proto3.h @@ -6,7 +6,7 @@ #include "unittest_proto3.pb.h" #endif -#define PUBLIC : iguana::pb_base +#define PUBLIC(T) : public iguana::pb_base_impl // define the struct as msg in proto namespace stpb { @@ -18,7 +18,19 @@ enum class Enum { NEG = -1, // Intentionally negative. }; -struct BaseTypeMsg PUBLIC { +struct BaseTypeMsg PUBLIC(BaseTypeMsg) { + BaseTypeMsg() = default; + BaseTypeMsg(int32_t a, int64_t b, uint32_t c, uint64_t d, float e, double f, + bool g, std::string h, Enum i) + : optional_int32(a), + optional_int64(b), + optional_uint32(c), + optional_uint64(d), + optional_float(e), + optional_double(f), + optional_bool(g), + optional_string(std::move(h)), + optional_enum(i) {} int32_t optional_int32; int64_t optional_int64; uint32_t optional_uint32; @@ -44,7 +56,17 @@ REFLECTION(BaseTypeMsg, optional_int32, optional_int64, optional_uint32, optional_uint64, optional_float, optional_double, optional_bool, optional_string, optional_enum); -struct IguanaTypeMsg PUBLIC { +struct IguanaTypeMsg PUBLIC(IguanaTypeMsg) { + IguanaTypeMsg() = default; + IguanaTypeMsg(iguana::sint32_t a, iguana::sint64_t b, iguana::fixed32_t c, + iguana::fixed64_t d = {}, iguana::sfixed32_t e = {}, + iguana::sfixed64_t f = {}) + : optional_sint32(a), + optional_sint64(b), + optional_fixed32(c), + optional_fixed64(d), + optional_sfixed32(e), + optional_sfixed64(f) {} iguana::sint32_t optional_sint32; iguana::sint64_t optional_sint64; iguana::fixed32_t optional_fixed32; @@ -64,7 +86,20 @@ struct IguanaTypeMsg PUBLIC { REFLECTION(IguanaTypeMsg, optional_sint32, optional_sint64, optional_fixed32, optional_fixed64, optional_sfixed32, optional_sfixed64); -struct RepeatBaseTypeMsg PUBLIC { +struct RepeatBaseTypeMsg PUBLIC(RepeatBaseTypeMsg) { + RepeatBaseTypeMsg() = default; + RepeatBaseTypeMsg(std::vector a, std::vector b, + std::vector c, std::vector d, + std::vector e, std::vector f, + std::vector g, std::vector h) + : repeated_uint32(std::move(a)), + repeated_uint64(std::move(b)), + repeated_int32(std::move(c)), + repeated_int64(std::move(d)), + repeated_float(std::move(e)), + repeated_double(std::move(f)), + repeated_string(std::move(g)), + repeated_enum(std::move(h)) {} std::vector repeated_uint32; std::vector repeated_uint64; std::vector repeated_int32; @@ -79,7 +114,20 @@ REFLECTION(RepeatBaseTypeMsg, repeated_uint32, repeated_uint64, repeated_int32, repeated_int64, repeated_float, repeated_double, repeated_string, repeated_enum); -struct RepeatIguanaTypeMsg PUBLIC { +struct RepeatIguanaTypeMsg PUBLIC(RepeatIguanaTypeMsg) { + RepeatIguanaTypeMsg() = default; + RepeatIguanaTypeMsg(std::vector a, + std::vector b, + std::vector c, + std::vector d, + std::vector e, + std::vector f) + : repeated_sint32(std::move(a)), + repeated_sint64(std::move(b)), + repeated_fixed32(std::move(c)), + repeated_fixed64(std::move(d)), + repeated_sfixed32(std::move(e)), + repeated_sfixed64(std::move(f)) {} std::vector repeated_sint32; std::vector repeated_sint64; std::vector repeated_fixed32; @@ -92,7 +140,15 @@ REFLECTION(RepeatIguanaTypeMsg, repeated_sint32, repeated_sint64, repeated_fixed32, repeated_fixed64, repeated_sfixed32, repeated_sfixed64); -struct NestedMsg PUBLIC { +struct NestedMsg PUBLIC(NestedMsg) { + NestedMsg() = default; + NestedMsg(BaseTypeMsg a, std::vector b, IguanaTypeMsg c, + std::vector d, std::vector e) + : base_msg(std::move(a)), + repeat_base_msg(std::move(b)), + iguana_type_msg(std::move(c)), + repeat_iguna_msg(std::move(d)), + repeat_repeat_base_msg(std::move(e)) {} BaseTypeMsg base_msg; std::vector repeat_base_msg; IguanaTypeMsg iguana_type_msg; @@ -102,7 +158,14 @@ struct NestedMsg PUBLIC { REFLECTION(NestedMsg, base_msg, repeat_base_msg, iguana_type_msg, repeat_iguna_msg, repeat_repeat_base_msg); -struct MapMsg PUBLIC { +struct MapMsg PUBLIC(MapMsg) { + MapMsg() = default; + MapMsg(std::unordered_map a, + std::unordered_map b, + std::map c) + : sfix64_str_map(std::move(a)), + str_iguana_type_msg_map(std::move(b)), + int_repeat_base_msg_map(std::move(c)) {} std::unordered_map sfix64_str_map{}; std::unordered_map str_iguana_type_msg_map{}; std::map int_repeat_base_msg_map{}; @@ -110,28 +173,41 @@ struct MapMsg PUBLIC { REFLECTION(MapMsg, sfix64_str_map, str_iguana_type_msg_map, int_repeat_base_msg_map); -struct BaseOneofMsg PUBLIC { +struct BaseOneofMsg PUBLIC(BaseOneofMsg) { + BaseOneofMsg() = default; + BaseOneofMsg(int32_t a, std::variant b, + double c) + : optional_int32(a), one_of(std::move(b)), optional_double(c) {} int32_t optional_int32; std::variant one_of; double optional_double; }; REFLECTION(BaseOneofMsg, optional_int32, one_of, optional_double); -struct NestOneofMsg PUBLIC { +struct NestOneofMsg PUBLIC(NestOneofMsg) { + NestOneofMsg() = default; + NestOneofMsg(std::variant a) + : nest_one_of_msg(std::move(a)) {} std::variant nest_one_of_msg; }; REFLECTION(NestOneofMsg, nest_one_of_msg); -struct simple_t PUBLIC { +struct simple_t PUBLIC(simple_t) { + simple_t() = default; + simple_t(int32_t x, int32_t y, int64_t z, int64_t w, std::string s) + : a(x), b(y), c(z), d(w), str(std::move(s)) {} int32_t a; int32_t b; int64_t c; int64_t d; - std::string_view str; + std::string str; }; REFLECTION(simple_t, a, b, c, d, str); -struct simple_t1 PUBLIC { +struct simple_t1 PUBLIC(simple_t1) { + simple_t1() = default; + simple_t1(int32_t x, int32_t y, int64_t z, int64_t w, std::string_view s) + : a(x), b(y), c(z), d(w), str(s) {} int32_t a; int32_t b; int64_t c; @@ -142,7 +218,10 @@ REFLECTION(simple_t1, a, b, c, d, str); enum Color : uint8_t { Red, Green, Blue }; -struct simple_t2 PUBLIC { +struct simple_t2 PUBLIC(simple_t2) { + simple_t2() = default; + simple_t2(int16_t x, uint8_t y, Color z, int64_t w, std::string_view s = "") + : a(x), b(y), c(z), d(w), str(s) {} int16_t a; uint8_t b; Color c; @@ -151,7 +230,10 @@ struct simple_t2 PUBLIC { }; REFLECTION(simple_t2, a, b, c, d, str); -struct person PUBLIC { +struct person PUBLIC(person) { + person() = default; + person(int32_t a, std::string b, int c, double d) + : id(a), name(std::move(b)), age(c), salary(d) {} int32_t id; std::string name; int age; @@ -159,7 +241,10 @@ struct person PUBLIC { }; REFLECTION(person, id, name, age, salary); -struct rect PUBLIC { +struct rect PUBLIC(rect) { + rect() = default; + rect(int32_t a, int32_t b, int32_t c, int32_t d) + : x(a), y(b), width(c), height(d) {} int32_t x = 1; int32_t y = 0; int32_t width = 11; @@ -167,7 +252,9 @@ struct rect PUBLIC { }; REFLECTION(rect, x, y, width, height); -struct Vec3 PUBLIC { +struct Vec3 PUBLIC(Vec3) { + Vec3() = default; + Vec3(float a, float b, float c) : x(a), y(b), z(c) {} float x; float y; float z; @@ -175,13 +262,27 @@ struct Vec3 PUBLIC { REFLECTION(Vec3, x, y, z); }; -struct Weapon PUBLIC { +struct Weapon PUBLIC(Weapon) { + Weapon() = default; + Weapon(std::string a, int32_t b) : name(std::move(a)), damage(b) {} std::string name; int32_t damage; }; REFLECTION(Weapon, name, damage); -struct Monster PUBLIC { +struct Monster PUBLIC(Monster) { + Monster() = default; + Monster(Vec3 a, int32_t b, int32_t c, std::string d, std::string e, int32_t f, + std::vector g, Weapon h, std::vector i) + : pos(a), + mana(b), + hp(c), + name(std::move(d)), + inventory(std::move(e)), + color(f), + weapons(std::move(g)), + equipped(std::move(h)), + path(std::move(i)) {} Vec3 pos; int32_t mana; int32_t hp; @@ -195,7 +296,10 @@ struct Monster PUBLIC { REFLECTION(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, path); -struct bench_int32 PUBLIC { +struct bench_int32 PUBLIC(bench_int32) { + bench_int32() = default; + bench_int32(int32_t x, int32_t y, int32_t z, int32_t u) + : a(x), b(y), c(z), d(u) {} int32_t a; int32_t b; int32_t c; @@ -206,22 +310,21 @@ REFLECTION(bench_int32, a, b, c, d); } // namespace stpb inline auto create_person() { - stpb::person p{0, 432798, std::string(1024, 'A'), 24, 65536.42}; + stpb::person p{432798, std::string(1024, 'A'), 24, 65536.42}; return p; } inline stpb::Monster create_sp_monster() { stpb::Monster m = { - 0, - {0, 1, 2, 3}, + {1, 2, 3}, 16, 24, "it is a test", "\1\2\3\4", stpb::Color::Red, - {{0, "gun", 42}, {0, "shotgun", 56}}, - {0, "air craft", 67}, - {{0, 7, 8, 9}, {0, 71, 81, 91}}, + {{"gun", 42}, {"shotgun", 56}}, + {"air craft", 67}, + {{7, 8, 9}, {71, 81, 91}}, }; return m; } diff --git a/website/docs/en/struct_pb/struct_pb_intro.md b/website/docs/en/struct_pb/struct_pb_intro.md index efceb0947..4edd32c68 100644 --- a/website/docs/en/struct_pb/struct_pb_intro.md +++ b/website/docs/en/struct_pb/struct_pb_intro.md @@ -14,14 +14,14 @@ Utilize inline, zero copy, compile-time compute to optimize performance. ```cpp #include -struct my_struct : struct_pb::pb_base { +struct my_struct : struct_pb::pb_base_impl { int x; bool y; struct_pb::fixed64_t z; }; REFLECTION(my_struct, x, y, z); -struct nest : struct_pb::pb_base { +struct nest : struct_pb::pb_base_impl { std::string name; my_struct value; int var; diff --git a/website/docs/zh/struct_pb/struct_pb_intro.md b/website/docs/zh/struct_pb/struct_pb_intro.md index da329098e..fd7bf11da 100644 --- a/website/docs/zh/struct_pb/struct_pb_intro.md +++ b/website/docs/zh/struct_pb/struct_pb_intro.md @@ -11,14 +11,14 @@ struct_pb 是基于C++17 开发的高性能、易用、header only的protobuf格 ```cpp #include -struct my_struct : struct_pb::pb_base { +struct my_struct : struct_pb::pb_base_impl { int x; bool y; struct_pb::fixed64_t z; }; REFLECTION(my_struct, x, y, z); -struct nest : struct_pb::pb_base { +struct nest : struct_pb::pb_base_impl { std::string name; my_struct value; int var; From d521d6d790a67f9b0a90a0f53f4f0bb5eea90a88 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Fri, 24 May 2024 17:57:15 +0800 Subject: [PATCH 24/26] update doc --- include/ylt/standalone/iguana/pb_util.hpp | 4 ++-- src/struct_pb/tests/main.cpp | 6 +++--- website/docs/en/struct_pb/struct_pb_intro.md | 4 ++-- website/docs/zh/struct_pb/struct_pb_intro.md | 4 ++-- 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/include/ylt/standalone/iguana/pb_util.hpp b/include/ylt/standalone/iguana/pb_util.hpp index 8a9bb5ba0..a8014110a 100644 --- a/include/ylt/standalone/iguana/pb_util.hpp +++ b/include/ylt/standalone/iguana/pb_util.hpp @@ -475,7 +475,7 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t) { }, std::make_index_sequence{}); static_assert(inherits_from_pb_base_v, - "must be inherited from iguana::pb_base"); + "must be inherited from iguana::pb_base_impl"); t.cache_size = len; if constexpr (key_size == 0) { @@ -556,7 +556,7 @@ IGUANA_INLINE size_t pb_value_size(T&& t) { using value_type = std::remove_const_t>; if constexpr (is_reflection_v) { static_assert(inherits_from_pb_base_v>, - "must be inherited from iguana::pb_base"); + "must be inherited from iguana::pb_base_impl"); return t.cache_size; } else if constexpr (is_sequence_container::value) { diff --git a/src/struct_pb/tests/main.cpp b/src/struct_pb/tests/main.cpp index c7c6bd43b..0860f449d 100644 --- a/src/struct_pb/tests/main.cpp +++ b/src/struct_pb/tests/main.cpp @@ -900,13 +900,13 @@ TEST_CASE("test struct_pb") { std::string s; m->to_pb(s); - std::shared_ptr PUBLIC = m; + std::shared_ptr t = m; std::string str; - PUBLIC->to_pb(str); + t->to_pb(str); CHECK(s == str); - PUBLIC->from_pb(str); + t->from_pb(str); } { message_t st1{}; diff --git a/website/docs/en/struct_pb/struct_pb_intro.md b/website/docs/en/struct_pb/struct_pb_intro.md index 4edd32c68..0929f4892 100644 --- a/website/docs/en/struct_pb/struct_pb_intro.md +++ b/website/docs/en/struct_pb/struct_pb_intro.md @@ -106,10 +106,10 @@ oneof -> `std::variant <...>` - only support proto3, not support proto2 now; - don't support reflection now; - don't support unkonwn fields; -- struct must inherited from pb_base; +- struct must inherited from pb_base_impl; ## roadmap - support proto2; - support reflection; - support unkonwn fields; -- no need inheriting from pb_base; +- no need inheriting from pb_base_impl; diff --git a/website/docs/zh/struct_pb/struct_pb_intro.md b/website/docs/zh/struct_pb/struct_pb_intro.md index fd7bf11da..2e61bdc85 100644 --- a/website/docs/zh/struct_pb/struct_pb_intro.md +++ b/website/docs/zh/struct_pb/struct_pb_intro.md @@ -96,10 +96,10 @@ oneof -> `std::variant <...>` - 目前还只支持proto3,不支持proto2; - 目前还没支持反射; - 还没支持unkonwn字段; -- struct_pb 结构体必须派生于pb_base +- struct_pb 结构体必须派生于pb_base_impl ## roadmap - 支持proto2; - 支持反射; - 支持unkonwn字段; -- 去除struct_pb 结构体必须派生于pb_base的约束; +- 去除struct_pb 结构体必须派生于pb_base_impl的约束; From 25cc7b3574453d78ab0820683bdd6f92463c4463 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Tue, 28 May 2024 11:13:02 +0800 Subject: [PATCH 25/26] dynamic reflection and doc --- include/ylt/standalone/iguana/pb_util.hpp | 250 +++++++++++------- include/ylt/standalone/iguana/pb_writer.hpp | 52 ++-- include/ylt/standalone/iguana/reflection.hpp | 117 ++++++-- .../benchmark/struct_pb_sample.hpp | 16 +- src/struct_pb/examples/main.cpp | 34 ++- src/struct_pb/tests/main.cpp | 78 +++++- src/struct_pb/tests/unittest_proto3.h | 4 +- website/docs/en/struct_pb/struct_pb_intro.md | 64 ++++- website/docs/zh/struct_pb/struct_pb_intro.md | 66 ++++- 9 files changed, 514 insertions(+), 167 deletions(-) diff --git a/include/ylt/standalone/iguana/pb_util.hpp b/include/ylt/standalone/iguana/pb_util.hpp index a8014110a..b2e467721 100644 --- a/include/ylt/standalone/iguana/pb_util.hpp +++ b/include/ylt/standalone/iguana/pb_util.hpp @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -34,16 +35,15 @@ IGUANA_INLINE void to_pb(T& t, Stream& out); template IGUANA_INLINE void from_pb(T& t, std::string_view pb_str); -struct pb_base { - virtual void to_pb(std::string& str) {} - virtual void from_pb(std::string_view str) {} +using base = detail::base; - size_t cache_size = 0; - virtual ~pb_base() {} -}; +template +IGUANA_INLINE constexpr size_t member_offset(T* t, U T::*member) { + return (char*)&(t->*member) - (char*)t; +} template -struct pb_base_impl : public pb_base { +struct base_impl : public base { void to_pb(std::string& str) override { iguana::to_pb(*(static_cast(this)), str); } @@ -51,11 +51,61 @@ struct pb_base_impl : public pb_base { void from_pb(std::string_view str) override { iguana::from_pb(*(static_cast(this)), str); } - virtual ~pb_base_impl() {} + + iguana::detail::field_info get_field_info(std::string_view name) override { + static constexpr auto map = iguana::get_members(); + iguana::detail::field_info info{}; + for (auto [no, field] : map) { + if (info.offset > 0) { + break; + } + std::visit( + [&](auto val) { + if (val.field_name == name) { + info.offset = member_offset((T*)this, val.member_ptr); + using value_type = typename decltype(val)::value_type; +#if defined(__clang__) || defined(_MSC_VER) || \ + (defined(__GNUC__) && __GNUC__ > 8) + info.type_name = type_string(); +#endif + } + }, + field); + } + + return info; + } + + std::vector get_fields_name() override { + static constexpr auto map = iguana::get_members(); + std::vector vec; + for (auto [no, val] : map) { + std::visit( + [&](auto& field) { + vec.push_back(std::string_view(field.field_name.data(), + field.field_name.size())); + }, + val); + } + return vec; + } + + virtual ~base_impl() {} + + size_t cache_size = 0; }; template -constexpr bool inherits_from_pb_base_v = std::is_base_of_v; +constexpr bool inherits_from_base_v = std::is_base_of_v; + +IGUANA_INLINE std::shared_ptr create_instance(std::string_view name) { + auto it = iguana::detail::g_pb_map.find(name); + if (it == iguana::detail::g_pb_map.end()) { + throw std::invalid_argument(std::string(name) + + "not inheried from iguana::base_impl"); + } + return it->second(); +} namespace detail { template @@ -361,48 +411,66 @@ IGUANA_INLINE constexpr void for_each_n(F&& f, std::index_sequence) { (std::forward(f)(std::integral_constant{}), ...); } -template -IGUANA_INLINE size_t numeric_size(T&& t) { - using value_type = std::remove_const_t>; - if constexpr (omit_default_val) { - if constexpr (is_fixed_v || is_signed_varint_v) { - if (t.val == 0) +template +IGUANA_INLINE size_t str_numeric_size(Type&& t) { + using T = std::remove_const_t>; + if constexpr (std::is_same_v || + std::is_same_v) { + // string + if constexpr (omit_default_val) { + if (t.size() == 0) IGUANA_UNLIKELY { return 0; } } + if constexpr (key_size == 0) { + return t.size(); + } else { - if (t == static_cast(0)) - IGUANA_UNLIKELY { return 0; } + return key_size + variant_uint32_size(static_cast(t.size())) + + t.size(); } } - if constexpr (std::is_integral_v) { - if constexpr (std::is_same_v) { - return 1 + key_size; + else { + // numeric + if constexpr (omit_default_val) { + if constexpr (is_fixed_v || is_signed_varint_v) { + if (t.val == 0) + IGUANA_UNLIKELY { return 0; } + } + else { + if (t == static_cast(0)) + IGUANA_UNLIKELY { return 0; } + } + } + if constexpr (std::is_integral_v) { + if constexpr (std::is_same_v) { + return 1 + key_size; + } + else { + return key_size + variant_intergal_size(t); + } + } + else if constexpr (detail::is_signed_varint_v) { + return key_size + variant_intergal_size(encode_zigzag(t.val)); + } + else if constexpr (detail::is_fixed_v) { + return key_size + sizeof(typename T::value_type); + } + else if constexpr (std::is_same_v || std::is_same_v) { + return key_size + sizeof(T); + } + else if constexpr (std::is_enum_v) { + using U = std::underlying_type_t; + return key_size + variant_intergal_size(static_cast(t)); } else { - return key_size + variant_intergal_size(t); + static_assert(!sizeof(T), "err"); } } - else if constexpr (detail::is_signed_varint_v) { - return key_size + variant_intergal_size(encode_zigzag(t.val)); - } - else if constexpr (detail::is_fixed_v) { - return key_size + sizeof(typename value_type::value_type); - } - else if constexpr (std::is_same_v || - std::is_same_v) { - return key_size + sizeof(value_type); - } - else if constexpr (std::is_enum_v) { - using U = std::underlying_type_t; - return key_size + variant_intergal_size(static_cast(t)); - } - else { - static_assert(!sizeof(value_type), "err"); - } } -template -IGUANA_INLINE size_t pb_key_value_size(T&& t); +template +IGUANA_INLINE size_t pb_key_value_size(Type&& t, Arr& size_arr); template constexpr inline size_t get_variant_index() { @@ -420,12 +488,12 @@ constexpr inline size_t get_variant_index() { } } -template -IGUANA_INLINE size_t pb_oneof_size(Type&& t) { +template +IGUANA_INLINE size_t pb_oneof_size(Type&& t, Arr& size_arr) { using T = std::decay_t; int len = 0; std::visit( - [&len](auto&& value) IGUANA__INLINE_LAMBDA { + [&len, &size_arr](auto&& value) IGUANA__INLINE_LAMBDA { using value_type = std::remove_const_t>; constexpr auto offset = @@ -434,7 +502,7 @@ IGUANA_INLINE size_t pb_oneof_size(Type&& t) { ((field_no + offset) << 3) | static_cast(get_wire_type()); len = pb_key_value_size( - std::forward(value)); + std::forward(value), size_arr); }, std::forward(t)); return len; @@ -442,15 +510,20 @@ IGUANA_INLINE size_t pb_oneof_size(Type&& t) { // returns size = key_size + optional(len_size) + len // when key_size == 0, return len -template -IGUANA_INLINE size_t pb_key_value_size(Type&& t) { +template +IGUANA_INLINE size_t pb_key_value_size(Type&& t, Arr& size_arr) { using T = std::remove_const_t>; if constexpr (is_reflection_v || is_custom_reflection_v) { size_t len = 0; static constexpr auto tuple = get_members_tuple(); constexpr size_t SIZE = std::tuple_size_v>; + size_t pre_index = -1; + if constexpr (!inherits_from_base_v && key_size != 0) { + pre_index = size_arr.size(); + size_arr.push_back(0); // placeholder + } for_each_n( - [&len, &t](auto i) IGUANA__INLINE_LAMBDA { + [&len, &t, &size_arr](auto i) IGUANA__INLINE_LAMBDA { using field_type = std::tuple_element_t>; @@ -462,7 +535,7 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t) { get_variant_index - 1>(); if constexpr (offset == 0) { - len += pb_oneof_size(val); + len += pb_oneof_size(val, size_arr); } } else { @@ -470,14 +543,16 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t) { (value.field_no << 3) | static_cast(get_wire_type()); constexpr auto sub_keysize = variant_uint32_size_constexpr(sub_key); - len += pb_key_value_size(val); + len += pb_key_value_size(val, size_arr); } }, std::make_index_sequence{}); - static_assert(inherits_from_pb_base_v, - "must be inherited from iguana::pb_base_impl"); - t.cache_size = len; - + if constexpr (inherits_from_base_v) { + t.cache_size = len; + } + else if constexpr (key_size != 0) { + size_arr[pre_index] = len; + } if constexpr (key_size == 0) { // for top level return len; @@ -497,14 +572,14 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t) { size_t len = 0; if constexpr (is_lenprefix_v) { for (auto& item : t) { - len += pb_key_value_size(item); + len += pb_key_value_size(item, size_arr); } return len; } else { for (auto& item : t) { - // here 0 to get pakced size - len += numeric_size<0, false>(item); + // here 0 to get pakced size, and item must be numeric + len += str_numeric_size<0, false>(item); } if (len == 0) { return 0; @@ -518,8 +593,8 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t) { size_t len = 0; for (auto& [k, v] : t) { // the key_size of k and v is constant 1 - size_t kv_len = - pb_key_value_size<1, false>(k) + pb_key_value_size<1, false>(v); + auto kv_len = pb_key_value_size<1, false>(k, size_arr) + + pb_key_value_size<1, false>(v, size_arr); len += key_size + variant_uint32_size(static_cast(kv_len)) + kv_len; } @@ -529,42 +604,37 @@ IGUANA_INLINE size_t pb_key_value_size(Type&& t) { if (!t.has_value()) { return 0; } - return pb_key_value_size(*t); - } - else if constexpr (std::is_same_v || - std::is_same_v) { - if constexpr (omit_default_val) { - if (t.size() == 0) - IGUANA_UNLIKELY { return 0; } - } - if constexpr (key_size == 0) { - return t.size(); - } - else { - return key_size + variant_uint32_size(static_cast(t.size())) + - t.size(); - } + return pb_key_value_size(*t, size_arr); } else { - return numeric_size(t); + return str_numeric_size(t); } } // return the payload size -template -IGUANA_INLINE size_t pb_value_size(T&& t) { - using value_type = std::remove_const_t>; - if constexpr (is_reflection_v) { - static_assert(inherits_from_pb_base_v>, - "must be inherited from iguana::pb_base_impl"); - return t.cache_size; - } - else if constexpr (is_sequence_container::value) { - using item_type = typename value_type::value_type; +template +IGUANA_INLINE size_t pb_value_size(Type&& t, uint32_t*& sz_ptr) { + using T = std::remove_const_t>; + if constexpr (is_reflection_v || is_custom_reflection_v) { + if constexpr (inherits_from_base_v) { + return t.cache_size; + } + else { + // *sz_ptr is secure and logically guaranteed + if constexpr (skip_next) { + return *(sz_ptr++); + } + else { + return *sz_ptr; + } + } + } + else if constexpr (is_sequence_container::value) { + using item_type = typename T::value_type; size_t len = 0; if constexpr (!is_lenprefix_v) { for (auto& item : t) { - len += numeric_size<0, false>(item); + len += str_numeric_size<0, false>(item); } return len; } @@ -572,17 +642,17 @@ IGUANA_INLINE size_t pb_value_size(T&& t) { static_assert(!sizeof(item_type), "the size of this type is meaningless"); } } - else if constexpr (is_map_container::value) { - static_assert(!sizeof(value_type), "the size of this type is meaningless"); + else if constexpr (is_map_container::value) { + static_assert(!sizeof(T), "the size of this type is meaningless"); } - else if constexpr (optional_v) { + else if constexpr (optional_v) { if (!t.has_value()) { return 0; } - return pb_value_size(*t); + return pb_value_size(*t, sz_ptr); } else { - return pb_key_value_size<0>(t); + return str_numeric_size<0, false>(t); } } diff --git a/include/ylt/standalone/iguana/pb_writer.hpp b/include/ylt/standalone/iguana/pb_writer.hpp index 957d0e97b..db2662ab5 100644 --- a/include/ylt/standalone/iguana/pb_writer.hpp +++ b/include/ylt/standalone/iguana/pb_writer.hpp @@ -27,10 +27,11 @@ IGUANA_INLINE void encode_fixed_field(V val, It&& it) { template -IGUANA_INLINE void to_pb_impl(Type&& t, It&& it); +IGUANA_INLINE void to_pb_impl(Type&& t, It&& it, uint32_t*& sz_ptr); template -IGUANA_INLINE void encode_pair_value(V&& val, It&& it, size_t size) { +IGUANA_INLINE void encode_pair_value(V&& val, It&& it, size_t size, + uint32_t*& sz_ptr) { if (size == 0) IGUANA_UNLIKELY { // map keys can't be omitted even if values are empty @@ -39,7 +40,7 @@ IGUANA_INLINE void encode_pair_value(V&& val, It&& it, size_t size) { serialize_varint(0, it); } else { - to_pb_impl(val, it); + to_pb_impl(val, it, sz_ptr); } } @@ -78,10 +79,10 @@ IGUANA_INLINE void encode_numeric_field(T t, It&& it) { } template -IGUANA_INLINE void to_pb_oneof(Type&& t, It&& it) { +IGUANA_INLINE void to_pb_oneof(Type&& t, It&& it, uint32_t*& sz_ptr) { using T = std::decay_t; std::visit( - [&it](auto&& value) IGUANA__INLINE_LAMBDA { + [&it, &sz_ptr](auto&& value) IGUANA__INLINE_LAMBDA { using value_type = std::remove_const_t>; constexpr auto offset = @@ -89,20 +90,19 @@ IGUANA_INLINE void to_pb_oneof(Type&& t, It&& it) { constexpr uint32_t key = ((field_no + offset) << 3) | static_cast(get_wire_type()); - to_pb_impl(std::forward(value), it); + to_pb_impl(std::forward(value), it, sz_ptr); }, std::forward(t)); } // omit_default_val = true indicates to omit the default value in searlization template -IGUANA_INLINE void to_pb_impl(Type&& t, It&& it) { +IGUANA_INLINE void to_pb_impl(Type&& t, It&& it, uint32_t*& sz_ptr) { using T = std::remove_const_t>; if constexpr (is_reflection_v || is_custom_reflection_v) { - // TODO: improve the key serialize - auto len = pb_value_size(t); // can't be omitted even if values are empty if constexpr (key != 0) { + auto len = pb_value_size(t, sz_ptr); serialize_varint_u32_constexpr(it); serialize_varint(len, it); if (len == 0) @@ -111,7 +111,7 @@ IGUANA_INLINE void to_pb_impl(Type&& t, It&& it) { static constexpr auto tuple = get_members_tuple(); constexpr size_t SIZE = std::tuple_size_v>; for_each_n( - [&t, &it](auto i) IGUANA__INLINE_LAMBDA { + [&t, &it, &sz_ptr](auto i) IGUANA__INLINE_LAMBDA { using field_type = std::tuple_element_t>; @@ -124,14 +124,14 @@ IGUANA_INLINE void to_pb_impl(Type&& t, It&& it) { get_variant_index - 1>(); if constexpr (offset == 0) { - to_pb_oneof(val, it); + to_pb_oneof(val, it, sz_ptr); } } else { constexpr uint32_t sub_key = (value.field_no << 3) | static_cast(get_wire_type()); - to_pb_impl(val, it); + to_pb_impl(val, it, sz_ptr); } }, std::make_index_sequence{}); @@ -143,14 +143,14 @@ IGUANA_INLINE void to_pb_impl(Type&& t, It&& it) { if constexpr (is_lenprefix_v) { // non-packed for (auto& item : t) { - to_pb_impl(item, it); + to_pb_impl(item, it, sz_ptr); } } else { if (t.empty()) IGUANA_UNLIKELY { return; } serialize_varint_u32_constexpr(it); - serialize_varint(pb_value_size(t), it); + serialize_varint(pb_value_size(t, sz_ptr), it); for (auto& item : t) { encode_numeric_field(item, it); } @@ -168,26 +168,27 @@ IGUANA_INLINE void to_pb_impl(Type&& t, It&& it) { for (auto& [k, v] : t) { serialize_varint_u32_constexpr(it); - auto k_len = pb_value_size(k); - auto v_len = pb_value_size(v); - auto pair_len = key1_size + key2_size + k_len + v_len; + // k must be string or numeric + auto k_val_len = str_numeric_size<0, false>(k); + auto v_val_len = pb_value_size(v, sz_ptr); + auto pair_len = key1_size + key2_size + k_val_len + v_val_len; if constexpr (is_lenprefix_v) { - pair_len += variant_uint32_size(k_len); + pair_len += variant_uint32_size(k_val_len); } if constexpr (is_lenprefix_v) { - pair_len += variant_uint32_size(v_len); + pair_len += variant_uint32_size(v_val_len); } serialize_varint(pair_len, it); // map k and v can't be omitted even if values are empty - encode_pair_value(k, it, k_len); - encode_pair_value(v, it, v_len); + encode_pair_value(k, it, k_val_len, sz_ptr); + encode_pair_value(v, it, v_val_len, sz_ptr); } } else if constexpr (optional_v) { if (!t.has_value()) { return; } - to_pb_impl(*t, it); + to_pb_impl(*t, it, sz_ptr); } else if constexpr (std::is_same_v || std::is_same_v) { @@ -208,8 +209,11 @@ IGUANA_INLINE void to_pb_impl(Type&& t, It&& it) { template IGUANA_INLINE void to_pb(T& t, Stream& out) { - auto byte_len = detail::pb_key_value_size<0>(t); + std::vector size_arr; + auto byte_len = detail::pb_key_value_size<0>(t, size_arr); detail::resize(out, byte_len); - detail::to_pb_impl<0>(t, &out[0]); + auto sz_ptr = size_arr.empty() ? nullptr : &size_arr[0]; + detail::to_pb_impl<0>(t, &out[0], sz_ptr); } + } // namespace iguana diff --git a/include/ylt/standalone/iguana/reflection.hpp b/include/ylt/standalone/iguana/reflection.hpp index c2ff73bdd..cb0ff86a8 100644 --- a/include/ylt/standalone/iguana/reflection.hpp +++ b/include/ylt/standalone/iguana/reflection.hpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include #include @@ -19,6 +20,7 @@ #include "detail/string_stream.hpp" #include "detail/traits.hpp" +#include "enum_reflection.hpp" #include "frozen/string.h" #include "frozen/unordered_map.h" @@ -550,9 +552,88 @@ namespace iguana::detail { #define MAKE_STR_LIST(...) \ MACRO_CONCAT(CON_STR, GET_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__) +template +struct identity {}; + +struct field_info { + size_t offset; + std::string_view type_name; +}; + +struct base { + virtual void to_pb(std::string &str) {} + virtual void from_pb(std::string_view str) {} + virtual std::vector get_fields_name() { return {}; } + virtual iguana::detail::field_info get_field_info(std::string_view name) { + return {}; + } + + template + T &get_field_value(std::string_view name) { + auto info = get_field_info(name); + check_field(name, info); + auto ptr = (((char *)this) + info.offset); + return *((T *)ptr); + } + + template + void set_field_value(std::string_view name, T val) { + auto info = get_field_info(name); + check_field(name, info); + + auto ptr = (((char *)this) + info.offset); + + *((T *)ptr) = std::move(val); + } + virtual ~base() {} + + private: + template + void check_field(std::string_view name, const field_info &info) { + if (info.offset == 0) { + throw std::invalid_argument(std::string(name) + " field not exist "); + } + +#if defined(__clang__) || defined(_MSC_VER) || \ + (defined(__GNUC__) && __GNUC__ > 8) + if (info.type_name != iguana::type_string()) { + std::string str = "type is not match: can not assign "; + str.append(iguana::type_string()); + str.append(" to ").append(info.type_name); + + throw std::invalid_argument(str); + } +#endif + } +}; + +inline std::unordered_map()>> + g_pb_map; + +template +inline bool register_type() { +#if defined(__clang__) || defined(_MSC_VER) || \ + (defined(__GNUC__) && __GNUC__ > 8) + if constexpr (std::is_base_of_v) { + auto it = g_pb_map.emplace(type_string(), [] { + return std::make_shared(); + }); + return it.second; + } + else { + return true; + } +#else + return true; +#endif +} + #define MAKE_META_DATA_IMPL(STRUCT_NAME, ...) \ + static inline bool IGUANA_UNIQUE_VARIABLE(reg_var) = \ + iguana::detail::register_type(); \ [[maybe_unused]] inline static auto iguana_reflect_members( \ - STRUCT_NAME const &) { \ + const iguana::detail::identity &) { \ struct reflect_members { \ constexpr decltype(auto) static apply_impl() { \ return std::make_tuple(__VA_ARGS__); \ @@ -602,7 +683,7 @@ constexpr std::array get_alias_arr(Args... pairs) { #define MAKE_META_DATA_IMPL_ALIAS(STRUCT_NAME, ALIAS, ...) \ [[maybe_unused]] inline static auto iguana_reflect_members( \ - STRUCT_NAME const &) { \ + const iguana::detail::identity &) { \ struct reflect_members { \ constexpr decltype(auto) static apply_impl() { \ return iguana::detail::get_mem_ptr_tp(__VA_ARGS__); \ @@ -622,7 +703,8 @@ constexpr std::array get_alias_arr(Args... pairs) { } #define MAKE_META_DATA_IMPL_EMPTY(STRUCT_NAME) \ - inline auto iguana_reflect_members(STRUCT_NAME const &) { \ + inline auto iguana_reflect_members( \ + const iguana::detail::identity &) { \ struct reflect_members { \ constexpr decltype(auto) static apply_impl() { \ return std::make_tuple(); \ @@ -840,11 +922,7 @@ constexpr inline auto get_members() { STRUCT_NAME, ALIAS, \ std::tuple_size_v, __VA_ARGS__) -#ifdef _MSC_VER #define IGUANA_UNIQUE_VARIABLE(str) MACRO_CONCAT(str, __COUNTER__) -#else -#define IGUANA_UNIQUE_VARIABLE(str) MACRO_CONCAT(str, __LINE__) -#endif template struct iguana_required_struct; #define REQUIRED_IMPL(STRUCT_NAME, N, ...) \ @@ -899,12 +977,6 @@ inline int add_custom_fields(std::string_view key, return 0; } -#ifdef _MSC_VER -#define IGUANA_UNIQUE_VARIABLE(str) MACRO_CONCAT(str, __COUNTER__) -#else -#define IGUANA_UNIQUE_VARIABLE(str) MACRO_CONCAT(str, __LINE__) -#endif - #define CUSTOM_FIELDS_IMPL(STRUCT_NAME, N, ...) \ inline auto IGUANA_UNIQUE_VARIABLE(STRUCT_NAME) = iguana::add_custom_fields( \ #STRUCT_NAME, {MARCO_EXPAND(MACRO_CONCAT(CON_STR, N)(__VA_ARGS__))}); @@ -913,14 +985,16 @@ inline int add_custom_fields(std::string_view key, CUSTOM_FIELDS_IMPL(STRUCT_NAME, GET_ARG_COUNT(__VA_ARGS__), __VA_ARGS__) template -using Reflect_members = decltype(iguana_reflect_members(std::declval())); +using Reflect_members = decltype(iguana_reflect_members( + std::declval>())); template struct is_public_reflection : std::false_type {}; template -struct is_public_reflection< - T, std::void_t()))>> +struct is_public_reflection>()))>> : std::true_type {}; template @@ -932,7 +1006,7 @@ struct is_private_reflection : std::false_type {}; template struct is_private_reflection< T, std::void_t().iguana_reflect_members( - std::declval()))>> : std::true_type {}; + std::declval>()))>> : std::true_type {}; template constexpr bool is_private_reflection_v = is_private_reflection::value; @@ -947,11 +1021,11 @@ struct is_reflection>> template inline auto iguana_reflect_type(const T &t) { - if constexpr (is_public_reflection_v) { - return iguana_reflect_members(t); + if constexpr (is_public_reflection_v>) { + return iguana_reflect_members(iguana::detail::identity{}); } else { - return t.iguana_reflect_members(t); + return t.iguana_reflect_members(iguana::detail::identity{}); } } @@ -1243,7 +1317,8 @@ constexpr void for_each(const std::tuple &t, F &&f, } template -constexpr std::enable_if_t::value> for_each(T &&t, F &&f) { +constexpr std::enable_if_t>::value> for_each( + T &&t, F &&f) { using M = decltype(iguana_reflect_type(std::forward(t))); for_each(M::apply_impl(), std::forward(f), std::make_index_sequence{}); diff --git a/src/struct_pack/benchmark/struct_pb_sample.hpp b/src/struct_pack/benchmark/struct_pb_sample.hpp index eaaa9f092..53ca2fae2 100644 --- a/src/struct_pack/benchmark/struct_pb_sample.hpp +++ b/src/struct_pack/benchmark/struct_pb_sample.hpp @@ -6,7 +6,7 @@ #include "sample.hpp" namespace pb_sample { -struct person : public iguana::pb_base_impl { +struct person : public iguana::base_impl { person() = default; person(int32_t a, std::string b, int c, double d) : id(a), name(std::move(b)), age(c), salary(d) {} @@ -17,14 +17,14 @@ struct person : public iguana::pb_base_impl { }; REFLECTION(person, id, name, age, salary); -struct persons : public iguana::pb_base_impl { +struct persons : public iguana::base_impl { persons() = default; explicit persons(std::vector l) : list(std::move(l)) {} std::vector list; }; REFLECTION(persons, list); -struct rect : public iguana::pb_base_impl { +struct rect : public iguana::base_impl { rect() = default; rect(int32_t a, int32_t b, int32_t c, int32_t d) : x(a), y(b), width(c), height(d) {} @@ -35,14 +35,14 @@ struct rect : public iguana::pb_base_impl { }; REFLECTION(rect, x, y, width, height); -struct rects : public iguana::pb_base_impl { +struct rects : public iguana::base_impl { rects() = default; explicit rects(std::vector l) : list(std::move(l)) {} std::vector list; }; REFLECTION(rects, list); -struct Vec3 : public iguana::pb_base_impl { +struct Vec3 : public iguana::base_impl { Vec3() = default; Vec3(float a, float b, float c) : x(a), y(b), z(c) {} float x; @@ -52,7 +52,7 @@ struct Vec3 : public iguana::pb_base_impl { REFLECTION(Vec3, x, y, z); }; -struct Weapon : public iguana::pb_base_impl { +struct Weapon : public iguana::base_impl { Weapon() = default; Weapon(std::string s, int32_t d) : name(std::move(s)), damage(d) {} std::string name; @@ -62,7 +62,7 @@ REFLECTION(Weapon, name, damage); enum Color : uint8_t { Red, Green, Blue }; -struct Monster : public iguana::pb_base_impl { +struct Monster : public iguana::base_impl { Monster() = default; Monster(Vec3 a, int32_t b, int32_t c, std::string d, std::string e, Color f, std::vector g, Weapon h, std::vector i) {} @@ -79,7 +79,7 @@ struct Monster : public iguana::pb_base_impl { REFLECTION(Monster, pos, mana, hp, name, inventory, color, weapons, equipped, path); -struct Monsters : public iguana::pb_base_impl { +struct Monsters : public iguana::base_impl { Monsters() = default; explicit Monsters(std::vector l) : list(std::move(l)) {} std::vector list; diff --git a/src/struct_pb/examples/main.cpp b/src/struct_pb/examples/main.cpp index 7108b6d23..92a2ce4ba 100644 --- a/src/struct_pb/examples/main.cpp +++ b/src/struct_pb/examples/main.cpp @@ -2,7 +2,7 @@ #include #include -struct my_struct : struct_pb::pb_base_impl { +struct my_struct : struct_pb::base_impl { my_struct() = default; my_struct(int a, bool b, struct_pb::fixed64_t c) : x(a), y(b), z(c) {} int x; @@ -11,7 +11,7 @@ struct my_struct : struct_pb::pb_base_impl { }; REFLECTION(my_struct, x, y, z); -struct nest : struct_pb::pb_base_impl { +struct nest : struct_pb::base_impl { nest() = default; nest(std::string s, my_struct t, int v) : name(std::move(s)), value(t), var(v) {} @@ -21,6 +21,13 @@ struct nest : struct_pb::pb_base_impl { }; REFLECTION(nest, name, value, var); +struct person { + int id; + std::string name; + int age; +}; +REFLECTION(person, id, name, age); + int main() { nest v{"Hi", my_struct{1, false, {3}}, 5}; std::string s; @@ -31,4 +38,27 @@ int main() { assert(v.var == v2.var); assert(v.value.y == v2.value.y); assert(v.value.z == v2.value.z); + + person p{1, "tom", 22}; + std::string str; + struct_pb::to_pb(p, str); + + person p1; + struct_pb::from_pb(p1, str); + assert(p.age == p1.age); + assert(p.name == p1.name); + assert(p.id == p1.id); + + // dynamic reflection + auto t = struct_pb::create_instance("nest"); + auto names = t->get_fields_name(); + bool r = (names == std::vector{"name", "value", "var"}); + assert(r); + + t->set_field_value("name", std::string("tom")); + auto name = t->get_field_value("name"); + assert(name == "tom"); + + auto d = dynamic_cast(t.get()); + assert(d->name == "tom"); } \ No newline at end of file diff --git a/src/struct_pb/tests/main.cpp b/src/struct_pb/tests/main.cpp index 0860f449d..30a3702cd 100644 --- a/src/struct_pb/tests/main.cpp +++ b/src/struct_pb/tests/main.cpp @@ -585,7 +585,7 @@ struct test_pb_st1 PUBLIC(test_pb_st1) { }; REFLECTION(test_pb_st1, x, y, z); -struct test_pb_st2 PUBLIC(test_pb_st2) { +struct test_pb_st2 { test_pb_st2() = default; test_pb_st2(int a, iguana::fixed32_t b, iguana::fixed64_t c) : x(a), y(b), z(c) {} @@ -763,13 +763,78 @@ struct numer_st PUBLIC(numer_st) { }; REFLECTION(numer_st, a, b, c); +TEST_CASE("test reflection") { + { + auto t = iguana::create_instance("nest1"); + std::vector fields_name = t->get_fields_name(); + CHECK(fields_name == std::vector{"name", "value", "var"}); + + my_struct mt{2, true, {42}}; + t->set_field_value("value", mt); + t->set_field_value("name", std::string("test")); + t->set_field_value("var", 41); + nest1 *st = dynamic_cast(t.get()); + auto p = *st; + std::cout << p.name << "\n"; + auto &r0 = t->get_field_value("name"); + CHECK(r0 == "test"); + auto &r = t->get_field_value("var"); + CHECK(r == 41); + auto &r1 = t->get_field_value("value"); + CHECK(r1.x == 2); + } + { + auto t = iguana::create_instance("pair_t"); + t->set_field_value("x", 12); + t->set_field_value("y", 24); + auto &r0 = t->get_field_value("x"); + CHECK(r0 == 12); + auto &r = t->get_field_value("y"); + CHECK(r == 24); + + std::string str; + t->to_pb(str); + + pair_t t1; + t1.from_pb(str); + + pair_t *st = dynamic_cast(t.get()); + CHECK(st->x == t1.x); + CHECK(st->y == t1.y); + } + auto t = iguana::create_instance("numer_st"); + t->set_field_value("a", true); + t->set_field_value("b", double(25)); + t->set_field_value("c", float(42)); + auto &r0 = t->get_field_value("a"); + CHECK(r0); + auto &r = t->get_field_value("b"); + CHECK(r == 25); + auto &r1 = t->get_field_value("c"); + CHECK(r1 == 42); + + numer_st *st = dynamic_cast(t.get()); + CHECK(st->a == true); + CHECK(st->b == 25); + CHECK(st->c == 42); + + std::string str; + t->to_pb(str); + + numer_st t1; + t1.from_pb(str); + + CHECK(st->a == t1.a); + CHECK(st->b == t1.b); + CHECK(st->c == t1.c); +} + TEST_CASE("test struct_pb") { { my_space::inner_struct inner{41, 42, 43}; std::string str; iguana::to_pb(inner, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(inner)); my_space::inner_struct inner1; iguana::from_pb(inner1, str); @@ -782,7 +847,6 @@ TEST_CASE("test struct_pb") { test_pb_st1 st1{41, {42}, {43}}; std::string str; iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st1 st2; iguana::from_pb(st2, str); @@ -795,7 +859,6 @@ TEST_CASE("test struct_pb") { test_pb_st2 st1{41, {42}, {43}}; std::string str; iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st2 st2; iguana::from_pb(st2, str); @@ -805,7 +868,6 @@ TEST_CASE("test struct_pb") { test_pb_st3 st1{41, {42}, {43}}; std::string str; iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st3 st2; iguana::from_pb(st2, str); @@ -815,7 +877,6 @@ TEST_CASE("test struct_pb") { test_pb_st4 st1{41, "it is a test"}; std::string str; iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st4 st2; iguana::from_pb(st2, str); @@ -826,7 +887,6 @@ TEST_CASE("test struct_pb") { test_pb_st5 st1{41, "it is a test"}; std::string str; iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st5 st2; iguana::from_pb(st2, str); @@ -837,7 +897,6 @@ TEST_CASE("test struct_pb") { test_pb_st6 st1{41, "it is a test"}; std::string str; iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st6 st2; iguana::from_pb(st2, str); @@ -867,7 +926,6 @@ TEST_CASE("test struct_pb") { test_pb_st9 st1{1, {2, 4, 6}, "test"}; std::string str; iguana::to_pb(st1, str); - CHECK(str.size() == iguana::detail::pb_key_value_size<0>(st1)); test_pb_st9 st2; iguana::from_pb(st2, str); @@ -900,7 +958,7 @@ TEST_CASE("test struct_pb") { std::string s; m->to_pb(s); - std::shared_ptr t = m; + std::shared_ptr t = m; std::string str; t->to_pb(str); diff --git a/src/struct_pb/tests/unittest_proto3.h b/src/struct_pb/tests/unittest_proto3.h index e1761ec60..82db6416d 100644 --- a/src/struct_pb/tests/unittest_proto3.h +++ b/src/struct_pb/tests/unittest_proto3.h @@ -6,7 +6,7 @@ #include "unittest_proto3.pb.h" #endif -#define PUBLIC(T) : public iguana::pb_base_impl +#define PUBLIC(T) : public iguana::base_impl // define the struct as msg in proto namespace stpb { @@ -230,7 +230,7 @@ struct simple_t2 PUBLIC(simple_t2) { }; REFLECTION(simple_t2, a, b, c, d, str); -struct person PUBLIC(person) { +struct person { person() = default; person(int32_t a, std::string b, int c, double d) : id(a), name(std::move(b)), age(c), salary(d) {} diff --git a/website/docs/en/struct_pb/struct_pb_intro.md b/website/docs/en/struct_pb/struct_pb_intro.md index 0929f4892..3dc6012b8 100644 --- a/website/docs/en/struct_pb/struct_pb_intro.md +++ b/website/docs/en/struct_pb/struct_pb_intro.md @@ -14,14 +14,14 @@ Utilize inline, zero copy, compile-time compute to optimize performance. ```cpp #include -struct my_struct : struct_pb::pb_base_impl { +struct my_struct { int x; bool y; struct_pb::fixed64_t z; }; REFLECTION(my_struct, x, y, z); -struct nest : struct_pb::pb_base_impl { +struct nest { std::string name; my_struct value; int var; @@ -32,7 +32,7 @@ REFLECTION(nest, name, value, var); ### serialization and deserialization ```cpp int main() { - nest v{0, "Hi", {0, 1, false, 3}, 5}, v2{}; + nest v{"Hi", {1, false, {3}}, 5}, v2{}; std::string s; struct_pb::to_pb(v, s); struct_pb::from_pb(v2, s); @@ -56,6 +56,60 @@ message nest { } ``` +## dynamic reflection +features: +- create instance by object's name; +- get all fields name from an object; +- get/set field value by filed name and instance; + +### create instance by object's name +```cpp +struct my_struct { + int x; + bool y; + iguana::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); + +struct nest1 : public iguana::base_imple { + nest1() = default; + nest1(std::string s, my_struct t, int d) + : name(std::move(s)), value(t), var(d) {} + std::string name; + my_struct value; + int var; +}; +REFLECTION(nest1, name, value, var); +``` + +```cpp +std::shared_ptr t = struct_pb::create_instance("nest1"); +``` +"create instance by object's name" require the struct inherited from struct_pb::base_impl. If not inherited,create_instance will throw exception. + +### get/set field value by filed name and instance +```cpp + auto t = iguana::create_instance("nest1"); + + std::vector fields_name = t->get_fields_name(); + CHECK(fields_name == std::vector{"name", "value", "var"}); + + my_struct mt{2, true, {42}}; + t->set_field_value("value", mt); + t->set_field_value("name", std::string("test")); + t->set_field_value("var", 41); + nest1 *st = dynamic_cast(t.get()); + auto p = *st; + std::cout << p.name << "\n"; + auto &r0 = t->get_field_value("name"); + CHECK(r0 == "test"); + auto &r = t->get_field_value("var"); + CHECK(r == 41); + auto &r1 = t->get_field_value("value"); + CHECK(r1.x == 2); +``` +“set field value by filed name and instance” require the setting value type is same with filed type, don't allow explicit transform, otherwise thrwo std::exception. + ## benchmark monster case: @@ -106,10 +160,10 @@ oneof -> `std::variant <...>` - only support proto3, not support proto2 now; - don't support reflection now; - don't support unkonwn fields; -- struct must inherited from pb_base_impl; +- struct must inherited from base_impl; ## roadmap - support proto2; - support reflection; - support unkonwn fields; -- no need inheriting from pb_base_impl; +- no need inheriting from base_impl; diff --git a/website/docs/zh/struct_pb/struct_pb_intro.md b/website/docs/zh/struct_pb/struct_pb_intro.md index 2e61bdc85..1e1f7113b 100644 --- a/website/docs/zh/struct_pb/struct_pb_intro.md +++ b/website/docs/zh/struct_pb/struct_pb_intro.md @@ -11,14 +11,14 @@ struct_pb 是基于C++17 开发的高性能、易用、header only的protobuf格 ```cpp #include -struct my_struct : struct_pb::pb_base_impl { +struct my_struct : struct_pb::base_impl { int x; bool y; struct_pb::fixed64_t z; }; REFLECTION(my_struct, x, y, z); -struct nest : struct_pb::pb_base_impl { +struct nest : struct_pb::base_impl { std::string name; my_struct value; int var; @@ -29,7 +29,7 @@ REFLECTION(nest, name, value, var); ### 序列化 ```cpp int main() { - nest v{0, "Hi", {0, 1, false, 3}, 5}, v2{}; + nest v{"Hi", {1, false, {3}}, 5}, v2{}; std::string s; struct_pb::to_pb(v, s); struct_pb::from_pb(v2, s); @@ -53,6 +53,62 @@ message nest { } ``` +## 动态反射 +特性: +- 根据对象名称创建实例; +- 获取对象的所有字段名; +- 根据对象实例和字段名获取或设置字段的值 + +### 根据名称创建对象 +```cpp +struct my_struct { + int x; + bool y; + iguana::fixed64_t z; +}; +REFLECTION(my_struct, x, y, z); + +struct nest1 : public iguana::base_imple { + nest1() = default; + nest1(std::string s, my_struct t, int d) + : name(std::move(s)), value(t), var(d) {} + std::string name; + my_struct value; + int var; +}; +REFLECTION(nest1, name, value, var); +``` + +```cpp +std::shared_ptr t = iguana::create_instance("nest1"); +``` +根据对象nest1创建了实例,返回的是基类指针。 + +“根据对象名称创建实例” 要求对象必须从iguana::base_impl 派生,如果没有派生则创建实例会抛异常。 + +### 根据名称设置字段的值 +```cpp + auto t = iguana::create_instance("nest1"); + + std::vector fields_name = t->get_fields_name(); + CHECK(fields_name == std::vector{"name", "value", "var"}); + + my_struct mt{2, true, {42}}; + t->set_field_value("value", mt); + t->set_field_value("name", std::string("test")); + t->set_field_value("var", 41); + nest1 *st = dynamic_cast(t.get()); + auto p = *st; + std::cout << p.name << "\n"; + auto &r0 = t->get_field_value("name"); + CHECK(r0 == "test"); + auto &r = t->get_field_value("var"); + CHECK(r == 41); + auto &r1 = t->get_field_value("value"); + CHECK(r1.x == 2); +``` +“根据对象实例和字段名获取或设置字段的值” 如果字段名不存在则会抛异常;如果设置的值类型和结构体字段类型不相同则会抛异常;需要类型完全一样,不允许隐式转换。比如字段类型是double,但是设置字段的值类型是int也会抛异常,必须显式传double;如果字段类型是std::string, 设置值类型是const char * 同样会报错;如果字段类型是int32_t, 设置值类型是uint_8也会抛异常,因为类型不相同。 + ## benchmark 在benchmark monster场景下,struct_pb 性能比protobuf 更好,序列化速度是protobuf的2.4倍,反序列化是protobuf的3.4倍。详情可以自行运行struct_pack 中的benchmark复现结果。 @@ -96,10 +152,10 @@ oneof -> `std::variant <...>` - 目前还只支持proto3,不支持proto2; - 目前还没支持反射; - 还没支持unkonwn字段; -- struct_pb 结构体必须派生于pb_base_impl +- struct_pb 结构体必须派生于base_impl ## roadmap - 支持proto2; - 支持反射; - 支持unkonwn字段; -- 去除struct_pb 结构体必须派生于pb_base_impl的约束; +- 去除struct_pb 结构体必须派生于base_impl的约束; From 21b217f07e84589e48364f07257f1529bb770ba9 Mon Sep 17 00:00:00 2001 From: qicosmos Date: Tue, 28 May 2024 14:10:43 +0800 Subject: [PATCH 26/26] update --- src/struct_pb/examples/main.cpp | 6 +++++- src/struct_pb/tests/main.cpp | 5 +++++ website/docs/en/struct_pb/struct_pb_intro.md | 8 +++++++- website/docs/zh/struct_pb/struct_pb_intro.md | 6 ++++++ 4 files changed, 23 insertions(+), 2 deletions(-) diff --git a/src/struct_pb/examples/main.cpp b/src/struct_pb/examples/main.cpp index 92a2ce4ba..6b631d608 100644 --- a/src/struct_pb/examples/main.cpp +++ b/src/struct_pb/examples/main.cpp @@ -59,6 +59,10 @@ int main() { auto name = t->get_field_value("name"); assert(name == "tom"); - auto d = dynamic_cast(t.get()); + auto d = dynamic_cast(t.get()); assert(d->name == "tom"); + + t->set_field_value("name", "hello"); + auto &field_name = t->get_field_value("name"); + assert(field_name == "hello"); } \ No newline at end of file diff --git a/src/struct_pb/tests/main.cpp b/src/struct_pb/tests/main.cpp index 30a3702cd..58098b3a2 100644 --- a/src/struct_pb/tests/main.cpp +++ b/src/struct_pb/tests/main.cpp @@ -782,6 +782,11 @@ TEST_CASE("test reflection") { CHECK(r == 41); auto &r1 = t->get_field_value("value"); CHECK(r1.x == 2); + + t->set_field_value("name", "hello"); + auto &s = t->get_field_value("name"); + CHECK(s == "hello"); + CHECK_THROWS_AS(t->set_field_value("name", 42), std::invalid_argument); } { auto t = iguana::create_instance("pair_t"); diff --git a/website/docs/en/struct_pb/struct_pb_intro.md b/website/docs/en/struct_pb/struct_pb_intro.md index 3dc6012b8..26f4de8e5 100644 --- a/website/docs/en/struct_pb/struct_pb_intro.md +++ b/website/docs/en/struct_pb/struct_pb_intro.md @@ -108,7 +108,13 @@ std::shared_ptr t = struct_pb::create_instance("nest1"); auto &r1 = t->get_field_value("value"); CHECK(r1.x == 2); ``` -“set field value by filed name and instance” require the setting value type is same with filed type, don't allow explicit transform, otherwise thrwo std::exception. +“set field value by filed name and instance” require the setting value type is same with filed type, don't allow explicit transform, otherwise throw exception. + +also support set field value with its type: +```cpp +t->set_field_value("name", "test"); +``` +implicit set field type can support implicit assign field value. If the field type is not the real field type, will throw exception. ## benchmark diff --git a/website/docs/zh/struct_pb/struct_pb_intro.md b/website/docs/zh/struct_pb/struct_pb_intro.md index 1e1f7113b..0e1292fa3 100644 --- a/website/docs/zh/struct_pb/struct_pb_intro.md +++ b/website/docs/zh/struct_pb/struct_pb_intro.md @@ -109,6 +109,12 @@ std::shared_ptr t = iguana::create_instance("nest1"); ``` “根据对象实例和字段名获取或设置字段的值” 如果字段名不存在则会抛异常;如果设置的值类型和结构体字段类型不相同则会抛异常;需要类型完全一样,不允许隐式转换。比如字段类型是double,但是设置字段的值类型是int也会抛异常,必须显式传double;如果字段类型是std::string, 设置值类型是const char * 同样会报错;如果字段类型是int32_t, 设置值类型是uint_8也会抛异常,因为类型不相同。 +设置字段值时也可以显式指定字段类型: +```cpp +t->set_field_value("name", "test"); +``` +这种方式则不要求设置值的类型和字段类型完全一样,只要能赋值成功即可。如果显式指定的字段类型不是实际的字段类型时也会抛异常。 + ## benchmark 在benchmark monster场景下,struct_pb 性能比protobuf 更好,序列化速度是protobuf的2.4倍,反序列化是protobuf的3.4倍。详情可以自行运行struct_pack 中的benchmark复现结果。