// Copyright (C) 2026 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only // Qt-Security score:significant reason:default #ifndef QGRPCINTERCEPTORCHAIN_H #define QGRPCINTERCEPTORCHAIN_H #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE class QGrpcInterceptorChainPrivate; class QGrpcInterceptorChain final { public: Q_GRPC_EXPORT QGrpcInterceptorChain(); Q_GRPC_EXPORT ~QGrpcInterceptorChain(); Q_DISABLE_COPY(QGrpcInterceptorChain) QGrpcInterceptorChain(QGrpcInterceptorChain &&other) noexcept : d_ptr(std::exchange(other.d_ptr, nullptr)) { } QT_MOVE_ASSIGNMENT_OPERATOR_IMPL_VIA_PURE_SWAP(QGrpcInterceptorChain) void swap(QGrpcInterceptorChain &other) noexcept { qt_ptr_swap(d_ptr, other.d_ptr); } template = true> bool add(std::unique_ptr &&interceptor) { return addHelper(std::move(interceptor)); } template = true> bool set(std::unique_ptr &&...interceptors) { return setHelper(std::move(interceptors)...); } template = true> bool add(T *interceptor) { return addHelper(interceptor); } template = true> bool set(Ts *...interceptors) { return setHelper(interceptors...); } Q_GRPC_EXPORT void clear(); [[nodiscard]] Q_GRPC_EXPORT qsizetype size() const noexcept; [[nodiscard]] bool isEmpty() const noexcept { return !size(); } [[nodiscard]] bool empty() const noexcept { return isEmpty(); } [[nodiscard]] Q_GRPC_EXPORT bool hasHandlerFor(QtGrpc::InterceptorCapability cap) const noexcept; [[nodiscard]] Q_GRPC_EXPORT QtGrpc::InterceptorCapabilities capabilities() const noexcept; [[nodiscard]] Q_GRPC_EXPORT QtGrpc::InterceptorCapabilities capabilitiesAt(qsizetype index) const; private: using DeleterFn = void (*)(void *); template struct InterceptorTraits { static constexpr bool is_supported = false; }; template struct InterceptorTraits { static constexpr bool is_supported = true; static constexpr bool is_owning = false; using element_type = T; static element_type *get(T *p) noexcept { return p; } static constexpr DeleterFn deleter() noexcept { return nullptr; } }; template struct InterceptorTraits> { static constexpr bool is_supported = true; static constexpr bool is_owning = true; using element_type = T; static_assert(!std::is_array_v, "Arrays of interceptors are not supported."); static element_type *get(const std::unique_ptr &p) noexcept { return p.get(); } static constexpr DeleterFn deleter() noexcept { return [](void *p) { delete static_cast(p); }; } }; template [[nodiscard]] bool addHelper(T &&interceptor) { using namespace QtGrpcPrivate; using DecayedT = q20::remove_cvref_t; using Traits = QGrpcInterceptorChain::InterceptorTraits; static_assert(Traits::is_supported, "Interceptor must be passed as T* or std::unique_ptr."); if (!interceptor) { warnNullInterceptor(); return false; } auto *ptr = Traits::get(interceptor); const auto deleter = Traits::deleter(); auto bindings = InterceptorCapabilityBinding::extractFrom(ptr); if (!addImpl(ptr, deleter, bindings)) return false; if constexpr (Traits::is_owning) interceptor.release(); // we take ownership on success return true; } template [[nodiscard]] bool setHelper(Ts &&...interceptors) { qsizetype failedIndex = -1; qsizetype idx = 0; auto checkNull = [&](const auto &p) { if (!p && failedIndex == -1) failedIndex = idx; ++idx; }; (checkNull(interceptors), ...); if (failedIndex != -1) { warnNullInterceptor(failedIndex, sizeof...(Ts) - 1); return false; } QGrpcInterceptorChain tmp; bool ok = (... && tmp.addHelper(std::forward(interceptors))); if (ok) *this = std::move(tmp); return ok; } [[nodiscard]] Q_GRPC_EXPORT bool addImpl(void *interceptor, DeleterFn deleter, QSpan bindings); Q_DECL_COLD_FUNCTION Q_GRPC_EXPORT void warnNullInterceptor(qsizetype index = -1, qsizetype total = -1) const; // prevent users from implementing their own, as the data-members don't qualify for it. friend bool operator==(const QGrpcInterceptorChain &, const QGrpcInterceptorChain &) = delete; friend bool operator!=(const QGrpcInterceptorChain &, const QGrpcInterceptorChain &) = delete; friend size_t qHash(const QGrpcInterceptorChain &) = delete; friend size_t qHash(const QGrpcInterceptorChain &, size_t) = delete; #ifndef QT_NO_DEBUG_STREAM friend QDebug operator<<(QDebug debug, const QGrpcInterceptorChain &) = delete; #endif #ifndef QT_NO_DATASTREAM friend QDataStream &operator<<(QDataStream &, const QGrpcInterceptorChain &) = delete; friend QDataStream &operator>>(QDataStream &, QGrpcInterceptorChain &) = delete; #endif QGrpcInterceptorChainPrivate *d_ptr; friend class QGrpcInterceptorEngine; Q_DECLARE_PRIVATE(QGrpcInterceptorChain) }; QT_END_NAMESPACE #endif // QGRPCINTERCEPTORCHAIN_H