almost finished reworking promises, they compile now but sometimes dont work

This commit is contained in:
HJfod 2024-03-13 22:50:36 +02:00
parent 8101ae50ab
commit bc98c9b84e
6 changed files with 109 additions and 114 deletions

View file

@ -11,7 +11,7 @@ namespace geode {
std::optional<uint8_t> percentage; std::optional<uint8_t> percentage;
DefaultProgress() = default; DefaultProgress() = default;
DefaultProgress(auto msg) : message(msg) {} DefaultProgress(std::string const& msg) : message(msg) {}
DefaultProgress(auto msg, uint8_t percentage) : message(msg), percentage(percentage) {} DefaultProgress(auto msg, uint8_t percentage) : message(msg), percentage(percentage) {}
}; };
} }
@ -24,8 +24,8 @@ namespace geode {
template <class T = impl::DefaultValue, class E = impl::DefaultError, class P = impl::DefaultProgress> template <class T = impl::DefaultValue, class E = impl::DefaultError, class P = impl::DefaultProgress>
class Promise final { class Promise final {
public: public:
using Value = T; using Value = T;
using Error = E; using Error = E;
using Progress = P; using Progress = P;
using OnResolved = utils::MiniFunction<void(Value)>; using OnResolved = utils::MiniFunction<void(Value)>;
@ -46,12 +46,12 @@ namespace geode {
Promise() : m_data(std::make_shared<Data>()) {} Promise() : m_data(std::make_shared<Data>()) {}
Promise(utils::MiniFunction<void(OnResolved, OnRejected)> source, bool threaded = true) Promise(utils::MiniFunction<void(OnResolved, OnRejected)> source, bool threaded = true)
: Promise([source](auto resolve, auto reject, auto, auto) { : Promise([source](auto resolve, auto reject, auto, auto const&) {
source(resolve, reject); source(resolve, reject);
}) {} }, threaded) {}
Promise(utils::MiniFunction<void(OnResolved, OnRejected, OnProgress, OnCancelled)> source, bool threaded = true) Promise(utils::MiniFunction<void(OnResolved, OnRejected, OnProgress, std::atomic_bool const&)> source, bool threaded = true)
: Promise([source](auto onStateChanged) { : Promise([source](auto onStateChanged, auto const& cancelled) {
source( source(
[onStateChanged](auto&& value) { [onStateChanged](auto&& value) {
onStateChanged(State(std::in_place_index<STATE_VALUE_INDEX>, value)); onStateChanged(State(std::in_place_index<STATE_VALUE_INDEX>, value));
@ -62,13 +62,12 @@ namespace geode {
[onStateChanged](auto&& progress) { [onStateChanged](auto&& progress) {
onStateChanged(State(std::in_place_index<STATE_PROGRESS_INDEX>, progress)); onStateChanged(State(std::in_place_index<STATE_PROGRESS_INDEX>, progress));
}, },
[onStateChanged]() { cancelled
onStateChanged(State(std::in_place_index<STATE_CANCELLED_INDEX>, CancelledState()));
}
); );
}) {} }, threaded, std::monostate()) {}
Promise(utils::MiniFunction<void(OnStateChange)> source, bool threaded = true) : m_data(std::make_shared<Data>()) { Promise(utils::MiniFunction<void(OnStateChange, std::atomic_bool const&)> source, bool threaded, std::monostate tag) : m_data(std::make_shared<Data>()) {
m_data->shouldStartThreaded = threaded;
if (threaded) { if (threaded) {
std::thread([source = std::move(source), data = m_data]() mutable { std::thread([source = std::move(source), data = m_data]() mutable {
Promise::invoke_source(std::move(source), data); Promise::invoke_source(std::move(source), data);
@ -88,7 +87,10 @@ namespace geode {
template <class T2> template <class T2>
requires (!std::is_void_v<T2>) requires (!std::is_void_v<T2>)
Promise<T2, E, P> then(utils::MiniFunction<T2(T)>&& callback) { Promise<T2, E, P> then(utils::MiniFunction<T2(T)>&& callback) {
if (m_data->cancelled) return make_cancelled<T2, E, P>(); if (m_data->cancelled) {
return make_cancelled<T2, E, P>();
}
std::unique_lock<std::mutex> _(m_data->mutex); std::unique_lock<std::mutex> _(m_data->mutex);
// Check if this Promise has already been resolved, and if so // Check if this Promise has already been resolved, and if so
@ -103,47 +105,16 @@ namespace geode {
return make_cancelled<T2, E, P>(); return make_cancelled<T2, E, P>();
} }
return Promise<T2, E, P>([data = m_data, callback](auto fwdStateToNextPromise) { return make_fwd<STATE_VALUE_INDEX, T2, E, P>(callback, m_data);
data->callback = [fwdStateToNextPromise, callback](auto&& state) {
// Can't use std::visit if Value and Error are the same >:(
switch (state.index()) {
case STATE_VALUE_INDEX: {
auto mapped = callback(std::get<STATE_VALUE_INDEX>(state));
fwdStateToNextPromise(Promise<T2, E, P>::State(
std::in_place_index<STATE_VALUE_INDEX>,
std::move(mapped)
));
} break;
case STATE_ERROR_INDEX: {
fwdStateToNextPromise(Promise<T2, E, P>::State(
std::in_place_index<STATE_ERROR_INDEX>,
std::move(std::get<STATE_ERROR_INDEX>(state))
));
} break;
case STATE_PROGRESS_INDEX: {
fwdStateToNextPromise(Promise<T2, E, P>::State(
std::in_place_index<STATE_PROGRESS_INDEX>,
std::move(std::get<STATE_PROGRESS_INDEX>(state))
));
} break;
case STATE_CANCELLED_INDEX: {
fwdStateToNextPromise(Promise<T2, E, P>::State(
std::in_place_index<STATE_CANCELLED_INDEX>,
std::move(std::get<STATE_CANCELLED_INDEX>(state))
));
} break;
}
};
});
} }
template <class T2, class E2> template <class T2, class E2>
requires (!std::is_void_v<T2>) requires (!std::is_void_v<T2>)
Promise<T2, E2, P> then(utils::MiniFunction<Result<T2, E2>(Result<T, E>)>&& callback) { Promise<T2, E2, P> then(utils::MiniFunction<Result<T2, E2>(Result<T, E>)>&& callback) {
if (m_data->cancelled) return make_cancelled<T2, E2, P>(); if (m_data->cancelled) {
return make_cancelled<T2, E2, P>();
}
std::unique_lock<std::mutex> _(m_data->mutex); std::unique_lock<std::mutex> _(m_data->mutex);
// Check if this Promise has already been resolved, and if so // Check if this Promise has already been resolved, and if so
@ -163,8 +134,8 @@ namespace geode {
return make_cancelled<T2, E2, P>(); return make_cancelled<T2, E2, P>();
} }
return Promise<T2, E2, P>([data = m_data, callback](auto fwdStateToNextPromise) { return Promise<T2, E2, P>([data = m_data, callback](auto fwdStateToNextPromise, auto const& nextPromiseCancelled) {
data->callback = [fwdStateToNextPromise, callback](auto&& state) { data->callback = [&nextPromiseCancelled, fwdStateToNextPromise, callback](auto&& state) {
// Can't use std::visit if Value and Error are the same >:( // Can't use std::visit if Value and Error are the same >:(
switch (state.index()) { switch (state.index()) {
case STATE_VALUE_INDEX: { case STATE_VALUE_INDEX: {
@ -214,7 +185,7 @@ namespace geode {
} break; } break;
} }
}; };
}); }, m_data->shouldStartThreaded, std::monostate());
} }
Promise expect(utils::MiniFunction<void(Error)>&& callback) { Promise expect(utils::MiniFunction<void(Error)>&& callback) {
@ -226,7 +197,10 @@ namespace geode {
template <class E2> template <class E2>
requires (!std::is_void_v<E2>) requires (!std::is_void_v<E2>)
Promise<T, E2, P> expect(utils::MiniFunction<E2(E)>&& callback) { Promise<T, E2, P> expect(utils::MiniFunction<E2(E)>&& callback) {
if (m_data->cancelled) return make_cancelled<T, E2, P>(); if (m_data->cancelled) {
return make_cancelled<T, E2, P>();
}
std::unique_lock<std::mutex> _(m_data->mutex); std::unique_lock<std::mutex> _(m_data->mutex);
// Check if this Promise has already been resolved, and if so // Check if this Promise has already been resolved, and if so
@ -241,41 +215,7 @@ namespace geode {
return make_cancelled<T, E2, P>(); return make_cancelled<T, E2, P>();
} }
return Promise<T, E2, P>([data = m_data, callback](auto fwdStateToNextPromise) { return make_fwd<STATE_ERROR_INDEX, T, E2, P>(callback, m_data);
data->callback = [fwdStateToNextPromise, callback](auto&& state) {
// Can't use std::visit if Value and Error are the same >:(
switch (state.index()) {
case STATE_VALUE_INDEX: {
fwdStateToNextPromise(Promise<T, E2, P>::State(
std::in_place_index<STATE_VALUE_INDEX>,
std::move(std::get<STATE_VALUE_INDEX>(state))
));
} break;
case STATE_ERROR_INDEX: {
auto mapped = callback(std::get<STATE_ERROR_INDEX>(state));
fwdStateToNextPromise(Promise<T, E2, P>::State(
std::in_place_index<STATE_ERROR_INDEX>,
std::move(mapped)
));
} break;
case STATE_PROGRESS_INDEX: {
fwdStateToNextPromise(Promise<T, E2, P>::State(
std::in_place_index<STATE_PROGRESS_INDEX>,
std::move(std::get<STATE_PROGRESS_INDEX>(state))
));
} break;
case STATE_CANCELLED_INDEX: {
fwdStateToNextPromise(Promise<T, E2, P>::State(
std::in_place_index<STATE_CANCELLED_INDEX>,
std::move(std::get<STATE_CANCELLED_INDEX>(state))
));
} break;
}
};
});
} }
Promise progress(utils::MiniFunction<void(Progress)>&& callback) { Promise progress(utils::MiniFunction<void(Progress)>&& callback) {
@ -287,7 +227,10 @@ namespace geode {
template <class P2> template <class P2>
requires (!std::is_void_v<P2>) requires (!std::is_void_v<P2>)
Promise<T, E, P2> progress(utils::MiniFunction<P2(P)>&& callback) { Promise<T, E, P2> progress(utils::MiniFunction<P2(P)>&& callback) {
if (m_data->cancelled) return make_cancelled<T, E, P2>(); if (m_data->cancelled) {
return make_cancelled<T, E, P2>();
}
std::unique_lock<std::mutex> _(m_data->mutex); std::unique_lock<std::mutex> _(m_data->mutex);
// Check if this Promise has already been resolved // Check if this Promise has already been resolved
@ -295,21 +238,14 @@ namespace geode {
return make_cancelled<T, E, P2>(); return make_cancelled<T, E, P2>();
} }
return Promise<T, E, P2>([data = m_data, callback](auto fwdStateToNextPromise) { return make_fwd<STATE_PROGRESS_INDEX, T, E, P2>(callback, m_data);
data->callback = [fwdStateToNextPromise, callback](auto&& state) {
if (state.index() == STATE_PROGRESS_INDEX) {
auto mapped = callback(std::get<STATE_PROGRESS_INDEX>(state));
fwdStateToNextPromise(Promise<T, E, P2>::State(std::in_place_index<STATE_PROGRESS_INDEX>, mapped));
}
else {
fwdStateToNextPromise(state);
}
};
});
} }
Promise finally(utils::MiniFunction<void()>&& callback) { Promise finally(utils::MiniFunction<void()>&& callback) {
if (m_data->cancelled) return make_cancelled(); if (m_data->cancelled) {
return make_cancelled();
}
std::unique_lock<std::mutex> _(m_data->mutex); std::unique_lock<std::mutex> _(m_data->mutex);
// Check if this Promise has already been resolved, and if so // Check if this Promise has already been resolved, and if so
@ -380,6 +316,7 @@ namespace geode {
OnStateChange callback; OnStateChange callback;
std::optional<std::variant<Value, Error>> result; std::optional<std::variant<Value, Error>> result;
std::atomic_bool cancelled; std::atomic_bool cancelled;
bool shouldStartThreaded;
}; };
std::shared_ptr<Data> m_data; std::shared_ptr<Data> m_data;
@ -390,12 +327,59 @@ namespace geode {
return std::move(ret); return std::move(ret);
} }
template <size_t Ix, class T2, class E2, class P2>
static Promise<T2, E2, P2> make_fwd(auto mapper, std::shared_ptr<Data> data) {
return Promise<T2, E2, P2>([data, mapper](auto fwdStateToNextPromise, auto const&) {
data->callback = [fwdStateToNextPromise, mapper](auto&& state) {
if (state.index() == Ix) {
auto mapped = mapper(std::get<Ix>(state));
fwdStateToNextPromise(Promise<T2, E2, P2>::State(
std::in_place_index<Ix>,
mapped
));
}
// Can't use std::visit if Value and Error are the same >:(
else switch (state.index()) {
case STATE_VALUE_INDEX: if constexpr (Ix != STATE_VALUE_INDEX) {
fwdStateToNextPromise(Promise<T2, E2, P2>::State(
std::in_place_index<STATE_VALUE_INDEX>,
std::move(std::get<STATE_VALUE_INDEX>(state))
));
} break;
case STATE_ERROR_INDEX: if constexpr (Ix != STATE_ERROR_INDEX) {
fwdStateToNextPromise(Promise<T2, E2, P2>::State(
std::in_place_index<STATE_ERROR_INDEX>,
std::move(std::get<STATE_ERROR_INDEX>(state))
));
} break;
case STATE_PROGRESS_INDEX: if constexpr (Ix != STATE_PROGRESS_INDEX) {
fwdStateToNextPromise(Promise<T2, E2, P2>::State(
std::in_place_index<STATE_PROGRESS_INDEX>,
std::move(std::get<STATE_PROGRESS_INDEX>(state))
));
} break;
case STATE_CANCELLED_INDEX: if constexpr (Ix != STATE_CANCELLED_INDEX) {
fwdStateToNextPromise(Promise<T2, E2, P2>::State(
std::in_place_index<STATE_CANCELLED_INDEX>,
std::move(std::get<STATE_CANCELLED_INDEX>(state))
));
} break;
}
};
}, data->shouldStartThreaded, std::monostate());
}
static void invoke_callback(State&& state, std::shared_ptr<Data> data) { static void invoke_callback(State&& state, std::shared_ptr<Data> data) {
if (data->cancelled) return; if (data->cancelled) return;
std::unique_lock<std::mutex> _(data->mutex); std::unique_lock<std::mutex> _(data->mutex);
if (data->callback) { if (data->callback) {
data->callback(State(state)); Loader::get()->queueInMainThread([callback = data->callback, state = State(state)]() {
callback(state);
});
} }
// Store the state to let future installed callbacks be immediately resolved // Store the state to let future installed callbacks be immediately resolved
@ -410,10 +394,13 @@ namespace geode {
} }
} }
static void invoke_source(utils::MiniFunction<void(OnStateChange)>&& source, std::shared_ptr<Data> data) { static void invoke_source(utils::MiniFunction<void(OnStateChange, std::atomic_bool const&)>&& source, std::shared_ptr<Data> data) {
source([data](auto&& state) { source(
invoke_callback(std::move(state), data); [data](auto&& state) {
}); invoke_callback(std::move(state), data);
},
data->cancelled
);
} }
}; };
@ -472,11 +459,12 @@ namespace geode {
// the same IDs again, so technically if some promise takes // the same IDs again, so technically if some promise takes
// literally forever then this could cause issues later on // literally forever then this could cause issues later on
static size_t ID_COUNTER = 0; static size_t ID_COUNTER = 0;
ID_COUNTER += 1;
// Reserve 0 for PromiseEventFilter not listening to anything // Reserve 0 for PromiseEventFilter not listening to anything
if (ID_COUNTER == 0) { if (ID_COUNTER == 0) {
ID_COUNTER += 1; ID_COUNTER += 1;
} }
size_t id = ++ID_COUNTER; size_t id = ID_COUNTER;
this this
->then([id](auto&& value) { ->then([id](auto&& value) {
PromiseEvent<T, E, P>(id, std::variant<T, E, P> { std::in_place_index<0>, std::forward<T>(value) }).post(); PromiseEvent<T, E, P>(id, std::variant<T, E, P> { std::in_place_index<0>, std::forward<T>(value) }).post();

View file

@ -150,7 +150,7 @@ namespace server {
template <class As> template <class As>
As* find(Query const& query) { As* find(Query const& query) {
auto it = std::find_if(m_values.begin(), m_values.end(), [](auto const& q) { auto it = std::find_if(m_values.begin(), m_values.end(), [query](auto const& q) {
return q.first == query; return q.first == query;
}); });
if (it == m_values.end()) { if (it == m_values.end()) {
@ -226,7 +226,11 @@ namespace server {
Cache m_cache; Cache m_cache;
ServerPromise<Result> fetch(Query const& query) { ServerPromise<Result> fetch(Query const& query) {
return m_cache.pend(Query(query)); return F(Query(query))
.then([this, query = std::move(query)](auto res) {
m_cache.add(Query(query), Result(res));
});
// return m_cache.pend(Query(query));
} }
public: public:

View file

@ -93,7 +93,8 @@ protected:
this->setSprite(CCSprite::create("loadingCircle.png")); this->setSprite(CCSprite::create("loadingCircle.png"));
static_cast<CCSprite*>(m_sprite)->setBlendFunc({ GL_ONE, GL_ONE }); static_cast<CCSprite*>(m_sprite)->setBlendFunc({ GL_ONE, GL_ONE });
m_sprite->runAction(CCRepeatForever::create(CCRotateBy::create(1.f, 360.f))); m_sprite->runAction(CCRepeatForever::create(CCRotateBy::create(1.f, 360.f)));
m_listener.setFilter(server::ServerResultCache<&server::getModLogo>::shared().get(id).listen()); m_listener.setFilter(server::getModLogo(id).listen());
// m_listener.setFilter(server::ServerResultCache<&server::getModLogo>::shared().get(id).listen());
} }
return true; return true;

View file

@ -110,7 +110,7 @@ typename ModListSource::PagePromise ModListSource::loadPage(size_t page, bool up
// Return a generic "Coming soon" message if there's no provider set // Return a generic "Coming soon" message if there's no provider set
if (!m_provider.get) { if (!m_provider.get) {
return PagePromise([this, page](auto, auto reject) { return PagePromise([this, page](auto, auto reject) {
reject("Coming soon! ;)"); reject(LoadPageError("Coming soon! ;)"));
}); });
} }
if (!update && m_cachedPages.contains(page)) { if (!update && m_cachedPages.contains(page)) {

View file

@ -24,7 +24,7 @@ public:
std::optional<std::string> details; std::optional<std::string> details;
LoadPageError() = default; LoadPageError() = default;
LoadPageError(auto msg) : message(msg) {} LoadPageError(std::string const& msg) : message(msg) {}
LoadPageError(auto msg, auto details) : message(msg), details(details) {} LoadPageError(auto msg, auto details) : message(msg), details(details) {}
}; };

View file

@ -115,7 +115,7 @@ std::string urlParamEncode(std::string_view const input) {
WebPromise WebRequest::send(std::string_view method, std::string_view url) { WebPromise WebRequest::send(std::string_view method, std::string_view url) {
m_impl->m_method = method; m_impl->m_method = method;
m_impl->m_url = url; m_impl->m_url = url;
return WebPromise([impl = m_impl](auto resolve, auto reject, auto progress, auto cancelled) { return WebPromise([impl = m_impl](auto resolve, auto reject, auto progress, auto const& cancelled) {
// Init Curl // Init Curl
auto curl = curl_easy_init(); auto curl = curl_easy_init();
if (!curl) { if (!curl) {
@ -130,11 +130,13 @@ WebPromise WebRequest::send(std::string_view method, std::string_view url) {
struct ResponseData { struct ResponseData {
WebResponse response; WebResponse response;
Impl* impl; Impl* impl;
WebPromise::Progress progress; WebPromise::OnProgress progress;
std::atomic_bool const& cancelled;
} responseData = { } responseData = {
.response = WebResponse(), .response = WebResponse(),
.impl = impl.get(), .impl = impl.get(),
.progress = progress, .progress = progress,
.cancelled = cancelled,
}; };
// Store downloaded response data into a byte vector // Store downloaded response data into a byte vector