in include/ylt/standalone/iguana/pb_writer.hpp [101:207]
IGUANA_INLINE void to_pb_impl(Type&& t, uint32_t*& sz_ptr, Writer& writer) {
using T = std::remove_const_t<std::remove_reference_t<Type>>;
if constexpr (ylt_refletable_v<T> || is_custom_reflection_v<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<key>(writer);
serialize_varint(len, writer);
if (len == 0)
IGUANA_UNLIKELY { return; }
}
static auto tuple = get_pb_members_tuple(std::forward<Type>(t));
constexpr size_t SIZE = std::tuple_size_v<std::decay_t<decltype(tuple)>>;
for_each_n(
[&t, &sz_ptr, &writer](auto i) IGUANA__INLINE_LAMBDA {
using field_type =
std::tuple_element_t<decltype(i)::value,
std::decay_t<decltype(tuple)>>;
auto value = std::get<decltype(i)::value>(tuple);
auto& val = value.value(t);
using U = typename field_type::value_type;
using sub_type = typename field_type::sub_type;
if constexpr (variant_v<U>) {
constexpr auto offset =
get_variant_index<U, sub_type, std::variant_size_v<U> - 1>();
if constexpr (offset == 0) {
to_pb_oneof<value.field_no>(val, sz_ptr, writer);
}
}
else {
constexpr uint32_t sub_key =
(value.field_no << 3) |
static_cast<uint32_t>(get_wire_type<U>());
to_pb_impl<sub_key>(val, sz_ptr, writer);
}
},
std::make_index_sequence<SIZE>{});
}
else if constexpr (is_sequence_container<T>::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<item_type>) {
// non-packed
for (auto& item : t) {
to_pb_impl<key, false>(item, sz_ptr, writer);
}
}
else {
if (t.empty())
IGUANA_UNLIKELY { return; }
serialize_varint_u32<key>(writer);
serialize_varint(pb_value_size(t, sz_ptr), writer);
for (auto& item : t) {
encode_numeric_field<false, 0>(item, writer);
}
}
}
else if constexpr (is_map_container<T>::value) {
using first_type = typename T::key_type;
using second_type = typename T::mapped_type;
constexpr uint32_t key1 =
(1 << 3) | static_cast<uint32_t>(get_wire_type<first_type>());
constexpr auto key1_size = variant_uint32_size_constexpr(key1);
constexpr uint32_t key2 =
(2 << 3) | static_cast<uint32_t>(get_wire_type<second_type>());
constexpr auto key2_size = variant_uint32_size_constexpr(key2);
for (auto& [k, v] : t) {
serialize_varint_u32<key>(writer);
// k must be string or numeric
auto k_val_len = str_numeric_size<0, false>(k);
auto v_val_len = pb_value_size<false>(v, sz_ptr);
auto pair_len = key1_size + key2_size + k_val_len + v_val_len;
if constexpr (is_lenprefix_v<first_type>) {
pair_len += variant_uint32_size(k_val_len);
}
if constexpr (is_lenprefix_v<second_type>) {
pair_len += variant_uint32_size(v_val_len);
}
serialize_varint(pair_len, writer);
// map k and v can't be omitted even if values are empty
encode_pair_value<key1>(k, k_val_len, sz_ptr, writer);
encode_pair_value<key2>(v, v_val_len, sz_ptr, writer);
}
}
else if constexpr (optional_v<T>) {
if (!t.has_value()) {
return;
}
to_pb_impl<key, omit_default_val>(*t, sz_ptr, writer);
}
else if constexpr (std::is_same_v<T, std::string> ||
std::is_same_v<T, std::string_view>) {
if constexpr (omit_default_val) {
if (t.size() == 0)
IGUANA_UNLIKELY { return; }
}
serialize_varint_u32<key>(writer);
serialize_varint(t.size(), writer);
writer.write(t.data(), t.size());
}
else {
encode_numeric_field<key, omit_default_val>(t, writer);
}
}