async: add Promise and use it for AsyncDialogBox
This commit is contained in:
parent
4f868a1f3c
commit
0302bfdc22
7 changed files with 208 additions and 36 deletions
|
|
@ -59,8 +59,7 @@ void CAsyncDialogBox::onWrite(int fd, uint32_t mask) {
|
|||
if (mask & (WL_EVENT_HANGUP | WL_EVENT_ERROR)) {
|
||||
Debug::log(LOG, "CAsyncDialogBox: dialog {:x} hung up, closed.");
|
||||
|
||||
if (m_onResolution)
|
||||
m_onResolution(m_stdout);
|
||||
m_promiseResolver->resolve(m_stdout);
|
||||
|
||||
wl_event_source_remove(m_readEventSource);
|
||||
m_selfReference.reset();
|
||||
|
|
@ -68,9 +67,7 @@ void CAsyncDialogBox::onWrite(int fd, uint32_t mask) {
|
|||
}
|
||||
}
|
||||
|
||||
void CAsyncDialogBox::open(std::function<void(std::string)> onResolution) {
|
||||
m_onResolution = onResolution;
|
||||
|
||||
SP<CPromise<std::string>> CAsyncDialogBox::open() {
|
||||
std::string buttonsString = "";
|
||||
for (auto& b : m_buttons) {
|
||||
buttonsString += b + ";";
|
||||
|
|
@ -83,7 +80,7 @@ void CAsyncDialogBox::open(std::function<void(std::string)> onResolution) {
|
|||
int outPipe[2];
|
||||
if (pipe(outPipe)) {
|
||||
Debug::log(ERR, "CAsyncDialogBox::open: failed to pipe()");
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_pipeReadFd = CFileDescriptor(outPipe[0]);
|
||||
|
|
@ -94,7 +91,7 @@ void CAsyncDialogBox::open(std::function<void(std::string)> onResolution) {
|
|||
|
||||
if (!m_readEventSource) {
|
||||
Debug::log(ERR, "CAsyncDialogBox::open: failed to add read fd to loop");
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_selfReference = m_selfWeakReference.lock();
|
||||
|
|
@ -102,13 +99,17 @@ void CAsyncDialogBox::open(std::function<void(std::string)> onResolution) {
|
|||
if (!proc.runAsync()) {
|
||||
Debug::log(ERR, "CAsyncDialogBox::open: failed to run async");
|
||||
wl_event_source_remove(m_readEventSource);
|
||||
return;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
m_dialogPid = proc.pid();
|
||||
|
||||
// close the write fd, only the dialog owns it now
|
||||
close(outPipe[1]);
|
||||
|
||||
auto promise = CPromise<std::string>::make([this](SP<CPromiseResolver<std::string>> r) { m_promiseResolver = r; });
|
||||
|
||||
return promise;
|
||||
}
|
||||
|
||||
void CAsyncDialogBox::kill() {
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "../macros.hpp"
|
||||
#include "./memory/Memory.hpp"
|
||||
#include "./defer/Promise.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
|
@ -15,29 +16,30 @@ class CAsyncDialogBox {
|
|||
public:
|
||||
static SP<CAsyncDialogBox> create(const std::string& title, const std::string& description, std::vector<std::string> buttons);
|
||||
|
||||
CAsyncDialogBox(const CAsyncDialogBox&) = delete;
|
||||
CAsyncDialogBox(CAsyncDialogBox&&) = delete;
|
||||
CAsyncDialogBox& operator=(const CAsyncDialogBox&) = delete;
|
||||
CAsyncDialogBox& operator=(CAsyncDialogBox&&) = delete;
|
||||
CAsyncDialogBox(const CAsyncDialogBox&) = delete;
|
||||
CAsyncDialogBox(CAsyncDialogBox&&) = delete;
|
||||
CAsyncDialogBox& operator=(const CAsyncDialogBox&) = delete;
|
||||
CAsyncDialogBox& operator=(CAsyncDialogBox&&) = delete;
|
||||
|
||||
void open(std::function<void(std::string)> onResolution);
|
||||
void kill();
|
||||
bool isRunning() const;
|
||||
SP<CPromise<std::string>> open();
|
||||
void kill();
|
||||
bool isRunning() const;
|
||||
|
||||
void onWrite(int fd, uint32_t mask);
|
||||
void onWrite(int fd, uint32_t mask);
|
||||
|
||||
private:
|
||||
CAsyncDialogBox(const std::string& title, const std::string& description, std::vector<std::string> buttons);
|
||||
|
||||
pid_t m_dialogPid = 0;
|
||||
wl_event_source* m_readEventSource = nullptr;
|
||||
std::function<void(std::string)> m_onResolution;
|
||||
Hyprutils::OS::CFileDescriptor m_pipeReadFd;
|
||||
std::string m_stdout = "";
|
||||
pid_t m_dialogPid = 0;
|
||||
wl_event_source* m_readEventSource = nullptr;
|
||||
Hyprutils::OS::CFileDescriptor m_pipeReadFd;
|
||||
std::string m_stdout = "";
|
||||
|
||||
const std::string m_title;
|
||||
const std::string m_description;
|
||||
const std::vector<std::string> m_buttons;
|
||||
const std::string m_title;
|
||||
const std::string m_description;
|
||||
const std::vector<std::string> m_buttons;
|
||||
|
||||
SP<CPromiseResolver<std::string>> m_promiseResolver;
|
||||
|
||||
// WARNING: cyclic reference. This will be removed once the event source is removed to avoid dangling pointers
|
||||
SP<CAsyncDialogBox> m_selfReference;
|
||||
|
|
|
|||
119
src/helpers/defer/Promise.hpp
Normal file
119
src/helpers/defer/Promise.hpp
Normal file
|
|
@ -0,0 +1,119 @@
|
|||
#pragma once
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include "../memory/Memory.hpp"
|
||||
|
||||
// TODO: move into hyprutils
|
||||
|
||||
template <typename T>
|
||||
class CPromise;
|
||||
template <typename T>
|
||||
class CPromiseResult;
|
||||
|
||||
template <typename T>
|
||||
class CPromiseResolver {
|
||||
public:
|
||||
CPromiseResolver(const CPromiseResolver&) = delete;
|
||||
CPromiseResolver(CPromiseResolver&&) = delete;
|
||||
CPromiseResolver& operator=(const CPromiseResolver&) = delete;
|
||||
CPromiseResolver& operator=(CPromiseResolver&&) = delete;
|
||||
|
||||
void resolve(T value) {
|
||||
if (m_promise->m_result)
|
||||
return;
|
||||
|
||||
m_promise->m_result = CPromiseResult<T>::result(value);
|
||||
|
||||
if (!m_promise->m_then)
|
||||
return;
|
||||
|
||||
m_promise->m_then(m_promise->m_result);
|
||||
}
|
||||
|
||||
void reject(const std::string& reason) {
|
||||
if (m_promise->m_result)
|
||||
return;
|
||||
|
||||
m_promise->m_result = CPromiseResult<T>::err(reason);
|
||||
|
||||
if (!m_promise->m_then)
|
||||
return;
|
||||
|
||||
m_promise->m_then(m_promise->m_result);
|
||||
}
|
||||
|
||||
private:
|
||||
CPromiseResolver(SP<CPromise<T>> promise) : m_promise(promise) {}
|
||||
|
||||
SP<CPromise<T>> m_promise;
|
||||
|
||||
friend class CPromise<T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class CPromiseResult {
|
||||
public:
|
||||
bool hasError() {
|
||||
return m_hasError;
|
||||
}
|
||||
|
||||
T result() {
|
||||
return m_result;
|
||||
}
|
||||
|
||||
std::string error() {
|
||||
return m_error;
|
||||
}
|
||||
|
||||
private:
|
||||
static SP<CPromiseResult<T>> result(T result) {
|
||||
auto p = SP<CPromiseResult<T>>(new CPromiseResult<T>());
|
||||
p->m_result = result;
|
||||
return p;
|
||||
}
|
||||
|
||||
static SP<CPromiseResult<T>> err(std::string reason) {
|
||||
auto p = SP<CPromiseResult<T>>(new CPromiseResult<T>());
|
||||
p->m_error = reason;
|
||||
p->m_hasError = true;
|
||||
return p;
|
||||
}
|
||||
|
||||
T m_result = {};
|
||||
std::string m_error = {};
|
||||
bool m_hasError = false;
|
||||
|
||||
friend class CPromiseResolver<T>;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class CPromise {
|
||||
public:
|
||||
CPromise(const CPromise&) = delete;
|
||||
CPromise(CPromise&&) = delete;
|
||||
CPromise& operator=(const CPromise&) = delete;
|
||||
CPromise& operator=(CPromise&&) = delete;
|
||||
|
||||
static SP<CPromise> make(const std::function<void(SP<CPromiseResolver<T>>)>& fn) {
|
||||
auto sp = SP<CPromise<T>>(new CPromise<T>());
|
||||
fn(SP<CPromiseResolver<T>>(new CPromiseResolver<T>(sp)));
|
||||
return sp;
|
||||
}
|
||||
|
||||
void then(std::function<void(SP<CPromiseResult<T>>)>&& fn) {
|
||||
m_then = std::move(fn);
|
||||
if (m_result)
|
||||
m_then(m_result);
|
||||
}
|
||||
|
||||
private:
|
||||
CPromise() = default;
|
||||
|
||||
const std::function<void(SP<CPromiseResult<T>>)> m_fn;
|
||||
std::function<void(SP<CPromiseResult<T>>)> m_then;
|
||||
SP<CPromiseResult<T>> m_result;
|
||||
|
||||
friend class CPromiseResult<T>;
|
||||
friend class CPromiseResolver<T>;
|
||||
};
|
||||
Loading…
Add table
Add a link
Reference in a new issue