You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
219 lines
6.4 KiB
219 lines
6.4 KiB
7 years ago
|
// Copyright (c) 2013-2014 Sandstorm Development Group, Inc. and contributors
|
||
|
// Licensed under the MIT License:
|
||
|
//
|
||
|
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||
|
// of this software and associated documentation files (the "Software"), to deal
|
||
|
// in the Software without restriction, including without limitation the rights
|
||
|
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||
|
// copies of the Software, and to permit persons to whom the Software is
|
||
|
// furnished to do so, subject to the following conditions:
|
||
|
//
|
||
|
// The above copyright notice and this permission notice shall be included in
|
||
|
// all copies or substantial portions of the Software.
|
||
|
//
|
||
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||
|
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||
|
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||
|
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||
|
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||
|
// THE SOFTWARE.
|
||
|
|
||
|
// This file contains a bunch of internal declarations that must appear before async.h can start.
|
||
|
// We don't define these directly in async.h because it makes the file hard to read.
|
||
|
|
||
|
#ifndef KJ_ASYNC_PRELUDE_H_
|
||
|
#define KJ_ASYNC_PRELUDE_H_
|
||
|
|
||
|
#if defined(__GNUC__) && !KJ_HEADER_WARNINGS
|
||
|
#pragma GCC system_header
|
||
|
#endif
|
||
|
|
||
|
#include "exception.h"
|
||
|
#include "tuple.h"
|
||
|
|
||
|
namespace kj {
|
||
|
|
||
|
class EventLoop;
|
||
|
template <typename T>
|
||
|
class Promise;
|
||
|
class WaitScope;
|
||
|
|
||
|
template <typename T>
|
||
|
Promise<Array<T>> joinPromises(Array<Promise<T>>&& promises);
|
||
|
Promise<void> joinPromises(Array<Promise<void>>&& promises);
|
||
|
|
||
|
namespace _ { // private
|
||
|
|
||
|
template <typename T> struct JoinPromises_ { typedef T Type; };
|
||
|
template <typename T> struct JoinPromises_<Promise<T>> { typedef T Type; };
|
||
|
|
||
|
template <typename T>
|
||
|
using JoinPromises = typename JoinPromises_<T>::Type;
|
||
|
// If T is Promise<U>, resolves to U, otherwise resolves to T.
|
||
|
//
|
||
|
// TODO(cleanup): Rename to avoid confusion with joinPromises() call which is completely
|
||
|
// unrelated.
|
||
|
|
||
|
class PropagateException {
|
||
|
// A functor which accepts a kj::Exception as a parameter and returns a broken promise of
|
||
|
// arbitrary type which simply propagates the exception.
|
||
|
public:
|
||
|
class Bottom {
|
||
|
public:
|
||
|
Bottom(Exception&& exception): exception(kj::mv(exception)) {}
|
||
|
|
||
|
Exception asException() { return kj::mv(exception); }
|
||
|
|
||
|
private:
|
||
|
Exception exception;
|
||
|
};
|
||
|
|
||
|
Bottom operator()(Exception&& e) {
|
||
|
return Bottom(kj::mv(e));
|
||
|
}
|
||
|
Bottom operator()(const Exception& e) {
|
||
|
return Bottom(kj::cp(e));
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <typename Func, typename T>
|
||
|
struct ReturnType_ { typedef decltype(instance<Func>()(instance<T>())) Type; };
|
||
|
template <typename Func>
|
||
|
struct ReturnType_<Func, void> { typedef decltype(instance<Func>()()) Type; };
|
||
|
|
||
|
template <typename Func, typename T>
|
||
|
using ReturnType = typename ReturnType_<Func, T>::Type;
|
||
|
// The return type of functor Func given a parameter of type T, with the special exception that if
|
||
|
// T is void, this is the return type of Func called with no arguments.
|
||
|
|
||
|
template <typename T> struct SplitTuplePromise_ { typedef Promise<T> Type; };
|
||
|
template <typename... T>
|
||
|
struct SplitTuplePromise_<kj::_::Tuple<T...>> {
|
||
|
typedef kj::Tuple<Promise<JoinPromises<T>>...> Type;
|
||
|
};
|
||
|
|
||
|
template <typename T>
|
||
|
using SplitTuplePromise = typename SplitTuplePromise_<T>::Type;
|
||
|
// T -> Promise<T>
|
||
|
// Tuple<T> -> Tuple<Promise<T>>
|
||
|
|
||
|
struct Void {};
|
||
|
// Application code should NOT refer to this! See `kj::READY_NOW` instead.
|
||
|
|
||
|
template <typename T> struct FixVoid_ { typedef T Type; };
|
||
|
template <> struct FixVoid_<void> { typedef Void Type; };
|
||
|
template <typename T> using FixVoid = typename FixVoid_<T>::Type;
|
||
|
// FixVoid<T> is just T unless T is void in which case it is _::Void (an empty struct).
|
||
|
|
||
|
template <typename T> struct UnfixVoid_ { typedef T Type; };
|
||
|
template <> struct UnfixVoid_<Void> { typedef void Type; };
|
||
|
template <typename T> using UnfixVoid = typename UnfixVoid_<T>::Type;
|
||
|
// UnfixVoid is the opposite of FixVoid.
|
||
|
|
||
|
template <typename In, typename Out>
|
||
|
struct MaybeVoidCaller {
|
||
|
// Calls the function converting a Void input to an empty parameter list and a void return
|
||
|
// value to a Void output.
|
||
|
|
||
|
template <typename Func>
|
||
|
static inline Out apply(Func& func, In&& in) {
|
||
|
return func(kj::mv(in));
|
||
|
}
|
||
|
};
|
||
|
template <typename In, typename Out>
|
||
|
struct MaybeVoidCaller<In&, Out> {
|
||
|
template <typename Func>
|
||
|
static inline Out apply(Func& func, In& in) {
|
||
|
return func(in);
|
||
|
}
|
||
|
};
|
||
|
template <typename Out>
|
||
|
struct MaybeVoidCaller<Void, Out> {
|
||
|
template <typename Func>
|
||
|
static inline Out apply(Func& func, Void&& in) {
|
||
|
return func();
|
||
|
}
|
||
|
};
|
||
|
template <typename In>
|
||
|
struct MaybeVoidCaller<In, Void> {
|
||
|
template <typename Func>
|
||
|
static inline Void apply(Func& func, In&& in) {
|
||
|
func(kj::mv(in));
|
||
|
return Void();
|
||
|
}
|
||
|
};
|
||
|
template <typename In>
|
||
|
struct MaybeVoidCaller<In&, Void> {
|
||
|
template <typename Func>
|
||
|
static inline Void apply(Func& func, In& in) {
|
||
|
func(in);
|
||
|
return Void();
|
||
|
}
|
||
|
};
|
||
|
template <>
|
||
|
struct MaybeVoidCaller<Void, Void> {
|
||
|
template <typename Func>
|
||
|
static inline Void apply(Func& func, Void&& in) {
|
||
|
func();
|
||
|
return Void();
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <typename T>
|
||
|
inline T&& returnMaybeVoid(T&& t) {
|
||
|
return kj::fwd<T>(t);
|
||
|
}
|
||
|
inline void returnMaybeVoid(Void&& v) {}
|
||
|
|
||
|
class ExceptionOrValue;
|
||
|
class PromiseNode;
|
||
|
class ChainPromiseNode;
|
||
|
template <typename T>
|
||
|
class ForkHub;
|
||
|
|
||
|
class TaskSetImpl;
|
||
|
|
||
|
class Event;
|
||
|
|
||
|
class PromiseBase {
|
||
|
public:
|
||
|
kj::String trace();
|
||
|
// Dump debug info about this promise.
|
||
|
|
||
|
private:
|
||
|
Own<PromiseNode> node;
|
||
|
|
||
|
PromiseBase() = default;
|
||
|
PromiseBase(Own<PromiseNode>&& node): node(kj::mv(node)) {}
|
||
|
|
||
|
friend class kj::EventLoop;
|
||
|
friend class ChainPromiseNode;
|
||
|
template <typename>
|
||
|
friend class kj::Promise;
|
||
|
friend class TaskSetImpl;
|
||
|
template <typename U>
|
||
|
friend Promise<Array<U>> kj::joinPromises(Array<Promise<U>>&& promises);
|
||
|
friend Promise<void> kj::joinPromises(Array<Promise<void>>&& promises);
|
||
|
};
|
||
|
|
||
|
void detach(kj::Promise<void>&& promise);
|
||
|
void waitImpl(Own<_::PromiseNode>&& node, _::ExceptionOrValue& result, WaitScope& waitScope);
|
||
|
Promise<void> yield();
|
||
|
Own<PromiseNode> neverDone();
|
||
|
|
||
|
class NeverDone {
|
||
|
public:
|
||
|
template <typename T>
|
||
|
operator Promise<T>() const {
|
||
|
return Promise<T>(false, neverDone());
|
||
|
}
|
||
|
|
||
|
KJ_NORETURN(void wait(WaitScope& waitScope) const);
|
||
|
};
|
||
|
|
||
|
} // namespace _ (private)
|
||
|
} // namespace kj
|
||
|
|
||
|
#endif // KJ_ASYNC_PRELUDE_H_
|