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