forked from qt-creator/qt-creator
TaskTree: Make it possible to tweak the success bit in done handler
Make the arguments of done handler optional. Task-number: QTCREATORBUG-29834 Change-Id: I9c2af431feca87351c8c9129e61ce3889d137de5 Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
@@ -956,15 +956,14 @@ void GroupItem::addChildren(const QList<GroupItem> &children)
|
|||||||
GroupItem GroupItem::withTimeout(const GroupItem &item, milliseconds timeout,
|
GroupItem GroupItem::withTimeout(const GroupItem &item, milliseconds timeout,
|
||||||
const GroupEndHandler &handler)
|
const GroupEndHandler &handler)
|
||||||
{
|
{
|
||||||
const TimeoutTask::EndFunction taskHandler = handler
|
const auto onSetup = [timeout](milliseconds &timeoutData) { timeoutData = timeout; };
|
||||||
? [handler](const milliseconds &) { handler(); } : TimeoutTask::EndFunction();
|
|
||||||
return Group {
|
return Group {
|
||||||
parallel,
|
parallel,
|
||||||
stopOnFinished,
|
stopOnFinished,
|
||||||
Group {
|
Group {
|
||||||
finishAllAndError,
|
finishAllAndError,
|
||||||
TimeoutTask([timeout](milliseconds &timeoutData) { timeoutData = timeout; },
|
handler ? TimeoutTask(onSetup, [handler] { handler(); }, CallDoneIf::Success)
|
||||||
taskHandler, CallDoneIf::Success)
|
: TimeoutTask(onSetup)
|
||||||
},
|
},
|
||||||
item
|
item
|
||||||
};
|
};
|
||||||
@@ -1089,7 +1088,7 @@ public:
|
|||||||
// in order to unwind properly.
|
// in order to unwind properly.
|
||||||
SetupResult start();
|
SetupResult start();
|
||||||
void stop();
|
void stop();
|
||||||
void invokeDoneHandler(bool success);
|
bool invokeDoneHandler(bool success);
|
||||||
bool isRunning() const { return m_task || m_container.isRunning(); }
|
bool isRunning() const { return m_task || m_container.isRunning(); }
|
||||||
bool isTask() const { return bool(m_taskHandler.m_createHandler); }
|
bool isTask() const { return bool(m_taskHandler.m_createHandler); }
|
||||||
int taskCount() const { return isTask() ? 1 : m_container.m_constData.m_taskCount; }
|
int taskCount() const { return isTask() ? 1 : m_container.m_constData.m_taskCount; }
|
||||||
@@ -1451,14 +1450,14 @@ SetupResult TaskNode::start()
|
|||||||
const std::shared_ptr<SetupResult> unwindAction
|
const std::shared_ptr<SetupResult> unwindAction
|
||||||
= std::make_shared<SetupResult>(SetupResult::Continue);
|
= std::make_shared<SetupResult>(SetupResult::Continue);
|
||||||
QObject::connect(m_task.get(), &TaskInterface::done, taskTree(), [=](bool success) {
|
QObject::connect(m_task.get(), &TaskInterface::done, taskTree(), [=](bool success) {
|
||||||
invokeDoneHandler(success);
|
const bool result = invokeDoneHandler(success);
|
||||||
QObject::disconnect(m_task.get(), &TaskInterface::done, taskTree(), nullptr);
|
QObject::disconnect(m_task.get(), &TaskInterface::done, taskTree(), nullptr);
|
||||||
m_task.release()->deleteLater();
|
m_task.release()->deleteLater();
|
||||||
QTC_ASSERT(parentContainer() && parentContainer()->isRunning(), return);
|
QTC_ASSERT(parentContainer() && parentContainer()->isRunning(), return);
|
||||||
if (parentContainer()->isStarting())
|
if (parentContainer()->isStarting())
|
||||||
*unwindAction = toSetupResult(success);
|
*unwindAction = toSetupResult(result);
|
||||||
else
|
else
|
||||||
parentContainer()->childDone(success);
|
parentContainer()->childDone(result);
|
||||||
});
|
});
|
||||||
|
|
||||||
m_task->start();
|
m_task->start();
|
||||||
@@ -1490,11 +1489,13 @@ static bool shouldCall(CallDoneIf callDoneIf, bool success)
|
|||||||
return callDoneIf != CallDoneIf::Success;
|
return callDoneIf != CallDoneIf::Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TaskNode::invokeDoneHandler(bool success)
|
bool TaskNode::invokeDoneHandler(bool success)
|
||||||
{
|
{
|
||||||
|
bool result = success;
|
||||||
if (m_taskHandler.m_doneHandler && shouldCall(m_taskHandler.m_callDoneIf, success))
|
if (m_taskHandler.m_doneHandler && shouldCall(m_taskHandler.m_callDoneIf, success))
|
||||||
invokeHandler(parentContainer(), m_taskHandler.m_doneHandler, *m_task.get(), success);
|
result = invokeHandler(parentContainer(), m_taskHandler.m_doneHandler, *m_task.get(), success);
|
||||||
m_container.m_constData.m_taskTreePrivate->advanceProgress(1);
|
m_container.m_constData.m_taskTreePrivate->advanceProgress(1);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@@ -147,8 +147,8 @@ public:
|
|||||||
using TaskCreateHandler = std::function<TaskInterface *(void)>;
|
using TaskCreateHandler = std::function<TaskInterface *(void)>;
|
||||||
// Called prior to task start, just after createHandler
|
// Called prior to task start, just after createHandler
|
||||||
using TaskSetupHandler = std::function<SetupResult(TaskInterface &)>;
|
using TaskSetupHandler = std::function<SetupResult(TaskInterface &)>;
|
||||||
// Called on task done, just before delete later
|
// Called on task done, just before deleteLater
|
||||||
using TaskDoneHandler = std::function<void(const TaskInterface &, bool)>;
|
using TaskDoneHandler = std::function<bool(const TaskInterface &, bool)>;
|
||||||
// Called when group entered
|
// Called when group entered
|
||||||
using GroupSetupHandler = std::function<SetupResult()>;
|
using GroupSetupHandler = std::function<SetupResult()>;
|
||||||
// Called when group done / error
|
// Called when group done / error
|
||||||
@@ -335,20 +335,14 @@ public:
|
|||||||
"The Adapter type for the CustomTask<Adapter> needs to be derived from "
|
"The Adapter type for the CustomTask<Adapter> needs to be derived from "
|
||||||
"TaskAdapter<Task>.");
|
"TaskAdapter<Task>.");
|
||||||
using SetupFunction = std::function<void(const Task &)>;
|
using SetupFunction = std::function<void(const Task &)>;
|
||||||
using DoneFunction = std::function<void(const Task &, bool)>;
|
using DoneFunction = std::function<bool(const Task &, bool)>;
|
||||||
using EndFunction = std::function<void(const Task &)>;
|
|
||||||
static Adapter *createAdapter() { return new Adapter; }
|
static Adapter *createAdapter() { return new Adapter; }
|
||||||
CustomTask() : GroupItem({&createAdapter}) {}
|
|
||||||
template <typename SetupHandler = SetupFunction>
|
|
||||||
CustomTask(SetupHandler &&setup, const EndFunction &done, CallDoneIf callDoneIf)
|
|
||||||
: GroupItem({&createAdapter, wrapSetup(std::forward<SetupHandler>(setup)), wrapEnd(done),
|
|
||||||
callDoneIf}) {}
|
|
||||||
|
|
||||||
template <typename SetupHandler>
|
template <typename SetupHandler = SetupFunction, typename DoneHandler = DoneFunction>
|
||||||
CustomTask(SetupHandler &&setup, const DoneFunction &done = {},
|
CustomTask(SetupHandler &&setup = SetupFunction(), DoneHandler &&done = DoneFunction(),
|
||||||
CallDoneIf callDoneIf = CallDoneIf::SuccessOrError)
|
CallDoneIf callDoneIf = CallDoneIf::SuccessOrError)
|
||||||
: GroupItem({&createAdapter, wrapSetup(std::forward<SetupHandler>(setup)), wrapDone(done),
|
: GroupItem({&createAdapter, wrapSetup(std::forward<SetupHandler>(setup)),
|
||||||
callDoneIf})
|
wrapDone(std::forward<DoneHandler>(done)), callDoneIf})
|
||||||
{}
|
{}
|
||||||
|
|
||||||
GroupItem withTimeout(std::chrono::milliseconds timeout,
|
GroupItem withTimeout(std::chrono::milliseconds timeout,
|
||||||
@@ -357,17 +351,17 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
template<typename SetupHandler>
|
template<typename Handler>
|
||||||
static GroupItem::TaskSetupHandler wrapSetup(SetupHandler &&handler) {
|
static GroupItem::TaskSetupHandler wrapSetup(Handler &&handler) {
|
||||||
if constexpr (std::is_same_v<SetupHandler, std::function<void()>>)
|
if constexpr (std::is_same_v<Handler, SetupFunction>)
|
||||||
return {}; // When user passed {} for setup handler.
|
return {}; // When user passed {} for the setup handler.
|
||||||
static constexpr bool isDynamic = std::is_same_v<SetupResult,
|
static constexpr bool isDynamic
|
||||||
std::invoke_result_t<std::decay_t<SetupHandler>, typename Adapter::TaskType &>>;
|
= std::is_same_v<SetupResult, std::invoke_result_t<std::decay_t<Handler>, Task &>>;
|
||||||
constexpr bool isVoid = std::is_same_v<void,
|
constexpr bool isVoid
|
||||||
std::invoke_result_t<std::decay_t<SetupHandler>, typename Adapter::TaskType &>>;
|
= std::is_same_v<void, std::invoke_result_t<std::decay_t<Handler>, Task &>>;
|
||||||
static_assert(isDynamic || isVoid,
|
static_assert(isDynamic || isVoid,
|
||||||
"Task setup handler needs to take (Task &) as an argument and has to return "
|
"Task setup handler needs to take (Task &) as an argument (optionally) and has to "
|
||||||
"void or SetupResult. The passed handler doesn't fulfill these requirements.");
|
"return void or SetupResult. The passed handler doesn't fulfill these requirements.");
|
||||||
return [=](TaskInterface &taskInterface) {
|
return [=](TaskInterface &taskInterface) {
|
||||||
Adapter &adapter = static_cast<Adapter &>(taskInterface);
|
Adapter &adapter = static_cast<Adapter &>(taskInterface);
|
||||||
if constexpr (isDynamic)
|
if constexpr (isDynamic)
|
||||||
@@ -377,21 +371,42 @@ private:
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
static TaskDoneHandler wrapEnd(const EndFunction &handler) {
|
template<typename Handler>
|
||||||
if (!handler)
|
static GroupItem::TaskDoneHandler wrapDone(Handler &&handler) {
|
||||||
return {};
|
if constexpr (std::is_same_v<Handler, DoneFunction>)
|
||||||
return [handler](const TaskInterface &taskInterface, bool) {
|
return {}; // When user passed {} for the done handler.
|
||||||
|
static constexpr bool is2ArgDynamic
|
||||||
|
= std::is_invocable_r_v<bool, std::decay_t<Handler>, const Task &, bool>;
|
||||||
|
static constexpr bool is1ArgDynamic
|
||||||
|
= std::is_invocable_r_v<bool, std::decay_t<Handler>, const Task &>;
|
||||||
|
static constexpr bool is0ArgDynamic
|
||||||
|
= std::is_invocable_r_v<bool, std::decay_t<Handler>>;
|
||||||
|
static constexpr bool is2ArgVoid
|
||||||
|
= std::is_invocable_r_v<void, std::decay_t<Handler>, const Task &, bool>;
|
||||||
|
static constexpr bool is1ArgVoid
|
||||||
|
= std::is_invocable_r_v<void, std::decay_t<Handler>, const Task &>;
|
||||||
|
static constexpr bool is0ArgVoid
|
||||||
|
= std::is_invocable_r_v<void, std::decay_t<Handler>>;
|
||||||
|
static constexpr bool isInvocable = is2ArgDynamic || is1ArgDynamic || is0ArgDynamic
|
||||||
|
|| is2ArgVoid || is1ArgVoid || is0ArgVoid;
|
||||||
|
static_assert(isInvocable,
|
||||||
|
"Task done handler needs to take (const Task &, bool) as arguments (optionally) and "
|
||||||
|
"has to return void or bool. The passed handler doesn't fulfill these requirements.");
|
||||||
|
return [=](const TaskInterface &taskInterface, bool success) {
|
||||||
const Adapter &adapter = static_cast<const Adapter &>(taskInterface);
|
const Adapter &adapter = static_cast<const Adapter &>(taskInterface);
|
||||||
handler(*adapter.task());
|
if constexpr (is2ArgDynamic)
|
||||||
};
|
return std::invoke(handler, *adapter.task(), success);
|
||||||
};
|
if constexpr (is1ArgDynamic)
|
||||||
|
return std::invoke(handler, *adapter.task());
|
||||||
static TaskDoneHandler wrapDone(const DoneFunction &handler) {
|
if constexpr (is0ArgDynamic)
|
||||||
if (!handler)
|
return std::invoke(handler);
|
||||||
return {};
|
if constexpr (is2ArgVoid)
|
||||||
return [handler](const TaskInterface &taskInterface, bool success) {
|
std::invoke(handler, *adapter.task(), success);
|
||||||
const Adapter &adapter = static_cast<const Adapter &>(taskInterface);
|
else if constexpr (is1ArgVoid)
|
||||||
handler(*adapter.task(), success);
|
std::invoke(handler, *adapter.task());
|
||||||
|
else if constexpr (is0ArgVoid)
|
||||||
|
std::invoke(handler);
|
||||||
|
return success;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
@@ -429,9 +444,9 @@ public:
|
|||||||
|
|
||||||
template <typename StorageStruct, typename StorageHandler>
|
template <typename StorageStruct, typename StorageHandler>
|
||||||
void onStorageSetup(const TreeStorage<StorageStruct> &storage, StorageHandler &&handler) {
|
void onStorageSetup(const TreeStorage<StorageStruct> &storage, StorageHandler &&handler) {
|
||||||
constexpr bool isInvokable = std::is_invocable_v<std::decay_t<StorageHandler>,
|
constexpr bool isInvocable = std::is_invocable_v<std::decay_t<StorageHandler>,
|
||||||
StorageStruct &>;
|
StorageStruct &>;
|
||||||
static_assert(isInvokable,
|
static_assert(isInvocable,
|
||||||
"Storage setup handler needs to take (Storage &) as an argument. "
|
"Storage setup handler needs to take (Storage &) as an argument. "
|
||||||
"The passed handler doesn't fulfill these requirements.");
|
"The passed handler doesn't fulfill these requirements.");
|
||||||
setupStorageHandler(storage,
|
setupStorageHandler(storage,
|
||||||
@@ -439,9 +454,9 @@ public:
|
|||||||
}
|
}
|
||||||
template <typename StorageStruct, typename StorageHandler>
|
template <typename StorageStruct, typename StorageHandler>
|
||||||
void onStorageDone(const TreeStorage<StorageStruct> &storage, StorageHandler &&handler) {
|
void onStorageDone(const TreeStorage<StorageStruct> &storage, StorageHandler &&handler) {
|
||||||
constexpr bool isInvokable = std::is_invocable_v<std::decay_t<StorageHandler>,
|
constexpr bool isInvocable = std::is_invocable_v<std::decay_t<StorageHandler>,
|
||||||
const StorageStruct &>;
|
const StorageStruct &>;
|
||||||
static_assert(isInvokable,
|
static_assert(isInvocable,
|
||||||
"Storage done handler needs to take (const Storage &) as an argument. "
|
"Storage done handler needs to take (const Storage &) as an argument. "
|
||||||
"The passed handler doesn't fulfill these requirements.");
|
"The passed handler doesn't fulfill these requirements.");
|
||||||
setupStorageHandler(storage,
|
setupStorageHandler(storage,
|
||||||
|
@@ -223,9 +223,10 @@ void tst_Tasking::testTree_data()
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto setupDone = [storage](int taskId) {
|
const auto setupDone = [storage](int taskId, bool successTask = true) {
|
||||||
return [storage, taskId](const TaskObject &, bool success) {
|
return [storage, taskId, successTask](const TaskObject &, bool success) {
|
||||||
storage->m_log.append({taskId, success ? Handler::Done : Handler::Error});
|
storage->m_log.append({taskId, successTask && success ? Handler::Done : Handler::Error});
|
||||||
|
return successTask && success;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -237,14 +238,7 @@ void tst_Tasking::testTree_data()
|
|||||||
|
|
||||||
const auto createTask = [storage, setupTask, setupDone](
|
const auto createTask = [storage, setupTask, setupDone](
|
||||||
int taskId, bool successTask, milliseconds timeout = 0ms) -> GroupItem {
|
int taskId, bool successTask, milliseconds timeout = 0ms) -> GroupItem {
|
||||||
if (successTask)
|
return TestTask(setupTask(taskId, timeout), setupDone(taskId, successTask));
|
||||||
return TestTask(setupTask(taskId, timeout), setupDone(taskId));
|
|
||||||
const Group root {
|
|
||||||
finishAllAndError,
|
|
||||||
TestTask(setupTask(taskId, timeout)),
|
|
||||||
onGroupError([storage, taskId] { storage->m_log.append({taskId, Handler::Error}); })
|
|
||||||
};
|
|
||||||
return root;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const auto createSuccessTask = [createTask](int taskId, milliseconds timeout = 0ms) {
|
const auto createSuccessTask = [createTask](int taskId, milliseconds timeout = 0ms) {
|
||||||
|
Reference in New Issue
Block a user