#pragma once #include #include #include #include #include #include #include #include #include #include #include "util.hpp" #ifdef YLT_USE_CXX26_REFLECTION #include #include "ylt/reflection/reflect26_core.hpp" #endif namespace iguana { struct iguana_adl_t {}; #if defined(__GNUC__) && !defined(__clang__) #define IGUANA_DYNAMIC_NOINLINE __attribute__((noinline)) #else #define IGUANA_DYNAMIC_NOINLINE #endif struct pb_field_annotation { size_t value; }; constexpr pb_field_annotation pb_field(size_t field_no) { return {field_no}; } struct pb_zigzag_annotation {}; struct pb_fixed_annotation {}; struct pb_bytes_annotation {}; template struct pb_oneof_annotation { static constexpr std::array values{Ns...}; }; struct pb_timestamp_annotation {}; struct pb_duration_annotation {}; struct pb_optional_annotation {}; struct pb_unknown_fields_annotation {}; inline constexpr pb_zigzag_annotation pb_zigzag{}; inline constexpr pb_fixed_annotation pb_fixed{}; inline constexpr pb_bytes_annotation pb_bytes{}; template inline constexpr pb_oneof_annotation pb_oneof{}; template inline constexpr pb_oneof_annotation oneof{}; inline constexpr pb_timestamp_annotation pb_as_timestamp{}; inline constexpr pb_timestamp_annotation as_timestamp{}; inline constexpr pb_duration_annotation pb_as_duration{}; inline constexpr pb_duration_annotation as_duration{}; inline constexpr pb_optional_annotation pb_optional{}; inline constexpr pb_unknown_fields_annotation pb_unknown_fields{}; struct pb_timestamp { int64_t seconds{}; int32_t nanos{}; pb_timestamp() = default; explicit pb_timestamp(std::chrono::system_clock::time_point value) { using namespace std::chrono; auto total = duration_cast(value.time_since_epoch()); auto sec = duration_cast(total); auto rem = total - sec; if (rem.count() < 0) { --sec; rem += std::chrono::seconds{1}; } seconds = sec.count(); nanos = static_cast(rem.count()); } operator std::chrono::system_clock::time_point() const { using clock_duration = std::chrono::system_clock::duration; return std::chrono::system_clock::time_point{ std::chrono::duration_cast( std::chrono::seconds{seconds} + std::chrono::nanoseconds{nanos})}; } }; struct pb_duration { int64_t seconds{}; int32_t nanos{}; pb_duration() = default; explicit pb_duration(std::chrono::nanoseconds value) { auto sec = std::chrono::duration_cast(value); auto rem = value - sec; seconds = sec.count(); nanos = static_cast(rem.count()); } operator std::chrono::nanoseconds() const { return std::chrono::seconds{seconds} + std::chrono::nanoseconds{nanos}; } }; YLT_REFL(pb_timestamp, seconds, nanos); YLT_REFL(pb_duration, seconds, nanos); namespace detail { #ifdef YLT_USE_CXX26_REFLECTION namespace reflect26 = ylt::reflection::reflect26; #endif template struct identity {}; struct field_info { size_t offset; std::string_view type_name; }; struct base { virtual void to_pb(std::string& str) const {} virtual void from_pb(std::string_view str) {} virtual void to_xml(std::string& str) const {} virtual void from_xml(std::string_view str) {} virtual void to_json(std::string& str) const {} virtual void from_json(std::string_view str) {} virtual void to_yaml(std::string& str) const {} virtual void from_yaml(std::string_view str) {} virtual std::vector get_fields_name() const { return {}; } virtual std::any get_field_any(std::string_view name) const { return {}; } virtual iguana::detail::field_info get_field_info( std::string_view name) const { return {}; } template T& get_field_value(std::string_view name) { auto info = get_field_info(name); check_field(name, info); auto ptr = static_cast(object_ptr()) + info.offset; return *((T*)ptr); } template IGUANA_DYNAMIC_NOINLINE void set_field_value(std::string_view name, T val) { auto info = get_field_info(name); check_field(name, info); auto ptr = static_cast(object_ptr()) + info.offset; static_assert(std::is_constructible_v, "can not assign"); *((FiledType*)ptr) = std::move(val); } virtual ~base() {} protected: virtual void* object_ptr() { return this; } virtual const void* object_ptr() const { return this; } 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 struct field_type_t; template struct field_type_t> { using value_type = std::variant; }; template constexpr size_t count_variant_size() { if constexpr (is_variant::value) { using first_type = std::variant_alternative_t<0, T>; if constexpr (std::is_same_v) { return std::variant_size_v - 1; } else { 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 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 struct is_custom_reflection : std::false_type {}; template struct is_custom_reflection< T, std::void_t()))>> : std::true_type {}; template inline constexpr bool is_custom_reflection_v = is_custom_reflection>::value; // owner_type: parant type, value_type: member value type, SubType: subtype from // variant template struct pb_field_t { using owner_type = ylt::reflection::remove_cvref_t; using value_type = Value; using sub_type = ElementType; using wire_value_type = WireValue; using wire_sub_type = WireElement; // constexpr pb_field_t() = default; auto& value(owner_type& value) const { auto member_ptr = (value_type*)((char*)(&value) + offset); return *member_ptr; } auto const& value(const owner_type& value) const { auto member_ptr = (value_type*)((char*)(&value) + offset); return *member_ptr; } size_t offset; std::string_view field_name; inline static constexpr uint32_t field_no = FieldNo; inline static constexpr bool bytes_schema = BytesSchema; inline static constexpr bool timestamp_schema = TimestampSchema; inline static constexpr bool duration_schema = DurationSchema; inline static constexpr bool optional_schema = OptionalSchema; inline static constexpr bool zigzag_schema = ZigzagSchema; inline static constexpr bool fixed_schema = FixedSchema; }; template struct pb_field_no; template struct pb_field_no< pb_field_t> { static constexpr size_t value = FieldNo; }; constexpr bool is_valid_pb_field_no(size_t field_no) { constexpr size_t max_field_no = (size_t{1} << 29) - 1; return field_no > 0 && field_no <= max_field_no && (field_no < 19000 || field_no > 19999); } template constexpr bool has_invalid_field_nos(std::index_sequence) { return ((!is_valid_pb_field_no( pb_field_no>::value)) || ...); } template constexpr bool has_duplicate_field_nos(std::index_sequence) { if constexpr (sizeof...(I) == 0) { return false; } else { constexpr size_t nos[] = { pb_field_no>::value...}; constexpr size_t N = sizeof...(I); for (size_t i = 0; i < N; ++i) for (size_t j = i + 1; j < N; ++j) if (nos[i] == nos[j]) return true; return false; } } template constexpr void validate_pb_members_tuple() { constexpr size_t N = std::tuple_size_v; static_assert(!has_invalid_field_nos(std::make_index_sequence{}), "protobuf field numbers must be in [1, 2^29 - 1] and not in " "[19000, 19999]"); static_assert(!has_duplicate_field_nos(std::make_index_sequence{}), "duplicate proto field numbers detected"); } template constexpr inline auto get_field_no_impl(Array& arr, size_t& index) { arr[I] = index; if constexpr (is_variant::value) { constexpr size_t variant_size = count_variant_size(); index += variant_size; } else { index++; return; } } template inline constexpr auto get_field_no(std::index_sequence) { std::array arr{}; size_t index = 0; (get_field_no_impl< I, ylt::reflection::remove_cvref_t>>( arr, index), ...); return arr; } template constexpr size_t pb_variant_first_case_index() { using first_type = std::variant_alternative_t<0, Variant>; if constexpr (std::is_same_v) { return 1; } else { return 0; } } template constexpr size_t pb_variant_case_count() { return std::variant_size_v - pb_variant_first_case_index(); } template constexpr inline auto build_pb_variant_fields(size_t offset, std::string_view name, std::index_sequence) { return std::tuple( pb_field_t>{offset, name}...); } template constexpr inline auto build_pb_oneof_fields_impl(size_t offset, std::string_view name, std::index_sequence) { using U = ylt::reflection::remove_cvref_t; using value_type = ylt::reflection::remove_cvref_t; return std::tuple( pb_field_t>{offset, name}...); } template constexpr inline auto build_pb_oneof_fields(size_t offset, std::string_view name) { using value_type = ylt::reflection::remove_cvref_t; if constexpr (!is_variant::value) { static_assert(is_variant::value, "pb_oneof_field member must be std::variant"); return std::tuple<>{}; } else if constexpr (!std::is_same_v, std::monostate>) { static_assert(std::is_same_v, std::monostate>, "pb_oneof_field member must start with std::monostate"); return std::tuple<>{}; } else if constexpr (sizeof...(FieldNos) != pb_variant_case_count()) { static_assert(sizeof...(FieldNos) == pb_variant_case_count(), "pb_oneof_field field number count must match variant " "alternatives excluding std::monostate"); return std::tuple<>{}; } else { static_assert( (is_valid_pb_field_no(FieldNos) && ...), "protobuf oneof field numbers must be in [1, 2^29 - 1] and not in " "[19000, 19999]"); constexpr size_t first = pb_variant_first_case_index(); return build_pb_oneof_fields_impl( offset, name, std::make_index_sequence{}); } } template constexpr inline auto build_pb_fields_impl(size_t offset, std::string_view name) { using value_type = ylt::reflection::remove_cvref_t; using wire_value_type = ylt::reflection::remove_cvref_t; using U = std::remove_reference_t; if constexpr (is_variant::value) { constexpr size_t first = pb_variant_first_case_index(); constexpr size_t variant_size = pb_variant_case_count(); return build_pb_variant_fields( offset, name, std::make_index_sequence{}); } else { return std::tuple( pb_field_t{ offset, name}); } } template struct pb_wire_type_selector { using type = T; }; template <> struct pb_wire_type_selector { using type = iguana::sint32_t; }; template <> struct pb_wire_type_selector { using type = iguana::sint64_t; }; template <> struct pb_wire_type_selector { using type = iguana::fixed32_t; }; template <> struct pb_wire_type_selector { using type = iguana::fixed64_t; }; template <> struct pb_wire_type_selector { using type = iguana::sfixed32_t; }; template <> struct pb_wire_type_selector { using type = iguana::sfixed64_t; }; template struct pb_wire_type_selector> { using type = std::optional>::type>; }; template struct pb_wire_type_selector> { using type = std::vector>::type>; }; template struct pb_annotation_leaf_type { using type = ylt::reflection::remove_cvref_t; }; template struct pb_annotation_leaf_type> { using type = ylt::reflection::remove_cvref_t; }; template struct pb_annotation_leaf_type> { using type = ylt::reflection::remove_cvref_t; }; template using pb_annotation_leaf_type_t = typename pb_annotation_leaf_type>::type; template struct is_pb_zigzag_option : std::false_type {}; template <> struct is_pb_zigzag_option : std::true_type {}; template struct is_pb_fixed_option : std::false_type {}; template <> struct is_pb_fixed_option : std::true_type {}; template struct is_pb_bytes_option : std::false_type {}; template <> struct is_pb_bytes_option : std::true_type {}; template struct is_pb_timestamp_option : std::false_type {}; template <> struct is_pb_timestamp_option : std::true_type {}; template struct is_pb_duration_option : std::false_type {}; template <> struct is_pb_duration_option : std::true_type { }; template struct is_pb_optional_option : std::false_type {}; template <> struct is_pb_optional_option : std::true_type { }; template struct pb_schema_options { static constexpr bool bytes = (is_pb_bytes_option>::value || ...); static constexpr bool timestamp = (is_pb_timestamp_option>::value || ...); static constexpr bool duration = (is_pb_duration_option>::value || ...); static constexpr bool optional = (is_pb_optional_option>::value || ...); static constexpr bool zigzag = (is_pb_zigzag_option>::value || ...); static constexpr bool fixed = (is_pb_fixed_option>::value || ...); }; template struct pb_unknown_fields_t { using owner_type = ylt::reflection::remove_cvref_t; using value_type = Value; auto& value(owner_type& value) const { auto member_ptr = (value_type*)((char*)(&value) + offset); return *member_ptr; } auto const& value(const owner_type& value) const { auto member_ptr = (value_type*)((char*)(&value) + offset); return *member_ptr; } size_t offset; std::string_view field_name; }; template struct is_pb_unknown_fields_descriptor : std::false_type {}; template struct is_pb_unknown_fields_descriptor> : std::true_type {}; template inline constexpr bool is_pb_unknown_fields_descriptor_v = is_pb_unknown_fields_descriptor>::value; template IGUANA_INLINE auto pb_member_tuple_item(T&& value) { if constexpr (is_pb_unknown_fields_descriptor_v) { return std::tuple<>{}; } else { return std::make_tuple(std::forward(value)); } } template IGUANA_INLINE auto filter_pb_member_tuple_impl(Tuple&& tp, std::index_sequence) { return std::tuple_cat( pb_member_tuple_item(std::get(std::forward(tp)))...); } template IGUANA_INLINE auto filter_pb_member_tuple(Tuple&& tp) { using tuple_type = ylt::reflection::remove_cvref_t; return filter_pb_member_tuple_impl( std::forward(tp), std::make_index_sequence>{}); } template constexpr size_t pb_unknown_fields_count_tuple(std::index_sequence) { return ((is_pb_unknown_fields_descriptor_v> ? size_t{1} : size_t{0}) + ...); } template constexpr size_t pb_unknown_fields_count_tuple() { constexpr size_t N = std::tuple_size_v; if constexpr (N == 0) { return 0; } else { return pb_unknown_fields_count_tuple(std::make_index_sequence{}); } } template IGUANA_INLINE void visit_pb_unknown_field(T&& t, Field&& field, Func&& func) { using field_type = ylt::reflection::remove_cvref_t; if constexpr (is_pb_unknown_fields_descriptor_v) { using value_type = typename field_type::value_type; static_assert(std::is_same_v, "pb_unknown_fields member must be std::string"); func(field.value(t)); } } template IGUANA_INLINE void visit_pb_unknown_fields_tuple(T&& t, Tuple&& tp, Func&& func, std::index_sequence) { (visit_pb_unknown_field(t, std::get(tp), func), ...); } template IGUANA_INLINE void visit_pb_unknown_fields_custom(T&& t, Func&& func) { using U = ylt::reflection::remove_cvref_t; if constexpr (is_custom_reflection_v) { auto tp = get_members_impl((U*)nullptr); using Tuple = ylt::reflection::remove_cvref_t; static_assert(pb_unknown_fields_count_tuple() <= 1, "only one pb_unknown_fields member is supported"); visit_pb_unknown_fields_tuple( t, tp, std::forward(func), std::make_index_sequence>{}); } } #ifdef YLT_USE_CXX26_REFLECTION template struct is_pb_field_annotation : std::false_type {}; template <> struct is_pb_field_annotation : std::true_type {}; template struct is_pb_zigzag_annotation : std::false_type {}; template <> struct is_pb_zigzag_annotation : std::true_type { }; template struct is_pb_fixed_annotation : std::false_type {}; template <> struct is_pb_fixed_annotation : std::true_type {}; template struct is_pb_bytes_annotation : std::false_type {}; template <> struct is_pb_bytes_annotation : std::true_type {}; template struct is_pb_oneof_annotation : std::false_type {}; template struct is_pb_oneof_annotation> : std::true_type {}; template struct is_pb_timestamp_annotation : std::false_type {}; template <> struct is_pb_timestamp_annotation : std::true_type {}; template struct is_pb_duration_annotation : std::false_type {}; template <> struct is_pb_duration_annotation : std::true_type {}; template struct is_pb_optional_annotation : std::false_type {}; template <> struct is_pb_optional_annotation : std::true_type {}; template struct is_pb_unknown_fields_annotation : std::false_type {}; template <> struct is_pb_unknown_fields_annotation : std::true_type {}; template consteval bool has_pb_zigzag() { return reflect26::has_annotation(); } template consteval bool has_pb_fixed() { return reflect26::has_annotation(); } template consteval bool has_pb_unknown_fields() { return reflect26::has_annotation(); } template consteval bool has_pb_bytes() { return reflect26::has_annotation(); } template consteval bool has_pb_oneof() { return reflect26::has_annotation(); } template consteval bool has_pb_as_timestamp() { return reflect26::has_annotation(); } template consteval bool has_pb_as_duration() { return reflect26::has_annotation(); } template consteval bool has_pb_optional() { return reflect26::has_annotation(); } template consteval size_t pb_oneof_count() { static constexpr auto annotations = reflect26::annotations_array(); template for (constexpr auto annotation : annotations) { using annotation_t = reflect26::remove_cvref_meta_type_t; if constexpr (is_pb_oneof_annotation::value) { return annotation_t::values.size(); } } return 0; } template consteval size_t pb_oneof_field_no() { static constexpr auto annotations = reflect26::annotations_array(); template for (constexpr auto annotation : annotations) { using annotation_t = reflect26::remove_cvref_meta_type_t; if constexpr (is_pb_oneof_annotation::value) { constexpr auto field_no = annotation_t::values[I]; static_assert(field_no > 0, "protobuf oneof field number must be positive"); static_assert(field_no <= ((size_t{1} << 29) - 1), "protobuf oneof field number exceeds 2^29 - 1"); static_assert(field_no < 19000 || field_no > 19999, "protobuf oneof field number is in reserved range " "[19000, 19999]"); return field_no; } } return 0; } template struct pb_annotation_wire_type { using value_type = ylt::reflection::remove_cvref_t; static_assert(!(has_pb_zigzag() && has_pb_fixed()), "protobuf field can't use both pb_zigzag and pb_fixed"); using type = typename pb_wire_type_selector(), has_pb_fixed(), value_type>::type; }; template consteval size_t pb_unknown_fields_count() { using U = ylt::reflection::remove_cvref_t; static constexpr auto members = reflect26::data_members_array(); size_t count = 0; template for (constexpr auto member : members) { if constexpr (has_pb_unknown_fields()) { ++count; } } return count; } template IGUANA_INLINE void visit_pb_unknown_fields_annotation(T&& t, Func&& func) { using U = ylt::reflection::remove_cvref_t; static_assert(pb_unknown_fields_count() <= 1, "only one pb_unknown_fields member is supported"); static constexpr auto members = reflect26::data_members_array(); template for (constexpr auto member : members) { if constexpr (has_pb_unknown_fields()) { using field_type = ylt::reflection::remove_cvref_t; static_assert(std::is_same_v, "pb_unknown_fields member must be std::string"); func(t.[:member:]); } } } template consteval size_t pb_field_width() { using U = ylt::reflection::remove_cvref_t; static constexpr auto members = reflect26::data_members_array(); if constexpr (has_pb_unknown_fields()) { return 0; } else { using value_type = reflect26::remove_cvref_meta_type_t; if constexpr (is_variant::value) { if constexpr (has_pb_oneof()) { return pb_oneof_count(); } else { return pb_variant_case_count(); } } else { return 1; } } } template consteval size_t pb_default_field_index() { if constexpr (I == 0) { return 0; } else { return pb_default_field_index() + pb_field_width(); } } template consteval size_t pb_annotation_field_no() { static constexpr auto annotations = reflect26::annotations_array(); template for (constexpr auto annotation : annotations) { using annotation_t = reflect26::remove_cvref_meta_type_t; if constexpr (is_pb_field_annotation::value) { constexpr auto field_no = std::meta::extract(annotation).value; static_assert(field_no > 0, "protobuf field number must be positive"); static_assert(field_no <= ((size_t{1} << 29) - 1), "protobuf field number exceeds 2^29 - 1"); static_assert(field_no < 19000 || field_no > 19999, "protobuf field number is in reserved range " "[19000, 19999]"); return field_no; } } return 0; } template consteval size_t pb_field_index() { using U = ylt::reflection::remove_cvref_t; static constexpr auto members = reflect26::data_members_array(); if constexpr (I < members.size()) { constexpr auto field_no = pb_annotation_field_no(); if constexpr (field_no > 0) { return field_no - 1; } } return DefaultIndex; } template struct pb_field_value_type { using U = ylt::reflection::remove_cvref_t; static constexpr auto members = reflect26::data_members_array(); using type = typename pb_annotation_wire_type::type; }; template constexpr inline auto build_pb_annotation_oneof_fields( size_t offset, std::string_view name, std::index_sequence) { using U = ylt::reflection::remove_cvref_t; using value_type = ylt::reflection::remove_cvref_t; constexpr size_t first = pb_variant_first_case_index(); return std::tuple( pb_field_t(), std::variant_alternative_t>{offset, name}...); } template inline auto build_pb_annotation_field(const Array& offset_arr, std::string_view name) { using U = ylt::reflection::remove_cvref_t; static constexpr auto members = reflect26::data_members_array(); if constexpr (has_pb_unknown_fields()) { using value_type = ylt::reflection::remove_cvref_t; static_assert(std::is_same_v, "pb_unknown_fields member must be std::string"); return std::tuple<>{}; } else { constexpr size_t default_index = pb_default_field_index(); using value_type = ylt::reflection::remove_cvref_t; using annotation_leaf_type = pb_annotation_leaf_type_t; if constexpr (has_pb_oneof()) { static_assert(is_variant::value, "pb_oneof member must be std::variant"); static_assert(std::is_same_v, std::monostate>, "pb_oneof member must start with std::monostate"); static_assert( pb_oneof_count() == pb_variant_case_count(), "pb_oneof field number count must match variant " "alternatives excluding std::monostate"); return build_pb_annotation_oneof_fields( offset_arr[I], name, std::make_index_sequence()>{}); } else { static_assert(!(has_pb_as_timestamp() && has_pb_as_duration()), "protobuf field can't use both pb_as_timestamp and " "pb_as_duration"); static_assert(!has_pb_as_timestamp() || std::is_same_v, "pb_as_timestamp member must be " "std::chrono::system_clock::time_point, or optional/vector " "of that type"); static_assert( !has_pb_as_duration() || std::is_same_v, "pb_as_duration member must be std::chrono::nanoseconds, " "or optional/vector of that type"); static_assert(!has_pb_bytes() || std::is_same_v || std::is_same_v, "pb_bytes member must be std::string, std::string_view, " "or optional/vector of that type"); static_assert(!has_pb_optional() || optional_v, "pb_optional member must be std::optional"); static_assert(!has_pb_zigzag() || std::is_same_v || std::is_same_v, "pb_zigzag member must be int32_t/int64_t, or " "optional/vector of that type"); static_assert(!has_pb_fixed() || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v, "pb_fixed member must be 32/64-bit int, or " "optional/vector of that type"); return build_pb_fields_impl< T, pb_field_index(), ValueType, has_pb_bytes(), has_pb_as_timestamp(), has_pb_as_duration(), has_pb_optional(), has_pb_zigzag(), has_pb_fixed(), typename pb_field_value_type::type>(offset_arr[I], name); } } } #endif template IGUANA_INLINE void visit_pb_unknown_fields(T&& t, Func&& func) { using U = ylt::reflection::remove_cvref_t; if constexpr (is_custom_reflection_v) { visit_pb_unknown_fields_custom(t, std::forward(func)); } #ifdef YLT_USE_CXX26_REFLECTION else if constexpr (ylt_refletable_v) { visit_pb_unknown_fields_annotation(t, std::forward(func)); } #endif } template IGUANA_INLINE size_t pb_unknown_fields_size(const T& t) { size_t size = 0; visit_pb_unknown_fields(t, [&](const std::string& fields) { size += fields.size(); }); return size; } template IGUANA_INLINE void write_pb_unknown_fields(const T& t, Writer& writer) { visit_pb_unknown_fields(t, [&](const std::string& fields) { writer.write(fields.data(), fields.size()); }); } template IGUANA_INLINE void append_pb_unknown_field(T& t, const char* data, size_t size) { visit_pb_unknown_fields(t, [&](std::string& fields) { fields.append(data, size); }); } #ifdef YLT_USE_CXX26_REFLECTION template inline auto build_pb_fields(const Array& offset_arr, std::index_sequence) { constexpr auto arr = ylt::reflection::get_member_names(); using U = ylt::reflection::remove_cvref_t; static constexpr auto members = reflect26::data_members_array(); return std::tuple_cat( build_pb_annotation_field>( offset_arr, arr[I])...); } #else template inline auto build_pb_fields(const Array& offset_arr, std::index_sequence) { constexpr auto arr = ylt::reflection::get_member_names(); constexpr std::array indexs = get_field_no(std::make_index_sequence{}); return std::tuple_cat( build_pb_fields_impl>( offset_arr[I], arr[I])...); } #endif template inline auto get_pb_members_tuple(T&& t) { using U = ylt::reflection::remove_cvref_t; if constexpr (is_custom_reflection_v) { auto raw = get_members_impl((U*)nullptr); auto res = filter_pb_member_tuple(std::move(raw)); using ResultTuple = decltype(res); validate_pb_members_tuple(); return res; } else if constexpr (ylt_refletable_v) { #ifdef YLT_USE_CXX26_REFLECTION static const auto& offset_arr = ylt::reflection::internal::get_member_offset_arr(); constexpr auto count = ylt::reflection::members_count_v; auto res = build_pb_fields(offset_arr, std::make_index_sequence{}); #else static auto& offset_arr = ylt::reflection::internal::get_member_offset_arr( ylt::reflection::internal::wrapper::value); using Tuple = decltype(ylt::reflection::object_to_tuple(std::declval())); auto res = build_pb_fields( offset_arr, std::make_index_sequence>{}); #endif using ResultTuple = decltype(res); validate_pb_members_tuple(); return res; } else { static_assert(!sizeof(T), "not a reflectable type"); } } template inline auto get_members(T&& t) { if constexpr (ylt_refletable_v || is_custom_reflection_v) { static auto tp = get_pb_members_tuple(std::forward(t)); 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"); } } } // namespace detail template inline bool register_type() { #if defined(__clang__) || defined(_MSC_VER) || \ (defined(__GNUC__) && __GNUC__ > 8) if constexpr (std::is_base_of_v) { auto it = detail::g_pb_map.emplace(type_string(), [] { return std::make_shared(); }); return it.second; } else { return true; } #else return true; #endif } template IGUANA_INLINE constexpr size_t member_offset(T* t, U T::*member) { return (char*)&(t->*member) - (char*)t; } template IGUANA_INLINE auto build_pb_field(std::string_view name) { using owner = typename ylt::reflection::member_traits::owner_type; using value_type = typename ylt::reflection::member_traits::value_type; size_t offset = member_offset((owner*)nullptr, ptr); return iguana::detail::pb_field_t{offset, name}; } template IGUANA_INLINE auto pb_field_ex(std::string_view name, Options... options) { ((void)options, ...); using owner = typename ylt::reflection::member_traits::owner_type; using value_type = ylt::reflection::remove_cvref_t< typename ylt::reflection::member_traits::value_type>; using leaf_type = detail::pb_annotation_leaf_type_t; using opts = detail::pb_schema_options; using wire_value_type = typename detail::pb_wire_type_selector::type; static_assert(detail::is_valid_pb_field_no(field_no), "protobuf field number must be in [1, 2^29 - 1] and not in " "[19000, 19999]"); static_assert(!(opts::timestamp && opts::duration), "protobuf field can't use both pb_as_timestamp and " "pb_as_duration"); static_assert(!(opts::zigzag && opts::fixed), "protobuf field can't use both pb_zigzag and pb_fixed"); static_assert(!opts::bytes || std::is_same_v || std::is_same_v, "pb_bytes_field member must be std::string, " "std::string_view, or optional/vector of that type"); static_assert( !opts::timestamp || std::is_same_v, "pb_timestamp_field member must be " "std::chrono::system_clock::time_point, or optional/vector of " "that type"); static_assert( !opts::duration || std::is_same_v, "pb_duration_field member must be std::chrono::nanoseconds, " "or optional/vector of that type"); static_assert(!opts::optional || optional_v, "pb_optional_field member must be std::optional"); static_assert(!opts::zigzag || std::is_same_v || std::is_same_v, "pb_zigzag_field member must be int32_t/int64_t, or " "optional/vector of that type"); static_assert(!opts::fixed || std::is_same_v || std::is_same_v || std::is_same_v || std::is_same_v, "pb_fixed_field member must be 32/64-bit int, or " "optional/vector of that type"); size_t offset = member_offset((owner*)nullptr, ptr); return iguana::detail::pb_field_t< owner, value_type, field_no, value_type, opts::bytes, opts::timestamp, opts::duration, opts::optional, opts::zigzag, opts::fixed, wire_value_type, wire_value_type>{offset, name}; } template IGUANA_INLINE auto pb_field(std::string_view name) { return pb_field_ex(name); } template IGUANA_INLINE auto pb_bytes_field(std::string_view name) { return pb_field_ex(name, pb_bytes); } template IGUANA_INLINE auto pb_zigzag_field(std::string_view name) { return pb_field_ex(name, pb_zigzag); } template IGUANA_INLINE auto pb_fixed_field(std::string_view name) { return pb_field_ex(name, pb_fixed); } template IGUANA_INLINE auto pb_optional_field(std::string_view name) { return pb_field_ex(name, pb_optional); } template IGUANA_INLINE auto pb_timestamp_field(std::string_view name) { return pb_field_ex(name, pb_as_timestamp); } template IGUANA_INLINE auto as_timestamp_field(std::string_view name) { return pb_timestamp_field(name); } template IGUANA_INLINE auto pb_duration_field(std::string_view name) { return pb_field_ex(name, pb_as_duration); } template IGUANA_INLINE auto as_duration_field(std::string_view name) { return pb_duration_field(name); } template IGUANA_INLINE auto pb_unknown_fields_field(std::string_view name = "") { using owner = typename ylt::reflection::member_traits::owner_type; using value_type = ylt::reflection::remove_cvref_t< typename ylt::reflection::member_traits::value_type>; static_assert(std::is_same_v, "pb_unknown_fields_field member must be std::string"); size_t offset = member_offset((owner*)nullptr, ptr); return iguana::detail::pb_unknown_fields_t{offset, name}; } template IGUANA_INLINE auto pb_oneof_field(std::string_view name) { using owner = typename ylt::reflection::member_traits::owner_type; using value_type = typename ylt::reflection::member_traits::value_type; size_t offset = member_offset((owner*)nullptr, ptr); return iguana::detail::build_pb_oneof_fields( offset, name); } namespace detail { template IGUANA_INLINE auto as_pb_member_tuple(T&& value) { using U = ylt::reflection::remove_cvref_t; if constexpr (is_tuple::value) { return std::forward(value); } else { return std::make_tuple(std::forward(value)); } } } // namespace detail template IGUANA_INLINE auto pb_members(Fields&&... fields) { return std::tuple_cat( detail::as_pb_member_tuple(std::forward(fields))...); } } // namespace iguana