constexpr void inline serialize_one()

in include/ylt/struct_pack/packer.hpp [243:531]


  constexpr void inline serialize_one(const T &item) {
    using type = remove_cvref_t<decltype(item)>;
    static_assert(!std::is_pointer_v<type>);
    constexpr auto id = get_type_id<type, parent_tag>();
    if constexpr (is_trivial_view_v<T>) {
      return serialize_one<size_type, version>(item.get());
    }
    else if constexpr (version == UINT64_MAX) {
      if constexpr (id == type_id::compatible_t) {
        // do nothing
      }
      else if constexpr (std::is_same_v<type, std::monostate>) {
        // do nothing
      }
      else if constexpr (id == type_id::user_defined_type) {
        sp_serialize_to(writer_, item);
      }
      else if constexpr (detail::varint_t<type, parent_tag>) {
        if constexpr (is_enable_fast_varint_coding(parent_tag)) {
          // do nothing
        }
        else {
          detail::serialize_varint(writer_, item);
        }
      }
      else if constexpr (std::is_fundamental_v<type> || std::is_enum_v<type> ||
                         id == type_id::int128_t || id == type_id::uint128_t) {
        write_wrapper<sizeof(item)>(writer_, (char *)&item);
      }
      else if constexpr (id == type_id::bitset_t) {
        write_bytes_array(writer_, (char *)&item, sizeof(item));
      }
      else if constexpr (unique_ptr<type>) {
        bool has_value = (item != nullptr);
        write_wrapper<sizeof(char)>(writer_, (char *)&has_value);
        if (has_value) {
          if constexpr (is_base_class<typename type::element_type>) {
            bool is_ok{};
            uint32_t id = item->get_struct_pack_id();
            auto index = search_type_by_md5<typename type::element_type>(
                item->get_struct_pack_id(), is_ok);
            assert(is_ok);
            write_wrapper<sizeof(uint32_t)>(writer_, (char *)&id);
            ylt::reflection::template_switch<serialize_one_derived_class_helper<
                derived_class_set_t<typename type::element_type>,
                std::integral_constant<std::size_t, size_type>,
                std::integral_constant<std::uint64_t, version>>>(index, this,
                                                                 item.get());
          }
          else {
            serialize_one<size_type, version>(*item);
          }
        }
      }
      else if constexpr (id == type_id::array_t) {
        if constexpr (is_trivial_serializable<type>::value &&
                      is_little_endian_copyable<sizeof(item[0])>) {
          write_bytes_array(writer_, (char *)&item, sizeof(type));
        }
        else {
          for (const auto &i : item) {
            serialize_one<size_type, version>(i);
          }
        }
      }
      else if constexpr (map_container<type> || container<type>) {
        auto size = item.size();

        if constexpr (size_type == 1) {
          low_bytes_write_wrapper<size_type>(writer_, size);
        }
        else {
#ifdef STRUCT_PACK_OPTIMIZE
          constexpr bool struct_pack_optimize = true;
#else
          constexpr bool struct_pack_optimize = false;
#endif
          if constexpr (force_optimize || struct_pack_optimize) {
            if constexpr (size_type == 2) {
              low_bytes_write_wrapper<size_type>(writer_, size);
            }
            else if constexpr (size_type == 4) {
              low_bytes_write_wrapper<size_type>(writer_, size);
            }
            else if constexpr (size_type == 8) {
              if constexpr (sizeof(std::size_t) >= 8) {
                low_bytes_write_wrapper<size_type>(writer_, size);
              }
              else {
                std::uint64_t sz = size;
                low_bytes_write_wrapper<size_type>(writer_, sz);
              }
            }
            else {
              static_assert(!sizeof(item), "illegal size_type.");
            }
          }
          else {
            switch ((info_.metainfo() & 0b11000) >> 3) {
              case 1:
                low_bytes_write_wrapper<2>(writer_, size);
                break;
              case 2:
                low_bytes_write_wrapper<4>(writer_, size);
                break;
              case 3:
                if constexpr (sizeof(std::size_t) >= 8) {
                  low_bytes_write_wrapper<8>(writer_, size);
                }
                else {
                  unreachable();
                }
                break;
              default:
                unreachable();
            }
          }
        }
        if constexpr (trivially_copyable_container<type> &&
                      is_little_endian_copyable<sizeof(
                          typename type::value_type)>) {
          write_bytes_array(writer_, (char *)item.data(),
                            item.size() * sizeof(typename type::value_type));
          return;
        }
        else {
          for (const auto &i : item) {
            serialize_one<size_type, version>(i);
          }
        }
      }
      else if constexpr (container_adapter<type>) {
        static_assert(!sizeof(type),
                      "the container adapter type is not supported");
      }
      else if constexpr (!pair<type> && tuple<type> &&
                         !is_trivial_tuple<type>) {
        std::apply(
            [&](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
              serialize_many<size_type, version>(items...);
            },
            item);
      }
      else if constexpr (ylt::reflection::optional<type>) {
        bool has_value = item.has_value();
        write_wrapper<sizeof(bool)>(writer_, (char *)&has_value);
        if (has_value) {
          serialize_one<size_type, version>(*item);
        }
      }
      else if constexpr (is_variant_v<type>) {
        static_assert(std::variant_size_v<type> < 256,
                      "variant's size is too large");
        uint8_t index = item.index();
        write_wrapper<sizeof(uint8_t)>(writer_, (char *)&index);
        std::visit(
            [this](auto &&e) {
              this->serialize_one<size_type, version>(e);
            },
            item);
      }
      else if constexpr (ylt::reflection::expected<type>) {
        bool has_value = item.has_value();
        write_wrapper<sizeof(bool)>(writer_, (char *)&has_value);
        if (has_value) {
          if constexpr (!std::is_same_v<typename type::value_type, void>)
            serialize_one<size_type, version>(item.value());
        }
        else {
          serialize_one<size_type, version>(item.error());
        }
      }
      else if constexpr (std::is_class_v<type>) {
        if constexpr (!pair<type> && !is_trivial_tuple<type>)
          if constexpr (!user_defined_refl<type>)
            static_assert(
                std::is_aggregate_v<remove_cvref_t<type>>,
                "struct_pack only support aggregated type, or you should "
                "add macro YLT_REFL(Type,field1,field2...)");
        if constexpr (is_trivial_serializable<type>::value &&
                      is_little_endian_copyable<sizeof(type)>) {
          write_wrapper<sizeof(type)>(writer_, (char *)&item);
        }
        else if constexpr ((is_trivial_serializable<type>::value &&
                            !is_little_endian_copyable<sizeof(type)>) ||
                           is_trivial_serializable<type, true>::value) {
          visit_members(item, [this](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
            int i = 1;
            ((serialize_one<size_type, version>(items),
              write_padding(align::padding_size<type>[i++])),
             ...);
          });
        }
        else {
          constexpr uint64_t tag = get_parent_tag<type>();
          if constexpr (is_enable_fast_varint_coding(tag)) {
            visit_members(
                item, [this](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
                  constexpr uint64_t tag =
                      get_parent_tag<type>();  // to pass msvc with c++17
                  this->serialize_fast_varint<tag>(items...);
                });
          }
          visit_members(item, [this](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
            constexpr uint64_t tag =
                get_parent_tag<type>();  // to pass msvc with c++17
            this->serialize_many<size_type, version, tag>(items...);
          });
        }
      }
      else {
        static_assert(!sizeof(type), "the type is not supported yet");
      }
    }
    else if constexpr (exist_compatible_member<type, version>) {
      if constexpr (id == type_id::compatible_t) {
        if constexpr (version == type::version_number) {
          bool has_value = item.has_value();
          write_wrapper<sizeof(bool)>(writer_, (char *)&has_value);
          if (has_value) {
            serialize_one<size_type, UINT64_MAX>(*item);
          }
        }
      }
      else if constexpr (unique_ptr<type>) {
        if (item != nullptr) {
          if constexpr (is_base_class<typename type::element_type>) {
            bool is_ok{};
            auto index = search_type_by_md5<typename type::element_type>(
                item->get_struct_pack_id(), is_ok);
            assert(is_ok);
            ylt::reflection::template_switch<serialize_one_derived_class_helper<
                derived_class_set_t<typename type::element_type>,
                std::integral_constant<std::size_t, size_type>,
                std::integral_constant<std::uint64_t, version>>>(index, this,
                                                                 item.get());
          }
          else {
            serialize_one<size_type, version>(*item);
          }
        }
      }
      else if constexpr (id == type_id::array_t) {
        for (const auto &i : item) {
          serialize_one<size_type, version>(i);
        }
      }
      else if constexpr (map_container<type> || container<type>) {
        for (const auto &i : item) {
          serialize_one<size_type, version>(i);
        }
      }
      else if constexpr (!pair<type> && tuple<type> &&
                         !is_trivial_tuple<type>) {
        std::apply(
            [&](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
              serialize_many<size_type, version>(items...);
            },
            item);
      }
      else if constexpr (ylt::reflection::optional<type>) {
        if (item.has_value()) {
          serialize_one<size_type, version>(*item);
        }
      }
      else if constexpr (is_variant_v<type>) {
        std::visit(
            [this](const auto &e) {
              this->serialize_one<size_type, version>(e);
            },
            item);
      }
      else if constexpr (ylt::reflection::expected<type>) {
        if (item.has_value()) {
          if constexpr (!std::is_same_v<typename type::value_type, void>)
            serialize_one<size_type, version>(item.value());
        }
        else {
          serialize_one<size_type, version>(item.error());
        }
      }
      else if constexpr (std::is_class_v<type>) {
        visit_members(item, [&](auto &&...items) CONSTEXPR_INLINE_LAMBDA {
          serialize_many<size_type, version>(items...);
        });
      }
    }
    return;
  }