diff --git a/sources/CMakeLists.txt b/sources/CMakeLists.txt index 73d8928..bea789b 100644 --- a/sources/CMakeLists.txt +++ b/sources/CMakeLists.txt @@ -41,8 +41,7 @@ endif () # flags if (CMAKE_COMPILER_IS_GNUCXX) - set (ADD_CXX_FLAGS "-Wall") - set (CMAKE_CXX_FLAGS "-O0 ${ADD_CXX_FLAGS}") + set (CMAKE_CXX_FLAGS "-Wall -std=c++11") set (CMAKE_CXX_FLAGS_DEBUG "-g -O0") set (CMAKE_CXX_FLAGS_RELEASE "-O2 -DNDEBUG") else () diff --git a/sources/dataengine/CMakeLists.txt b/sources/dataengine/CMakeLists.txt index 7663df5..260ba99 100644 --- a/sources/dataengine/CMakeLists.txt +++ b/sources/dataengine/CMakeLists.txt @@ -13,13 +13,15 @@ set (PLUGIN_NAME ${SUBPROJECT}) file (GLOB SUBPROJECT_DESKTOP_IN *.desktop) file (RELATIVE_PATH SUBPROJECT_DESKTOP ${CMAKE_SOURCE_DIR} ${SUBPROJECT_DESKTOP_IN}) file (GLOB SUBPROJECT_SOURCE *.cpp) +set (TASK_HEADER ${CMAKE_SOURCE_DIR}/task.h) file (GLOB SUBPROJECT_CONF *.conf) # prepare configure_file (${SUBPROJECT_DESKTOP_IN} ${CMAKE_CURRENT_BINARY_DIR}/${SUBPROJECT_DESKTOP}) # make -kde4_add_plugin (${PLUGIN_NAME} ${SUBPROJECT_SOURCE}) +qt4_wrap_cpp (TASK_MOC_SOURCE ${TASK_HEADER}) +kde4_add_plugin (${PLUGIN_NAME} ${SUBPROJECT_SOURCE} ${TASK_MOC_SOURCE}) target_link_libraries (${PLUGIN_NAME} ${KDE4_KDECORE_LIBS} ${KDE4_PLASMA_LIBS} ${QT_QTNETWORK_LIBRARY}) # install diff --git a/sources/dataengine/netctl.cpp b/sources/dataengine/netctl.cpp index 492cf7f..1297644 100644 --- a/sources/dataengine/netctl.cpp +++ b/sources/dataengine/netctl.cpp @@ -16,6 +16,7 @@ ***************************************************************************/ #include "netctl.h" +#include "task.h" #include #include @@ -28,6 +29,29 @@ #include +struct TaskResult +{ + int exitCode; + QByteArray output; +}; + + +TaskResult runTask(const QString cmd) +{ + return Task::await( [ & ]() { + QProcess command; + command.start(cmd); + command.waitForFinished(-1); + + TaskResult r; + r.exitCode = command.exitCode(); + r.output = command.readAllStandardOutput(); + + return r; + }); +} + + Netctl::Netctl(QObject *parent, const QVariantList &args) : Plasma::DataEngine(parent, args) { @@ -43,7 +67,6 @@ Netctl::Netctl(QObject *parent, const QVariantList &args) setMinimumPollingInterval(333); readConfiguration(); - setProcesses(); setKeys(); } @@ -51,12 +74,6 @@ Netctl::Netctl(QObject *parent, const QVariantList &args) Netctl::~Netctl() { if (debug) qDebug() << "[DE]" << "[~Netctl]"; - - QStringList processesKeys = processes.keys(); - for (int i=0; iterminate(); - delete processes[processesKeys[i]]; - } } @@ -103,31 +120,6 @@ void Netctl::setKeys() } -void Netctl::setProcesses() -{ - if (debug) qDebug() << "[DE]" << "[setProcesses]"; - - processes[QString("currentProfile")] = new QProcess(); - connect(processes[QString("currentProfile")], SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(setCurrentProfile(int, QProcess::ExitStatus))); - processes[QString("extIp")] = new QProcess(); - connect(processes[QString("extIp")], SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(setExtIp(int, QProcess::ExitStatus))); - processes[QString("extIp6")] = new QProcess(); - connect(processes[QString("extIp6")], SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(setExtIp6(int, QProcess::ExitStatus))); - processes[QString("netctlAuto")] = new QProcess(); - connect(processes[QString("netctlAuto")], SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(setNetctlAutoStatus(int, QProcess::ExitStatus))); - processes[QString("profiles")] = new QProcess(); - connect(processes[QString("profiles")], SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(setProfileList(int, QProcess::ExitStatus))); - processes[QString("statusString")] = new QProcess(); - connect(processes[QString("statusString")], SIGNAL(finished(int, QProcess::ExitStatus)), - this, SLOT(setProfileStringStatus(int, QProcess::ExitStatus))); -} - - void Netctl::readConfiguration() { if (debug) qDebug() << "[DE]" << "[readConfiguration]"; @@ -206,33 +198,22 @@ bool Netctl::sourceRequestEvent(const QString &name) } -void Netctl::getCurrentProfile(const QString cmdNetctl, const QString cmdNetctlAuto) +QString Netctl::getCurrentProfile(const QString cmdNetctl, const QString cmdNetctlAuto) { if (debug) qDebug() << "[DE]" << "[getCurrentProfile]"; getNetctlAutoStatus(cmdNetctlAuto); - if (processes[QString("currentProfile")]->state() != QProcess::NotRunning) return; QString cmd; if (netctlAutoStatus) cmd = cmdNetctlAuto; else cmd = cmdNetctl; if (debug) qDebug() << "[DE]" << "[getCurrentProfile]" << ":" << "Cmd" << cmd; - - processes[QString("currentProfile")]->start(cmd + QString(" list")); -} - - -void Netctl::setCurrentProfile(int exitCode, QProcess::ExitStatus exitStatus) -{ - Q_UNUSED(exitStatus) - if (debug) qDebug() << "[DE]" << "[setCurrentProfile]"; - if (debug) qDebug() << "[DE]" << "[setCurrentProfile]" << ":" << "Cmd returns" << exitCode; + TaskResult process = runTask(cmd + QString(" list")); + if (debug) qDebug() << "[DE]" << "[getCurrentProfile]" << ":" << "Cmd returns" << process.exitCode; currentProfile = QString(""); - QString status = QString("false"); - QString cmdOutput = QTextCodec::codecForMib(106) - ->toUnicode(processes[QString("currentProfile")]->readAllStandardOutput()); + QString cmdOutput = QTextCodec::codecForMib(106)->toUnicode(process.output); QStringList profileList = cmdOutput.split(QChar('\n'), QString::SkipEmptyParts); for (int i=0; istate() != QProcess::NotRunning) return; + TaskResult process = runTask(cmd); + if (debug) qDebug() << "[DE]" << "[getExtIp]" << ":" << "Cmd returns" << process.exitCode; - processes[QString("extIp")]->start(cmd); -} + QString extIp = QTextCodec::codecForMib(106)->toUnicode(process.output).trimmed(); - -void Netctl::setExtIp(int exitCode, QProcess::ExitStatus exitStatus) -{ - Q_UNUSED(exitStatus) - if (debug) qDebug() << "[DE]" << "[setExtIp]"; - if (debug) qDebug() << "[DE]" << "[setExtIp]" << ":" << "Cmd returns" << exitCode; - - QString extIp = QString(""); - QString cmdOutput = QTextCodec::codecForMib(106) - ->toUnicode(processes[QString("extIp")]->readAllStandardOutput()) - .trimmed(); - extIp = cmdOutput; - - setData(QString("extIp"), QString("value"), extIp); -} - - -void Netctl::getExtIp6(const QString cmd) -{ - if (debug) qDebug() << "[DE]" << "[getExtIp6]"; - if (debug) qDebug() << "[DE]" << "[getExtIp6]" << ":" << "Cmd" << cmd; - - if (processes[QString("extIp6")]->state() != QProcess::NotRunning) return; - - processes[QString("extIp6")]->start(cmd); -} - - -void Netctl::setExtIp6(int exitCode, QProcess::ExitStatus exitStatus) -{ - Q_UNUSED(exitStatus) - if (debug) qDebug() << "[DE]" << "[setExtIp6]"; - if (debug) qDebug() << "[DE]" << "[setExtIp6]" << ":" << "Cmd returns" << exitCode; - - QString extIp = QString(""); - QString cmdOutput = QTextCodec::codecForMib(106) - ->toUnicode(processes[QString("extIp6")]->readAllStandardOutput()) - .trimmed(); - extIp = cmdOutput; - - setData(QString("extIp6"), QString("value"), extIp); + return extIp; } @@ -315,59 +253,37 @@ QStringList Netctl::getInterfaceList() } -QString Netctl::getIntIp() +QString Netctl::getIntIp(const QAbstractSocket::NetworkLayerProtocol protocol) { if (debug) qDebug() << "[DE]" << "[getIntIp]"; - QString intIp = QString("127.0.0.1/8"); + QString intIp = QString(""); + if (protocol == QAbstractSocket::IPv4Protocol) + intIp = QString("127.0.0.1/8"); + else if (protocol == QAbstractSocket::IPv6Protocol) + intIp = QString("::1/128"); QList rawList = QNetworkInterface::allAddresses(); for (int i=0; i rawList = QNetworkInterface::allAddresses(); - for (int i=0; istate() != QProcess::NotRunning) return; - - processes[QString("netctlAuto")]->start(cmdNetctlAuto + QString(" list")); -} - - -void Netctl::setNetctlAutoStatus(int exitCode, QProcess::ExitStatus exitStatus) -{ - Q_UNUSED(exitStatus) - if (debug) qDebug() << "[DE]" << "[setNetctlAutoStatus]"; - if (debug) qDebug() << "[DE]" << "[setNetctlAutoStatus]" << ":" << "Cmd returns" << exitCode; + TaskResult process = runTask(cmdNetctlAuto + QString(" list")); + if (debug) qDebug() << "[DE]" << "[getNetctlAutoStatus]" << ":" << "Cmd returns" << process.exitCode; QString status; - QString cmdOutput = QTextCodec::codecForMib(106) - ->toUnicode(processes[QString("netctlAuto")]->readAllStandardOutput()); + QString cmdOutput = QTextCodec::codecForMib(106)->toUnicode(process.output); if (cmdOutput.isEmpty()) { netctlAutoStatus = false; status = QString("false"); @@ -377,69 +293,64 @@ void Netctl::setNetctlAutoStatus(int exitCode, QProcess::ExitStatus exitStatus) status = QString("true"); } - setData(QString("netctlAuto"), QString("value"), status); + return status; } -void Netctl::getProfileList(const QString cmdNetctl, const QString cmdNetctlAuto) +QStringList Netctl::getProfileList(const QString cmdNetctl, const QString cmdNetctlAuto) { if (debug) qDebug() << "[DE]" << "[getProfileList]"; getNetctlAutoStatus(cmdNetctlAuto); - if (processes[QString("profiles")]->state() != QProcess::NotRunning) return; QString cmd; if (netctlAutoStatus) cmd = cmdNetctlAuto; else cmd = cmdNetctl; if (debug) qDebug() << "[DE]" << "[getCurrentProfile]" << ":" << "Cmd" << cmd; + TaskResult process = runTask(cmd + QString(" list")); + if (debug) qDebug() << "[DE]" << "[getCurrentProfile]" << ":" << "Cmd returns" << process.exitCode; - processes[QString("profiles")]->start(cmd + QString(" list")); -} - - -void Netctl::setProfileList(int exitCode, QProcess::ExitStatus exitStatus) -{ - Q_UNUSED(exitStatus) - if (debug) qDebug() << "[DE]" << "[setProfileList]"; - if (debug) qDebug() << "[DE]" << "[setProfileList]" << ":" << "Cmd returns" << exitCode; - - QString cmdOutput = QTextCodec::codecForMib(106) - ->toUnicode(processes[QString("profiles")]->readAllStandardOutput()); + QString cmdOutput = QTextCodec::codecForMib(106)->toUnicode(process.output); QStringList profileList = cmdOutput.split(QChar('\n'), QString::SkipEmptyParts); for (int i=0; istate() != QProcess::NotRunning) return; + QString status = QString("static"); + if (netctlAutoStatus) + status = QString("netctl-auto"); + else { + TaskResult process = runTask(cmdNetctl + QString(" is-enabled ") + getCurrentProfile(cmdNetctl, cmdNetctlAuto)); + if (debug) qDebug() << "[DE]" << "[getProfileStringStatus]" << ":" << "Cmd returns" << process.exitCode; - processes[QString("statusString")]->start(cmdNetctl + QString(" is-enabled ") + currentProfile); + if (process.exitCode == 0) + status = QString("enabled"); + } + + return status; } -void Netctl::setProfileStringStatus(int exitCode, QProcess::ExitStatus exitStatus) +QString Netctl::getStatus(const QString cmdNetctl, const QString cmdNetctlAuto) { - Q_UNUSED(exitStatus) - if (debug) qDebug() << "[DE]" << "[setProfileStringStatus]"; - if (debug) qDebug() << "[DE]" << "[setProfileStringStatus]" << ":" << "Cmd returns" << exitCode; + if (debug) qDebug() << "[DE]" << "[getStatus]"; + getNetctlAutoStatus(cmdNetctlAuto); - QString status = QString("static"); - if (exitCode == 0) - status = QString("enabled"); + QString status = QString("false"); + QString currentProfile = getCurrentProfile(cmdNetctl, cmdNetctlAuto); + if (!currentProfile.isEmpty()) + status = QString("true"); - setData(QString("statusString"), QString("value"), status); + return status; } @@ -448,45 +359,45 @@ bool Netctl::updateSourceEvent(const QString &source) if (debug) qDebug() << "[DE]" << "[updateSourceEvent]"; if (debug) qDebug() << "[DE]" << "[updateSourceEvent]" << ":" << "Source name" << source; + QString value = QString("N\\A"); if (source == QString("currentProfile")) { - getCurrentProfile(configuration[QString("CMD")], + value = getCurrentProfile(configuration[QString("CMD")], configuration[QString("NETCTLAUTOCMD")]); } else if (source == QString("extIp")) { if (configuration[QString("EXTIP")] == QString("true")) - getExtIp(configuration[QString("EXTIPCMD")]); + value = getExtIp(configuration[QString("EXTIPCMD")]); } else if (source == QString("extIp6")) { if (configuration[QString("EXTIP6")] == QString("true")) - getExtIp(configuration[QString("EXTIP6CMD")]); + value = getExtIp(configuration[QString("EXTIP6CMD")]); } else if (source == QString("interfaces")) { - QString value = getInterfaceList().join(QChar(',')); - setData(source, QString("value"), value); + value = getInterfaceList().join(QChar(',')); } else if (source == QString("intIp")) { - QString value = getIntIp(); - setData(source, QString("value"), value); + value = getIntIp(QAbstractSocket::IPv4Protocol); } else if (source == QString("intIp6")) { - QString value = getIntIp6(); - setData(source, QString("value"), value); + value = getIntIp(QAbstractSocket::IPv6Protocol); } else if (source == QString("netctlAuto")) { - getNetctlAutoStatus(configuration[QString("NETCTLAUTOCMD")]); + value = getNetctlAutoStatus(configuration[QString("NETCTLAUTOCMD")]); } else if (source == QString("profiles")) { - getProfileList(configuration[QString("CMD")], - configuration[QString("NETCTLAUTOCMD")]); + value = getProfileList(configuration[QString("CMD")], + configuration[QString("NETCTLAUTOCMD")]) + .join(QChar(',')); } else if (source == QString("statusBool")) { - getCurrentProfile(configuration[QString("CMD")], + value = getCurrentProfile(configuration[QString("CMD")], configuration[QString("NETCTLAUTOCMD")]); } else if (source == QString("statusString")) { - getProfileStringStatus(configuration[QString("CMD")], + value = getStatus(configuration[QString("CMD")], configuration[QString("NETCTLAUTOCMD")]); } + setData(source, QString("value"), value); return true; } diff --git a/sources/dataengine/netctl.h b/sources/dataengine/netctl.h index c9ea304..fcbe3a8 100644 --- a/sources/dataengine/netctl.h +++ b/sources/dataengine/netctl.h @@ -19,7 +19,7 @@ #define NETCTL_DE_H #include -#include +#include class Netctl : public Plasma::DataEngine @@ -29,40 +29,28 @@ class Netctl : public Plasma::DataEngine public: Netctl(QObject *parent, const QVariantList &args); ~Netctl(); - void getCurrentProfile(const QString cmdNetctl, const QString cmdNetctlAuto); - void getExtIp(const QString cmd); - void getExtIp6(const QString cmd); + QString getCurrentProfile(const QString cmdNetctl, const QString cmdNetctlAuto); + QString getExtIp(const QString cmd); QStringList getInterfaceList(); - QString getIntIp(); - QString getIntIp6(); - void getNetctlAutoStatus(const QString cmdNetctlAuto); - void getProfileList(const QString cmdNetctl, const QString cmdNetctlAuto); - void getProfileStringStatus(const QString cmdNetctl, const QString cmdNetctlAuto); + QString getIntIp(const QAbstractSocket::NetworkLayerProtocol protocol); + QString getNetctlAutoStatus(const QString cmdNetctlAuto); + QStringList getProfileList(const QString cmdNetctl, const QString cmdNetctlAuto); + QString getProfileStringStatus(const QString cmdNetctl, const QString cmdNetctlAuto); + QString getStatus(const QString cmdNetctl, const QString cmdNetctlAuto); protected: bool sourceRequestEvent(const QString &name); bool updateSourceEvent(const QString &source); QStringList sources() const; -private slots: - void setCurrentProfile(int exitCode, QProcess::ExitStatus exitStatus); - void setExtIp(int exitCode, QProcess::ExitStatus exitStatus); - void setExtIp6(int exitCode, QProcess::ExitStatus exitStatus); - void setNetctlAutoStatus(int exitCode, QProcess::ExitStatus exitStatus); - void setProfileList(int exitCode, QProcess::ExitStatus exitStatus); - void setProfileStringStatus(int exitCode, QProcess::ExitStatus exitStatus); - private: bool netctlAutoStatus; QString currentProfile; - // processes - QMap processes; // configuration bool debug; QMap configuration; void initValues(); void setKeys(); - void setProcesses(); void readConfiguration(); QMap updateConfiguration(const QMap rawConfig); }; diff --git a/sources/task.h b/sources/task.h new file mode 100644 index 0000000..bc1259e --- /dev/null +++ b/sources/task.h @@ -0,0 +1,385 @@ +/* + * copyright: 2014 + * name : mhogo mchungu + * email: mhogomchungu@gmail.com + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS + * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE + * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT + * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#ifndef __TASK_H_INCLUDED__ +#define __TASK_H_INCLUDED__ + +#include +#include +#include +#include +#include + +/* + * + * Examples on how to use the library are at the end of this file. + * + */ + +namespace Task +{ + class Thread : public QThread + { + Q_OBJECT + public: + Thread() + { + connect( this,SIGNAL( finished() ),this,SLOT( deleteLater() ) ) ; + } + protected: + virtual ~Thread() + { + } + private: + virtual void run( void ) + { + } + }; + + template< typename T > + class future + { + public: + future() : m_function( []( T t ){ Q_UNUSED( t ) ; } ) + { + } + void setActions( std::function< void( void ) > start, + std::function< void( void ) > cancel, + std::function< T ( void ) > get ) + { + m_start = std::move( start ) ; + m_cancel = std::move( cancel ) ; + m_get = std::move( get ) ; + } + void then( std::function< void( T ) > function ) + { + m_function = std::move( function ) ; + m_start() ; + } + T get() + { + return m_get() ; + } + T await() + { + QEventLoop p ; + + T q ; + + m_function = [ & ]( T r ){ q = std::move( r ) ; p.exit() ; } ; + + m_start() ; + + p.exec() ; + + return q ; + } + void start() + { + m_start() ; + } + void cancel() + { + m_cancel() ; + } + void run( T r ) + { + m_function( std::move( r ) ) ; + } + private: + std::function< void( T ) > m_function ; + std::function< void( void ) > m_start ; + std::function< void( void ) > m_cancel ; + std::function< T ( void ) > m_get ; + }; + + template< typename T > + class ThreadHelper : public Thread + { + public: + ThreadHelper( std::function< T ( void ) >&& function ) : m_function( std::move( function ) ) + { + } + future& Future( void ) + { + m_future.setActions( [ this ](){ this->start() ; }, + [ this ](){ this->deleteLater() ; }, + [ this ](){ T r = m_function() ; this->deleteLater() ; return r ; } ) ; + return m_future ; + } + private: + ~ThreadHelper() + { + m_future.run( std::move( m_cargo ) ) ; + } + void run( void ) + { + m_cargo = m_function() ; + } + std::function< T ( void ) > m_function ; + future m_future ; + T m_cargo ; + }; + + class future_1 + { + public: + future_1() : m_function( [](){} ) + { + } + void setActions( std::function< void( void ) > start, + std::function< void( void ) > cancel, + std::function< void( void ) > get ) + { + m_start = std::move( start ) ; + m_cancel = std::move( cancel ) ; + m_get = std::move( get ) ; + } + void then( std::function< void( void ) > function ) + { + m_function = std::move( function ) ; + m_start() ; + } + void get() + { + m_get() ; + } + void await() + { + QEventLoop p ; + + m_function = [ & ](){ p.exit() ; } ; + + m_start() ; + + p.exec() ; + } + void start() + { + m_start() ; + } + void run() + { + m_function() ; + } + void cancel() + { + m_cancel() ; + } + private: + std::function< void( void ) > m_function ; + std::function< void( void ) > m_start ; + std::function< void( void ) > m_cancel ; + std::function< void( void ) > m_get ; + }; + + class ThreadHelper_1 : public Thread + { + public: + ThreadHelper_1( std::function< void ( void ) >&& function ) : m_function( std::move( function ) ) + { + } + future_1& Future( void ) + { + m_future.setActions( [ this ](){ this->start() ; }, + [ this ](){ this->deleteLater() ; }, + [ this ](){ m_function() ; this->deleteLater() ; } ) ; + return m_future ; + } + private: + ~ThreadHelper_1() + { + m_future.run() ; + } + void run( void ) + { + m_function() ; + } + std::function< void ( void ) > m_function ; + future_1 m_future ; + }; + + /* + * Below APIs runs two tasks,the first one will run in a different thread and + * the second one will be run on the original thread after the completion of the + * first one. + */ + + template< typename T > + future& run( std::function< T ( void ) > function ) + { + auto t = new ThreadHelper( std::move( function ) ) ; + return t->Future() ; + } + + static inline future_1& run( std::function< void( void ) > function ) + { + auto t = new ThreadHelper_1( std::move( function ) ) ; + return t->Future() ; + } + + static inline void exec( std::function< void( void ) > function ) + { + Task::run( std::move( function ) ).start() ; + } + + /* + * Below APIs implements resumable functions where a function will be "blocked" + * waiting for the function to return without "hanging" the current thread. + * + * recommending reading up on C#'s await keyword to get a sense of what is being + * discussed below. + */ + + static inline void await( Task::future_1& e ) + { + e.await() ; + } + + static inline void await( std::function< void( void ) > function ) + { + Task::run( std::move( function ) ).await() ; + } + + template< typename T > + T await( std::function< T ( void ) > function ) + { + return Task::run( std::move( function ) ).await() ; + } + + template< typename T > + T await( Task::future& e ) + { + return e.await() ; + } + + template< typename T > + T await( std::future&& t ) + { + return Task::await( [ & ](){ return t.get() ; } ) ; + } +} + +#if 0 + +/* + * Examples on how to use the library + */ +/* + * templated version that passes a return value of one function to another function + */ +auto _a = [](){ + /* + * task _a does what task _a does here. + * + * This function body will run on a different thread + */ + return 0 ; +} + +auto _b = []( int r ){ + /* + * + * task _b does what task _b does here. + * + * r is a const reference to a value returned by _a + * + * This function body will run on the original thread + */ +} + +Task::run( _a ).then( _b ) ; + +alternatively, + +Task::future& e = Task::run( _a ) ; + +e.then( _b ) ; + +/* + * Non templated version that does not pass around return value + */ +auto _c = [](){ + /* + * task _a does what task _a does here. + * + * This function body will run on a different thread + */ +} + +auto _d = [](){ + /* + * task _b does what task _b does here. + * + * r is a const reference to a value returned by _a + * + * This function body will run on the original thread + */ +} + +Task::run( _c ).then( _d ) ; + +/* + * if no continuation + */ +Task::exec( _c ) ; + +/* + * Task::await() is used to "block" without "hanging" the calling thread until the function returns. + * + * Its use case is to do sync programming without hanging the calling thread. + * + * example use case for it is to "block" on function in a GUI thread withough blocking the GUI thread + * hanging the application. + */ + +/* + * await example when the called function return no result + */ +Task::await( _c ) ; + +/* + * await example when the called function return a result + */ +int r = Task::await( _a ) ; + +alternatively, + +Task::future& e = Task::run( _a ) ; + +int r = e.await() ; + +alternatively, + +int r = Task::run( _a ).await() ; + +#endif + +#endif //__TASK_H_INCLUDED__