/* * This file Copyright (C) 2016 Mnemosyne LLC * * It may be used under the GNU GPL versions 2 or 3 * or any future license endorsed by Mnemosyne LLC. * */ #pragma once #include #include #include #include #include #include #include #include "RpcClient.h" class RpcQueue: public QObject { Q_OBJECT public: explicit RpcQueue (QObject * parent = nullptr); void setTolerateErrors (bool tolerateErrors = true) { myTolerateErrors = tolerateErrors; } template void add (Func func) { myQueue.enqueue (qMakePair (normalizeFunc (func), ErrorHandlerFunction ())); } template void add (Func func, ErrorHandler errorHandler) { myQueue.enqueue (qMakePair (normalizeFunc (func), normalizeErrorHandler (errorHandler))); } RpcResponseFuture future (); // The first function in queue is ran synchronously // (hence it may be e. g. a lambda capturing local variables by reference). void run (); private: // Internally queued function. Takes the last response future, makes a // request and returns a new response future. typedef std::function QueuedFunction; // Internally stored error handler function. Takes the last response future and returns nothing. typedef std::function ErrorHandlerFunction; private slots: void stepFinished (); private: void runNext (const RpcResponseFuture& response); // These overloads convert various forms of input closures to what we store internally. // normal closure, takes response and returns new future template ::type, RpcResponseFuture>::value>::type * = nullptr> QueuedFunction normalizeFunc (const Func& func) { return [func] (const RpcResponseFuture& r) { return func (r.result ()); }; } // closure without argument (first step), takes nothing and returns new future template ::type, RpcResponseFuture>::value>::type * = nullptr> QueuedFunction normalizeFunc (const Func& func) { return [func] (const RpcResponseFuture&) { return func (); }; } // closure without return value ("auxiliary"), takes response and returns nothing -- internally we reuse the last future template ::type, void>::value>::type * = nullptr> QueuedFunction normalizeFunc (const Func& func) { return [func] (const RpcResponseFuture& r) { func (r.result ()); return r; }; } // closure without argument and return value, takes nothing and returns nothing -- next function will also get nothing template ::type, void>::value>::type * = nullptr> QueuedFunction normalizeFunc (const Func& func) { return [func] (const RpcResponseFuture& r) { func (); return r; }; } // normal error handler, takes last response template ::type, void>::value>::type * = nullptr> ErrorHandlerFunction normalizeErrorHandler (const Func& func) { return [func] (const RpcResponseFuture& r) { func (r.result ()); }; } // error handler without an argument, takes nothing template ::type, void>::value>::type * = nullptr> ErrorHandlerFunction normalizeErrorHandler (const Func& func) { return [func] (const RpcResponseFuture& r) { func (); }; } private: bool myTolerateErrors; QFutureInterface myPromise; QQueue> myQueue; ErrorHandlerFunction myNextErrorHandler; QFutureWatcher myFutureWatcher; };