Repository: bitcoin/bitcoin
File: src/serialize.h (C/C++)

Code before:
    ParamsStream(const Params& params LIFETIMEBOUND, SubStream& substream LIFETIMEBOUND) : m_params{params}, m_substream{substream} {}
    template <typename U> ParamsStream& operator<<(const U& obj) { ::Serialize(*this, obj); return *this; }
    template <typename U> ParamsStream& operator>>(U&& obj) { ::Unserialize(*this, obj); return *this; }
    void write(Span<const std::byte> src) { m_substream.write(src); }
    void read(Span<std::byte> dst) { m_substream.read(dst); }
    void ignore(size_t num) { m_substream.ignore(num); }
    bool eof() const { return m_substream.eof(); }
    size_t size() const { return m_substream.size(); }
    const Params& GetParams() const { return m_params; }
    int GetVersion() = delete; // Deprecated with Params usage
    int GetType() = delete;    // Deprecated with Params usage
};

/** Wrapper that serializes objects with the specified parameters. */
template <typename Params, typename T>
class ParamsWrapper
{
    const Params& m_params;
    T& m_object;

public:
    explicit ParamsWrapper(const Params& params, T& obj) : m_params{params}, m_object{obj} {}

    template <typename Stream>
    void Serialize(Stream& s) const
    {
        ParamsStream ss{m_params, s};
        ::Serialize(ss, m_object);
    }
    template <typename Stream>
    void Unserialize(Stream& s)
    {
        ParamsStream ss{m_params, s};
        ::Unserialize(ss, m_object);
    }
};

/**
 * Helper macro for SerParams structs
 *
 * Allows you define SerParams instances and then apply them directly
 * to an object via function call syntax, eg:
 *
 *   constexpr SerParams FOO{....};
 *   ss << FOO(obj);
 */
#define SER_PARAMS_OPFUNC                                                                \
    /**                                                                                  \
     * Return a wrapper around t that (de)serializes it with specified parameter params. \
     *                                                                                   \
     * See FORMATTER_METHODS_PARAMS for more information on serialization parameters.    \

Review comment (suggestion):
Just a comment: This does indeed not trigger clang-tidy's recursion check (I'm guessing because of the constexpr condition).

Code after:
        : ParamsStream{::ParamsStream{std::forward<NestedSubstream>(s), params2, params...}, params1} {}

    template <typename U> ParamsStream& operator<<(const U& obj) { ::Serialize(*this, obj); return *this; }
    template <typename U> ParamsStream& operator>>(U&& obj) { ::Unserialize(*this, obj); return *this; }
    void write(Span<const std::byte> src) { GetStream().write(src); }
    void read(Span<std::byte> dst) { GetStream().read(dst); }
    void ignore(size_t num) { GetStream().ignore(num); }
    bool eof() const { return GetStream().eof(); }
    size_t size() const { return GetStream().size(); }

    //! Get reference to stream parameters.
    template <typename P>
    const auto& GetParams() const
    {
        if constexpr (std::is_convertible_v<Params, P>) {
            return m_params;
        } else {
            return m_substream.template GetParams<P>();
        }
    }

    //! Get reference to underlying stream.
    auto& GetStream()
    {
        if constexpr (ContainsStream<SubStream>) {
            return m_substream.GetStream();
        } else {
            return m_substream;
        }
    }
    const auto& GetStream() const
    {
        if constexpr (ContainsStream<SubStream>) {
            return m_substream.GetStream();
        } else {
            return m_substream;
        }
    }
};

/**
 * Explicit template deduction guide is required for single-parameter
 * constructor so Substream&& is treated as a forwarding reference, and
 * SubStream is deduced as reference type for lvalue arguments.
 */
template <typename Substream, typename Params>
ParamsStream(Substream&&, const Params&) -> ParamsStream<Substream, Params>;

/**
 * Template deduction guide for multiple params arguments that creates a nested
 * ParamsStream.