From e0fa37441136aa1ca826b396aeb97726b2c04ade Mon Sep 17 00:00:00 2001 From: Mikhail Svetkin Date: Wed, 29 Apr 2020 22:06:00 +0200 Subject: Add QHttpServer::afterRequest This function allows to register a function to be run after each request. Task-number: QTBUG-77090 Change-Id: I40dd4c1e9a447fbe034149ffc1923c7c814cf0e9 Reviewed-by: Mikhail Svetkin --- src/httpserver/CMakeLists.txt | 9 +- src/httpserver/httpserver.pro | 4 +- src/httpserver/qhttpserver.cpp | 48 ++++- src/httpserver/qhttpserver.h | 63 ++++++- src/httpserver/qhttpserver_p.h | 3 + src/httpserver/qhttpserverresponse.cpp | 11 +- src/httpserver/qhttpserverresponse.h | 4 +- src/httpserver/qhttpserverrouterviewtraits.h | 255 +++++---------------------- src/httpserver/qhttpserverviewtraits.h | 109 ++++++++++++ src/httpserver/qhttpserverviewtraits_impl.h | 194 ++++++++++++++++++++ 10 files changed, 468 insertions(+), 232 deletions(-) create mode 100644 src/httpserver/qhttpserverviewtraits.h create mode 100644 src/httpserver/qhttpserverviewtraits_impl.h (limited to 'src') diff --git a/src/httpserver/CMakeLists.txt b/src/httpserver/CMakeLists.txt index b3586eb..efcce0d 100644 --- a/src/httpserver/CMakeLists.txt +++ b/src/httpserver/CMakeLists.txt @@ -16,6 +16,8 @@ qt_add_module(HttpServer qhttpserverrouter.cpp qhttpserverrouter.h qhttpserverrouter_p.h qhttpserverrouterrule.cpp qhttpserverrouterrule.h qhttpserverrouterrule_p.h qhttpserverrouterviewtraits.h + qhttpserverviewtraits.h + qhttpserverviewtraits_impl.h qthttpserverglobal.h INCLUDE_DIRECTORIES . @@ -45,10 +47,3 @@ qt_extend_target(HttpServer CONDITION QT_FEATURE_ssl PUBLIC_LIBRARIES Qt::SslServer ) - -qt_extend_target(HttpServer CONDITION TARGET Qt::Concurrent - SOURCES - qhttpserverfutureresponse.cpp qhttpserverfutureresponse.h - PUBLIC_LIBRARIES - Qt::Concurrent -) diff --git a/src/httpserver/httpserver.pro b/src/httpserver/httpserver.pro index 20f567f..fd1a231 100644 --- a/src/httpserver/httpserver.pro +++ b/src/httpserver/httpserver.pro @@ -23,7 +23,9 @@ HEADERS += \ qhttpserverrouter_p.h \ qhttpserverrouterrule.h \ qhttpserverrouterrule_p.h \ - qhttpserverrouterviewtraits.h + qhttpserverrouterviewtraits.h \ + qhttpserverviewtraits.h \ + qhttpserverviewtraits_impl.h SOURCES += \ qabstracthttpserver.cpp \ diff --git a/src/httpserver/qhttpserver.cpp b/src/httpserver/qhttpserver.cpp index 413e3c3..fb0b67b 100644 --- a/src/httpserver/qhttpserver.cpp +++ b/src/httpserver/qhttpserver.cpp @@ -66,8 +66,7 @@ QHttpServer::QHttpServer(QObject *parent) connect(this, &QAbstractHttpServer::missingHandler, this, [=] (const QHttpServerRequest &request, QTcpSocket *socket) { qCDebug(lcHS) << tr("missing handler:") << request.url().path(); - sendResponse( - QHttpServerResponse(QHttpServerResponder::StatusCode::NotFound), request, socket); + sendResponse(QHttpServerResponder::StatusCode::NotFound, request, socket); }); } @@ -103,6 +102,40 @@ QHttpServer::QHttpServer(QObject *parent) \sa QHttpServerRouter::addRule */ +/*! \fn template void afterRequest(ViewHandler &&viewHandler) + Register a function to be run after each request. + + \c ViewHandler can only be a lambda. The lambda definition can take two + arguments: \c {QHttpServerResponse &&} and \c {const QHttpServerRequest&} (optional). + + Examples: + + \code + + QHttpServer server; + + // Valid: + server.afterRequest([] (QHttpServerResponse &&resp, const QHttpServerRequest &request) { + return std::move(resp); + } + server.afterRequest([] (const QHttpServerRequest &request, QHttpServerResponse &&resp) { + return std::move(resp); + } + server.afterRequest([] (QHttpServerResponse &&resp) { return std::move(resp); } + + // Invalid (compile time error): + // resp must be passed by universal reference + server.afterRequest([] (QHttpServerResponse &resp, const QHttpServerRequest &request) { + return std::move(resp); + } + // request must be passed by const reference + server.afterRequest([] (QHttpServerResponse &&resp, QHttpServerRequest &request) { + return std::move(resp); + } + + \endcode +*/ + /*! Destroys a QHttpServer. */ @@ -119,13 +152,22 @@ QHttpServerRouter *QHttpServer::router() return &d->router; } +void QHttpServer::afterRequestImpl(AfterRequestHandler &&afterRequestHandler) +{ + Q_D(QHttpServer); + d->afterRequestHandlers.push_back(std::move(afterRequestHandler)); +} + /*! \internal */ -void QHttpServer::sendResponse(const QHttpServerResponse &response, +void QHttpServer::sendResponse(QHttpServerResponse &&response, const QHttpServerRequest &request, QTcpSocket *socket) { + Q_D(QHttpServer); + for (auto afterRequestHandler : d->afterRequestHandlers) + response = std::move(afterRequestHandler(std::move(response), request)); response.write(makeResponder(request, socket)); } diff --git a/src/httpserver/qhttpserver.h b/src/httpserver/qhttpserver.h index 6d754b1..97c5bc5 100644 --- a/src/httpserver/qhttpserver.h +++ b/src/httpserver/qhttpserver.h @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2020 Mikhail Svetkin ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** @@ -35,6 +36,7 @@ #include #include #include +#include #include @@ -75,6 +77,57 @@ public: std::forward(args)...); } + template + void afterRequest(ViewHandler &&viewHandler) + { + using ViewTraits = QHttpServerAfterRequestViewTraits; + static_assert(ViewTraits::Arguments::StaticAssert, + "ViewHandler arguments are in the wrong order or not supported"); + afterRequestHelper(std::move(viewHandler)); + } + + using AfterRequestHandler = + std::function; +private: + template + typename std::enable_if::type + afterRequestHelper(ViewHandler &&viewHandler) { + auto handler = [viewHandler](QHttpServerResponse &&resp, + const QHttpServerRequest &request) { + return std::move(viewHandler(std::move(resp), request)); + }; + + afterRequestImpl(std::move(handler)); + } + + template + typename std::enable_if::type + afterRequestHelper(ViewHandler &&viewHandler) { + auto handler = [viewHandler](QHttpServerResponse &&resp, + const QHttpServerRequest &) { + return std::move(viewHandler(std::move(resp))); + }; + + afterRequestImpl(std::move(handler)); + } + + template + typename std::enable_if::type + afterRequestHelper(ViewHandler &&viewHandler) { + auto handler = [viewHandler](QHttpServerResponse &&resp, + const QHttpServerRequest &request) { + return std::move(viewHandler(request, std::move(resp))); + }; + + afterRequestImpl(std::move(handler)); + } + + void afterRequestImpl(AfterRequestHandler &&afterRequestHandler); + private: template bool routeHelper(QtPrivate::IndexesList, Args &&... args) @@ -107,8 +160,8 @@ private: const QHttpServerRequest &request, QTcpSocket *socket) { - const QHttpServerResponse response(boundViewHandler()); - sendResponse(response, request, socket); + QHttpServerResponse response(boundViewHandler()); + sendResponse(std::move(response), request, socket); } template @@ -124,8 +177,8 @@ private: ViewTraits::Arguments::PlaceholdersCount == 1, void>::type responseImpl(T &boundViewHandler, const QHttpServerRequest &request, QTcpSocket *socket) { - const QHttpServerResponse response(boundViewHandler(request)); - sendResponse(response, request, socket); + QHttpServerResponse response(boundViewHandler(request)); + sendResponse(std::move(response), request, socket); } template @@ -150,7 +203,7 @@ private: bool handleRequest(const QHttpServerRequest &request, QTcpSocket *socket) override final; - void sendResponse(const QHttpServerResponse &response, + void sendResponse(QHttpServerResponse &&response, const QHttpServerRequest &request, QTcpSocket *socket); }; diff --git a/src/httpserver/qhttpserver_p.h b/src/httpserver/qhttpserver_p.h index 649c41f..eb39a9e 100644 --- a/src/httpserver/qhttpserver_p.h +++ b/src/httpserver/qhttpserver_p.h @@ -49,6 +49,8 @@ #include +#include + QT_BEGIN_NAMESPACE class QHttpServerPrivate: public QAbstractHttpServerPrivate @@ -59,6 +61,7 @@ public: QHttpServerPrivate() = default; QHttpServerRouter router; + std::list afterRequestHandlers; }; QT_END_NAMESPACE diff --git a/src/httpserver/qhttpserverresponse.cpp b/src/httpserver/qhttpserverresponse.cpp index 9cedeb9..5ed230e 100644 --- a/src/httpserver/qhttpserverresponse.cpp +++ b/src/httpserver/qhttpserverresponse.cpp @@ -40,11 +40,20 @@ QT_BEGIN_NAMESPACE -QHttpServerResponse::QHttpServerResponse(QHttpServerResponse &&other) +QHttpServerResponse::QHttpServerResponse(QHttpServerResponse &&other) noexcept : d_ptr(other.d_ptr.take()) { } +QHttpServerResponse& QHttpServerResponse::operator=(QHttpServerResponse &&other) noexcept +{ + if (this == &other) + return *this; + + qSwap(d_ptr, other.d_ptr); + return *this; +} + QHttpServerResponse::QHttpServerResponse( const QHttpServerResponse::StatusCode statusCode) : QHttpServerResponse(QHttpServerLiterals::contentTypeXEmpty(), diff --git a/src/httpserver/qhttpserverresponse.h b/src/httpserver/qhttpserverresponse.h index 3fef112..df748cb 100644 --- a/src/httpserver/qhttpserverresponse.h +++ b/src/httpserver/qhttpserverresponse.h @@ -50,8 +50,8 @@ public: QHttpServerResponse(const QHttpServerResponse &other) = delete; QHttpServerResponse& operator=(const QHttpServerResponse &other) = delete; - QHttpServerResponse(QHttpServerResponse &&other); - QHttpServerResponse& operator=(QHttpServerResponse &&other) = delete; + QHttpServerResponse(QHttpServerResponse &&other) noexcept; + QHttpServerResponse& operator=(QHttpServerResponse &&other) noexcept; QHttpServerResponse(const StatusCode statusCode); diff --git a/src/httpserver/qhttpserverrouterviewtraits.h b/src/httpserver/qhttpserverrouterviewtraits.h index 94fd5cc..2e812a5 100644 --- a/src/httpserver/qhttpserverrouterviewtraits.h +++ b/src/httpserver/qhttpserverrouterviewtraits.h @@ -1,5 +1,6 @@ /**************************************************************************** ** +** Copyright (C) 2020 Mikhail Svetkin ** Copyright (C) 2019 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** @@ -30,14 +31,7 @@ #ifndef QHTTPSERVERROUTERVIEWTRAITS_H #define QHTTPSERVERROUTERVIEWTRAITS_H -#include -#include -#include -#include - -#include -#include -#include +#include QT_BEGIN_NAMESPACE @@ -46,220 +40,53 @@ class QHttpServerResponder; namespace QtPrivate { -template -struct RemoveCVRef -{ - using Type = typename std::remove_cv::type>::type; -}; - - -template -struct FunctionTraitsHelper -{ - static constexpr const int ArgumentCount = sizeof ... (Args); - static constexpr const int ArgumentIndexMax = ArgumentCount - 1; - static constexpr const bool IsClassMember = classMember; - using ReturnType = ReturnT; - - template - struct Arg { - using Type = typename std::tuple_element>::type; - - using CleanType = typename QtPrivate::RemoveCVRef::Type; - - static constexpr bool Defined = QMetaTypeId2::Defined; - }; -}; - -template -struct FunctionTraitsHelper -{ - static constexpr const int ArgumentCount = 0; - static constexpr const int ArgumentIndexMax = -1; - static constexpr const bool IsClassMember = classMember; - using ReturnType = ReturnT; - - template - struct Arg { - using Type = std::false_type; - using CleanType = Type; - static constexpr bool Defined = QMetaTypeId2::Defined; - }; -}; - -template -struct FunctionTraits; - -template -struct FunctionTraits : public FunctionTraits{}; - -template -struct FunctionTraits - : public FunctionTraitsHelper -{ -}; - -template -struct FunctionTraits - : public FunctionTraitsHelper -{ - using classType = ClassT; -}; - template -struct ViewTraitsHelper { - using FunctionTraits = typename QtPrivate::FunctionTraits; - using ArgumentIndexes = typename QtPrivate::Indexes::Value; - - struct StaticMath { - template class Predicate, bool defaultValue> - struct Loop { - static constexpr bool eval() noexcept { - return defaultValue; - } +struct RouterViewTraitsHelper : ViewTraits { + using VTraits = ViewTraits; + using FunctionTraits = typename VTraits::FTraits; + + template + struct ArgumentChecker : FunctionTraits::template Arg { + using IsRequest = typename VTraits::template Special; + static_assert(IsRequest::AssertCondition, + "ViewHandler arguments error: " + "QHttpServerRequest can only be passed as a const reference"); + + using IsResponder = typename VTraits::template Special; + static_assert(IsResponder::AssertCondition, + "ViewHandler arguments error: " + "QHttpServerResponder can only be passed as a universal reference"); + + using IsSpecial = CheckAny; + + struct IsSimple { + static constexpr bool Value = !IsSpecial::Value && + I < FunctionTraits::ArgumentCount && + FunctionTraits::ArgumentIndexMax != -1; + static constexpr bool Valid = FunctionTraits::template Arg::Defined; - template - static constexpr T eval(const T it, N ...n) noexcept { - return Predicate::eval(it, eval(n...)); - } - }; + static constexpr bool StaticAssert = + DisableStaticAssert || !Value || Valid; - template - struct SumPredicate { - static constexpr T eval(const T rs, const T ls) noexcept - { - return rs + ls; - } - }; - template - struct AndPredicate { - static constexpr T eval(const T rs, const T ls) noexcept - { - return rs && ls; - } + static_assert(StaticAssert, + "ViewHandler arguments error: " + "Type is not registered, please use the Q_DECLARE_METATYPE macro " + "to make it known to Qt's meta-object system"); }; - using Sum = Loop; - using And = Loop; - using Or = Sum; - }; - - struct Arguments { - template - struct StaticCheck { - using Arg = typename FunctionTraits::template Arg; - using CleanType = typename Arg::CleanType; + using CheckOk = CheckAny; - template - static constexpr bool isType() noexcept - { - using SelectedType = - typename std::conditional< - Clean, - CleanType, - typename Arg::Type - >::type; - return std::is_same::value; - } + static constexpr bool Valid = CheckOk::Valid; + static constexpr bool StaticAssert = CheckOk::StaticAssert; + }; - template - struct SpecialHelper { - using CleanTypeT = typename QtPrivate::RemoveCVRef::Type; - - static constexpr bool TypeMatched = isType(); - static constexpr bool TypeCVRefMatched = isType(); - - static constexpr bool ValidPosition = - (I == FunctionTraits::ArgumentIndexMax || - I == FunctionTraits::ArgumentIndexMax - 1); - static constexpr bool ValidAll = TypeCVRefMatched && ValidPosition; - - static constexpr bool assertCondition = - DisableStaticAssert || !TypeMatched || TypeCVRefMatched; - - static constexpr bool assertConditionOrder = - DisableStaticAssert || !TypeMatched || ValidPosition; - - static constexpr bool staticAssert() noexcept - { - static_assert(assertConditionOrder, - "ViewHandler arguments error: " - "QHttpServerRequest or QHttpServerResponder" - " can only be the last argument"); - return true; - } - }; - - template - struct CheckAny { - static constexpr bool Value = StaticMath::Or::eval(T::Value...); - static constexpr bool Valid = StaticMath::Or::eval(T::Valid...); - static constexpr bool staticAssert() noexcept - { - return StaticMath::Or::eval(T::staticAssert()...); - } - }; - - struct IsRequest { - using Helper = SpecialHelper; - static constexpr bool Value = Helper::TypeMatched; - static constexpr bool Valid = Helper::ValidAll; - - static constexpr bool staticAssert() noexcept - { - static_assert(Helper::assertCondition, - "ViewHandler arguments error: " - "QHttpServerRequest can only be passed as a const reference"); - return Helper::staticAssert(); - } - }; - - struct IsResponder { - using Helper = SpecialHelper; - static constexpr bool Value = Helper::TypeMatched; - static constexpr bool Valid = Helper::ValidAll; - - static constexpr bool staticAssert() noexcept - { - static_assert(Helper::assertCondition, - "ViewHandler arguments error: " - "QHttpServerResponder can only be passed as a universal reference"); - return Helper::staticAssert(); - } - }; - - using IsSpecial = CheckAny; - - struct IsSimple { - static constexpr bool Value = !IsSpecial::Value && - I < FunctionTraits::ArgumentCount && - FunctionTraits::ArgumentIndexMax != -1; - static constexpr bool Valid = Arg::Defined; - - static constexpr bool assertCondition = - DisableStaticAssert || !Value || Valid; - - static constexpr bool staticAssert() noexcept - { - static_assert(assertCondition, - "ViewHandler arguments error: " - "Type is not registered, please use the Q_DECLARE_METATYPE macro " - "to make it known to Qt's meta-object system"); - return true; - } - }; - - using CheckOk = CheckAny; - - static constexpr bool Valid = CheckOk::Valid; - static constexpr bool StaticAssert = CheckOk::staticAssert(); - }; + struct Arguments { template struct ArgumentsReturn { template - using Arg = StaticCheck; + using Arg = ArgumentChecker; template static constexpr int metaTypeId() noexcept @@ -279,9 +106,9 @@ struct ViewTraitsHelper { static_cast(FunctionTraits::template Arg::Defined)...); static constexpr std::size_t PlaceholdersCount = Count - CapturableCount; - static constexpr bool Valid = StaticMath::And::eval(StaticCheck::Valid...); + static constexpr bool Valid = StaticMath::And::eval(Arg::Valid...); static constexpr bool StaticAssert = - StaticMath::And::eval(StaticCheck::StaticAssert...); + StaticMath::And::eval(Arg::StaticAssert...); using Indexes = typename QtPrivate::IndexesList; @@ -317,18 +144,20 @@ struct ViewTraitsHelper { }; }; + } // namespace QtPrivate template struct QHttpServerRouterViewTraits { - using Helpers = typename QtPrivate::ViewTraitsHelper; + using Helpers = typename QtPrivate::RouterViewTraitsHelper; using Arguments = decltype(Helpers::Arguments::eval(typename Helpers::ArgumentIndexes{})); using BindableType = decltype( Helpers::template BindType::eval( typename Arguments::PlaceholdersIndexes{})); }; + QT_END_NAMESPACE #endif // QHTTPSERVERROUTERVIEWTRAITS_H diff --git a/src/httpserver/qhttpserverviewtraits.h b/src/httpserver/qhttpserverviewtraits.h new file mode 100644 index 0000000..0469ffb --- /dev/null +++ b/src/httpserver/qhttpserverviewtraits.h @@ -0,0 +1,109 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Mikhail Svetkin +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERVIEWTRAITS_H +#define QHTTPSERVERVIEWTRAITS_H + +#include + +QT_BEGIN_NAMESPACE + +class QHttpServerRequest; +class QHttpServerResponse; + +namespace QtPrivate { + +template +struct AfterRequestViewTraitsHelper : ViewTraits { + using VTraits = ViewTraits; + using FunctionTraits = typename VTraits::FTraits; + + static_assert(DisableStaticAssert || + FunctionTraits::ArgumentCount == 2 || + FunctionTraits::ArgumentCount == 1, + "ViewHandler arguments error: " + "afterRequest can only accept QHttpServerResponse and QHttpServerRequest"); + + static_assert(DisableStaticAssert || + std::is_same::value, + "ViewHandler return type error: " + "Return type can only be QHttpServerResponse"); + + template + struct ArgumentChecker { + using IsRequest = typename VTraits::template Special; + static_assert(IsRequest::AssertCondition, + "ViewHandler arguments error: " + "QHttpServerRequest can only be passed as a const reference"); + + using IsResponse = typename VTraits::template Special; + static_assert(IsResponse::AssertCondition, + "ViewHandler arguments error: " + "QHttpServerResponse can only be passed as a universal reference"); + + using IsSpecial = CheckAny; + + static constexpr bool Valid = IsSpecial::Valid; + static constexpr bool StaticAssert = IsSpecial::StaticAssert; + }; + + struct Arguments { + template + struct ArgumentsReturn { + template + using Arg = ArgumentChecker; + static constexpr bool Valid = QtPrivate::StaticMath::And::eval(Arg::Valid...); + static constexpr bool StaticAssert = QtPrivate::StaticMath::And::eval( + Arg::StaticAssert...); + using Last = Arg; + static constexpr std::size_t Count = FunctionTraits::ArgumentCount; + }; + + template + static constexpr ArgumentsReturn eval(QtPrivate::IndexesList) noexcept + { + return ArgumentsReturn{}; + } + }; +}; + +} // namespace QtPrivate + +template +struct QHttpServerAfterRequestViewTraits +{ + using Helpers = typename QtPrivate::AfterRequestViewTraitsHelper; + using Arguments = decltype(Helpers::Arguments::eval(typename Helpers::ArgumentIndexes{})); +}; + +QT_END_NAMESPACE + +#endif // QHTTPSERVERVIEWTRAITS_H diff --git a/src/httpserver/qhttpserverviewtraits_impl.h b/src/httpserver/qhttpserverviewtraits_impl.h new file mode 100644 index 0000000..45c46d7 --- /dev/null +++ b/src/httpserver/qhttpserverviewtraits_impl.h @@ -0,0 +1,194 @@ +/**************************************************************************** +** +** Copyright (C) 2020 Mikhail Svetkin +** Copyright (C) 2019 The Qt Company Ltd. +** Contact: https://www.qt.io/licensing/ +** +** This file is part of the QtHttpServer module of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:GPL$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and The Qt Company. For licensing terms +** and conditions see https://www.qt.io/terms-conditions. For further +** information use the contact form at https://www.qt.io/contact-us. +** +** GNU General Public License Usage +** Alternatively, this file may be used under the terms of the GNU +** General Public License version 3 or (at your option) any later version +** approved by the KDE Free Qt Foundation. The licenses are as published by +** the Free Software Foundation and appearing in the file LICENSE.GPL3 +** included in the packaging of this file. Please review the following +** information to ensure the GNU General Public License requirements will +** be met: https://www.gnu.org/licenses/gpl-3.0.html. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef QHTTPSERVERVIEWTRAITS_IMPL_H +#define QHTTPSERVERVIEWTRAITS_IMPL_H + +#include +#include +#include +#include + +#include +#include +#include + +QT_BEGIN_NAMESPACE + +namespace QtPrivate { + +template +struct RemoveCVRef +{ + using Type = typename std::remove_cv::type>::type; +}; + + +template +struct FunctionTraitsHelper +{ + static constexpr const int ArgumentCount = sizeof ... (Args); + static constexpr const int ArgumentIndexMax = ArgumentCount - 1; + static constexpr const bool IsClassMember = classMember; + using ReturnType = ReturnT; + + template + struct Arg { + using Type = typename std::tuple_element>::type; + + using CleanType = typename QtPrivate::RemoveCVRef::Type; + + static constexpr bool Defined = QMetaTypeId2::Defined; + }; +}; + +template +struct FunctionTraitsHelper +{ + static constexpr const int ArgumentCount = 0; + static constexpr const int ArgumentIndexMax = -1; + static constexpr const bool IsClassMember = classMember; + using ReturnType = ReturnT; + + template + struct Arg { + using Type = std::false_type; + using CleanType = Type; + static constexpr bool Defined = QMetaTypeId2::Defined; + }; +}; + +template +struct FunctionTraits; + +template +struct FunctionTraits : public FunctionTraits{}; + +template +struct FunctionTraits + : public FunctionTraitsHelper +{ +}; + +template +struct FunctionTraits + : public FunctionTraitsHelper +{ + using classType = ClassT; +}; + +struct StaticMath { + template class Predicate, bool defaultValue> + struct Loop { + static constexpr bool eval() noexcept { + return defaultValue; + } + + template + static constexpr T eval(const T it, N ...n) noexcept { + return Predicate::eval(it, eval(n...)); + } + }; + + template + struct SumPredicate { + static constexpr T eval(const T rs, const T ls) noexcept + { + return rs + ls; + } + }; + + template + struct AndPredicate { + static constexpr T eval(const T rs, const T ls) noexcept + { + return rs && ls; + } + }; + + using Sum = Loop; + using And = Loop; + using Or = Sum; +}; + +template +struct CheckAny { + static constexpr bool Value = StaticMath::Or::eval(T::Value...); + static constexpr bool Valid = StaticMath::Or::eval(T::Valid...); + static constexpr bool StaticAssert = StaticMath::Or::eval(T::StaticAssert...); +}; + +template +struct ViewTraits { + using FTraits = FunctionTraits; + using ArgumentIndexes = typename Indexes::Value; + + template + struct SpecialHelper { + using Arg = typename FTraits::template Arg; + using CleanSpecialT = typename RemoveCVRef::Type; + + static constexpr bool TypeMatched = std::is_same::value; + static constexpr bool TypeCVRefMatched = std::is_same::value; + + static constexpr bool ValidPosition = + (I == FTraits::ArgumentIndexMax || + I == FTraits::ArgumentIndexMax - 1); + static constexpr bool ValidAll = TypeCVRefMatched && ValidPosition; + + static constexpr bool AssertCondition = + DisableStaticAssert || !TypeMatched || TypeCVRefMatched; + + static constexpr bool AssertConditionOrder = + DisableStaticAssert || !TypeMatched || ValidPosition; + + static constexpr bool StaticAssert = AssertCondition && AssertConditionOrder; + + static_assert(AssertConditionOrder, + "ViewHandler arguments error: " + "QHttpServerRequest or QHttpServerResponder" + " can only be the last argument"); + }; + + template + struct Special { + using Helper = SpecialHelper; + static constexpr bool Value = Helper::TypeMatched; + static constexpr bool Valid = Helper::ValidAll; + static constexpr bool StaticAssert = Helper::StaticAssert; + static constexpr bool AssertCondition = Helper::AssertCondition; + }; +}; + +} // namespace QtPrivate + +QT_END_NAMESPACE + +#endif // QHTTPSERVERVIEWTRAITS_IMPL_H -- cgit v1.2.3