Kylin/Universal/Private/PromiseHandler.h
2024-09-15 23:39:23 +08:00

209 lines
7.2 KiB
C++

#ifndef __PROMISEHANDLER_H__
#define __PROMISEHANDLER_H__
#include "../FunctionTraits.h"
#include "PromiseData.h"
#include <exception>
#include <type_traits>
template <typename T>
class Promise;
template <typename T>
struct PromiseDeduce {
using Type = Promise<T>;
};
template <typename T>
struct PromiseDeduce<T &> : public PromiseDeduce<T> {};
template <typename T>
struct PromiseDeduce<const T> : public PromiseDeduce<T> {};
template <typename T>
struct PromiseDeduce<const volatile T> : public PromiseDeduce<T> {};
template <typename T>
struct PromiseDeduce<Promise<T>> : public PromiseDeduce<T> {};
template <typename Functor, typename... Args>
struct PromiseFunctor {
using ResultType = typename std::invoke_result_t<Functor, Args...>;
using PromiseType = typename PromiseDeduce<ResultType>::Type;
};
template <typename T>
struct PromiseFulfill {
template <typename V, typename TResolve, typename TReject>
static void call(V &&value, const TResolve &resolve, const TReject &) {
resolve(std::forward<V>(value));
}
};
template <typename T>
struct PromiseFulfill<Promise<T>> {
template <typename TResolve, typename TReject>
static void call(const Promise<T> &promise, const TResolve &resolve, const TReject &reject) {
if (promise.isFulfilled()) {
resolve(promise.m_d->value());
} else if (promise.isRejected()) {
reject(promise.m_d->error());
} else {
promise.then([=]() { resolve(promise.m_d->value()); },
[=]() { // catch all
reject(promise.m_d->error());
});
}
}
};
template <>
struct PromiseFulfill<Promise<void>> {
template <typename TPromise, typename TResolve, typename TReject>
static void call(const TPromise &promise, const TResolve &resolve, const TReject &reject) {
if (promise.isFulfilled()) {
resolve();
} else if (promise.isRejected()) {
reject(promise.m_d->error());
} else {
promise.then([=]() { resolve(); },
[=]() { // catch all
reject(promise.m_d->error());
});
}
}
};
template <typename Result>
struct PromiseDispatch {
template <typename Resolve, typename Reject, typename Functor, typename... Args>
static void call(const Resolve &resolve, const Reject &reject, Functor fn, Args &&...args) {
try {
PromiseFulfill<std::decay_t<Result>>::call(fn(std::forward<Args>(args)...), resolve, reject);
} catch (...) {
reject(std::current_exception());
}
}
};
template <>
struct PromiseDispatch<void> {
template <typename Resolve, typename Reject, typename Functor, typename... Args>
static void call(const Resolve &resolve, const Reject &reject, Functor fn, Args &&...args) {
try {
fn(std::forward<Args>(args)...);
resolve();
} catch (...) {
reject(std::current_exception());
}
}
};
template <typename T, typename THandler, typename TArg = typename ArgsOf<THandler>::first>
struct PromiseHandler {
using ResType = std::invoke_result_t<THandler, T>;
using PromiseType = typename PromiseDeduce<ResType>::Type;
template <typename TResolve, typename TReject>
static std::function<void(const T &)> create(const THandler &handler, const TResolve &resolve, const TReject &reject) {
return [=](const T &value) { PromiseDispatch<ResType>::call(resolve, reject, handler, value); };
}
};
template <typename T, typename THandler>
struct PromiseHandler<T, THandler, void> {
using ResType = std::invoke_result_t<THandler>;
using PromiseType = typename PromiseDeduce<ResType>::Type;
template <typename TResolve, typename TReject>
static std::function<void(const T &)> create(const THandler &handler, const TResolve &resolve, const TReject &reject) {
return [=](const T &) { PromiseDispatch<ResType>::call(resolve, reject, handler); };
}
};
template <typename THandler>
struct PromiseHandler<void, THandler, void> {
using ResType = std::invoke_result_t<THandler>;
using PromiseType = typename PromiseDeduce<ResType>::Type;
template <typename TResolve, typename TReject>
static std::function<void()> create(const THandler &handler, const TResolve &resolve, const TReject &reject) {
return [=]() { PromiseDispatch<ResType>::call(resolve, reject, handler); };
}
};
template <typename T>
struct PromiseHandler<T, std::nullptr_t, void> {
using PromiseType = Promise<T>;
template <typename TResolve, typename TReject>
static std::function<void(const T &)> create(std::nullptr_t, const TResolve &resolve, const TReject &reject) {
return [=](const T &value) {
// 2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled,
// promise2 must be fulfilled with the same value as promise1.
PromiseFulfill<T>::call(std::move(T(value)), resolve, reject);
};
}
};
template <>
struct PromiseHandler<void, std::nullptr_t, void> {
using PromiseType = Promise<void>;
template <typename TResolve, typename TReject>
static std::function<void()> create(std::nullptr_t, const TResolve &resolve, const TReject &) {
return [=]() {
// 2.2.7.3. If onFulfilled is not a function and promise1 is fulfilled,
// promise2 must be fulfilled with the same value as promise1.
resolve();
};
}
};
template <typename T, typename THandler, typename TArg = typename ArgsOf<THandler>::first>
struct PromiseCatcher {
using ResType = std::invoke_result_t<THandler, TArg>;
template <typename TResolve, typename TReject>
static std::function<void(const PromiseError &)> create(const THandler &handler, const TResolve &resolve, const TReject &reject) {
return [=](const PromiseError &error) {
try {
error.rethrow();
} catch (const TArg &argError) {
PromiseDispatch<ResType>::call(resolve, reject, handler, argError);
} catch (...) {
reject(std::current_exception());
}
};
}
};
template <typename T, typename THandler>
struct PromiseCatcher<T, THandler, void> {
using ResType = typename std::invoke_result_t<THandler>;
template <typename TResolve, typename TReject>
static std::function<void(const PromiseError &)> create(const THandler &handler, const TResolve &resolve, const TReject &reject) {
return [=](const PromiseError &error) {
try {
error.rethrow();
} catch (...) {
PromiseDispatch<ResType>::call(resolve, reject, handler);
}
};
}
};
template <typename T>
struct PromiseCatcher<T, std::nullptr_t, void> {
template <typename TResolve, typename TReject>
static std::function<void(const PromiseError &)> create(std::nullptr_t, const TResolve &, const TReject &reject) {
return [=](const PromiseError &error) {
// 2.2.7.4. If onRejected is not a function and promise1 is rejected,
// promise2 must be rejected with the same reason as promise1
reject(error);
};
}
};
#endif // __PROMISEHANDLER_H__