#pragma once
#include "ExceptionOr.h"
#include "JSDOMGlobalObject.h"
#include "JSDOMPromiseDeferred.h"
#include <wtf/Function.h>
#include <wtf/Optional.h>
#include <wtf/Vector.h>
namespace WebCore {
template<typename IDLType>
class DOMPromiseProxy {
WTF_MAKE_FAST_ALLOCATED;
public:
using Value = typename IDLType::StorageType;
DOMPromiseProxy() = default;
~DOMPromiseProxy() = default;
JSC::JSValue promise(JSC::JSGlobalObject&, JSDOMGlobalObject&);
void clear();
bool isFulfilled() const;
void resolve(typename IDLType::ParameterType);
void resolveWithNewlyCreated(typename IDLType::ParameterType);
void reject(Exception);
private:
Optional<ExceptionOr<Value>> m_valueOrException;
Vector<Ref<DeferredPromise>, 1> m_deferredPromises;
};
template<>
class DOMPromiseProxy<IDLVoid> {
WTF_MAKE_FAST_ALLOCATED;
public:
DOMPromiseProxy() = default;
~DOMPromiseProxy() = default;
JSC::JSValue promise(JSC::JSGlobalObject&, JSDOMGlobalObject&);
void clear();
bool isFulfilled() const;
void resolve();
void reject(Exception);
private:
Optional<ExceptionOr<void>> m_valueOrException;
Vector<Ref<DeferredPromise>, 1> m_deferredPromises;
};
template<typename IDLType>
class DOMPromiseProxyWithResolveCallback {
WTF_MAKE_FAST_ALLOCATED;
public:
using ResolveCallback = WTF::Function<typename IDLType::ParameterType ()>;
template <typename Class, typename BaseClass>
DOMPromiseProxyWithResolveCallback(Class&, typename IDLType::ParameterType (BaseClass::*)());
DOMPromiseProxyWithResolveCallback(ResolveCallback&&);
~DOMPromiseProxyWithResolveCallback() = default;
JSC::JSValue promise(JSC::JSGlobalObject&, JSDOMGlobalObject&);
void clear();
bool isFulfilled() const;
void resolve(typename IDLType::ParameterType);
void resolveWithNewlyCreated(typename IDLType::ParameterType);
void reject(Exception);
private:
ResolveCallback m_resolveCallback;
Optional<ExceptionOr<void>> m_valueOrException;
Vector<Ref<DeferredPromise>, 1> m_deferredPromises;
};
template<typename IDLType>
inline JSC::JSValue DOMPromiseProxy<IDLType>::promise(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject)
{
UNUSED_PARAM(lexicalGlobalObject);
for (auto& deferredPromise : m_deferredPromises) {
if (deferredPromise->globalObject() == &globalObject)
return deferredPromise->promise();
}
auto deferredPromise = DeferredPromise::create(globalObject, DeferredPromise::Mode::RetainPromiseOnResolve);
if (!deferredPromise)
return JSC::jsUndefined();
if (m_valueOrException) {
if (m_valueOrException->hasException())
deferredPromise->reject(m_valueOrException->exception());
else
deferredPromise->template resolve<IDLType>(m_valueOrException->returnValue());
}
auto result = deferredPromise->promise();
m_deferredPromises.append(deferredPromise.releaseNonNull());
return result;
}
template<typename IDLType>
inline void DOMPromiseProxy<IDLType>::clear()
{
m_valueOrException = WTF::nullopt;
m_deferredPromises.clear();
}
template<typename IDLType>
inline bool DOMPromiseProxy<IDLType>::isFulfilled() const
{
return m_valueOrException.hasValue();
}
template<typename IDLType>
inline void DOMPromiseProxy<IDLType>::resolve(typename IDLType::ParameterType value)
{
ASSERT(!m_valueOrException);
m_valueOrException = ExceptionOr<Value> { std::forward<typename IDLType::ParameterType>(value) };
for (auto& deferredPromise : m_deferredPromises)
deferredPromise->template resolve<IDLType>(m_valueOrException->returnValue());
}
template<typename IDLType>
inline void DOMPromiseProxy<IDLType>::resolveWithNewlyCreated(typename IDLType::ParameterType value)
{
ASSERT(!m_valueOrException);
m_valueOrException = ExceptionOr<Value> { std::forward<typename IDLType::ParameterType>(value) };
for (auto& deferredPromise : m_deferredPromises)
deferredPromise->template resolveWithNewlyCreated<IDLType>(m_valueOrException->returnValue());
}
template<typename IDLType>
inline void DOMPromiseProxy<IDLType>::reject(Exception exception)
{
ASSERT(!m_valueOrException);
m_valueOrException = ExceptionOr<Value> { WTFMove(exception) };
for (auto& deferredPromise : m_deferredPromises)
deferredPromise->reject(m_valueOrException->exception());
}
inline JSC::JSValue DOMPromiseProxy<IDLVoid>::promise(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject)
{
UNUSED_PARAM(lexicalGlobalObject);
for (auto& deferredPromise : m_deferredPromises) {
if (deferredPromise->globalObject() == &globalObject)
return deferredPromise->promise();
}
auto deferredPromise = DeferredPromise::create(globalObject, DeferredPromise::Mode::RetainPromiseOnResolve);
if (!deferredPromise)
return JSC::jsUndefined();
if (m_valueOrException) {
if (m_valueOrException->hasException())
deferredPromise->reject(m_valueOrException->exception());
else
deferredPromise->resolve();
}
auto result = deferredPromise->promise();
m_deferredPromises.append(deferredPromise.releaseNonNull());
return result;
}
inline void DOMPromiseProxy<IDLVoid>::clear()
{
m_valueOrException = WTF::nullopt;
m_deferredPromises.clear();
}
inline bool DOMPromiseProxy<IDLVoid>::isFulfilled() const
{
return m_valueOrException.hasValue();
}
inline void DOMPromiseProxy<IDLVoid>::resolve()
{
ASSERT(!m_valueOrException);
m_valueOrException = ExceptionOr<void> { };
for (auto& deferredPromise : m_deferredPromises)
deferredPromise->resolve();
}
inline void DOMPromiseProxy<IDLVoid>::reject(Exception exception)
{
ASSERT(!m_valueOrException);
m_valueOrException = ExceptionOr<void> { WTFMove(exception) };
for (auto& deferredPromise : m_deferredPromises)
deferredPromise->reject(m_valueOrException->exception());
}
template<typename IDLType>
template <typename Class, typename BaseClass>
inline DOMPromiseProxyWithResolveCallback<IDLType>::DOMPromiseProxyWithResolveCallback(Class& object, typename IDLType::ParameterType (BaseClass::*function)())
: m_resolveCallback(std::bind(function, &object))
{
}
template<typename IDLType>
inline DOMPromiseProxyWithResolveCallback<IDLType>::DOMPromiseProxyWithResolveCallback(ResolveCallback&& function)
: m_resolveCallback(WTFMove(function))
{
}
template<typename IDLType>
inline JSC::JSValue DOMPromiseProxyWithResolveCallback<IDLType>::promise(JSC::JSGlobalObject& lexicalGlobalObject, JSDOMGlobalObject& globalObject)
{
UNUSED_PARAM(lexicalGlobalObject);
for (auto& deferredPromise : m_deferredPromises) {
if (deferredPromise->globalObject() == &globalObject)
return deferredPromise->promise();
}
auto deferredPromise = DeferredPromise::create(globalObject, DeferredPromise::Mode::RetainPromiseOnResolve);
if (!deferredPromise)
return JSC::jsUndefined();
if (m_valueOrException) {
if (m_valueOrException->hasException())
deferredPromise->reject(m_valueOrException->exception());
else
deferredPromise->template resolve<IDLType>(m_resolveCallback());
}
auto result = deferredPromise->promise();
m_deferredPromises.append(deferredPromise.releaseNonNull());
return result;
}
template<typename IDLType>
inline void DOMPromiseProxyWithResolveCallback<IDLType>::clear()
{
m_valueOrException = WTF::nullopt;
m_deferredPromises.clear();
}
template<typename IDLType>
inline bool DOMPromiseProxyWithResolveCallback<IDLType>::isFulfilled() const
{
return m_valueOrException.hasValue();
}
template<typename IDLType>
inline void DOMPromiseProxyWithResolveCallback<IDLType>::resolve(typename IDLType::ParameterType value)
{
ASSERT(!m_valueOrException);
m_valueOrException = ExceptionOr<void> { };
for (auto& deferredPromise : m_deferredPromises)
deferredPromise->template resolve<IDLType>(value);
}
template<typename IDLType>
inline void DOMPromiseProxyWithResolveCallback<IDLType>::resolveWithNewlyCreated(typename IDLType::ParameterType value)
{
ASSERT(!m_valueOrException);
m_valueOrException = ExceptionOr<void> { };
for (auto& deferredPromise : m_deferredPromises)
deferredPromise->template resolveWithNewlyCreated<IDLType>(value);
}
template<typename IDLType>
inline void DOMPromiseProxyWithResolveCallback<IDLType>::reject(Exception exception)
{
ASSERT(!m_valueOrException);
m_valueOrException = ExceptionOr<void> { WTFMove(exception) };
for (auto& deferredPromise : m_deferredPromises)
deferredPromise->reject(m_valueOrException->exception());
}
}