//
// await
// ~~~~~
// Stackless coroutines / resumable functions.
//
// Copyright (c) 2014 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//

#ifndef EXECUTORS_EXPERIMENTAL_AWAIT_HEADER
#define EXECUTORS_EXPERIMENTAL_AWAIT_HEADER

#include <memory>
#include <system_error>
#include <experimental/executor>
#include <experimental/type_traits>

namespace std {
namespace experimental {
inline namespace concurrency_v1 {

class __await_context_impl_base;
class __coroutine;

// Context object used to represent the currently executing coroutine.

template <class _Executor>
class basic_await_context
{
public:
  typedef _Executor executor_type;

  // construct / copy / destroy:

  template <class _OtherExecutor>
    basic_await_context(const basic_await_context<_OtherExecutor>&);

  // basic_await_context operations:

  executor_type get_executor() const noexcept;
  basic_await_context operator[](error_code& __ec) const;

private:
  template <class> friend class basic_await_context;
  template <class, class, class, class...> friend class __await_context_impl;
  template <class, class...> friend struct __await_context_handler;

  basic_await_context(const executor_work<_Executor>& __w,
    shared_ptr<__await_context_impl_base> __i)
      : _M_executor(__w.get_executor()), _M_impl(std::move(__i)) {}

  friend __coroutine& _Get_coroutine(const basic_await_context& __c)
    { return _Get_coroutine(*__c._M_impl); }
  friend __coroutine& _Get_coroutine(const basic_await_context* __c)
    { return _Get_coroutine(*__c->_M_impl); }
  friend exception_ptr* _Get_coroutine_exception(const basic_await_context& __c)
    { return _Get_coroutine_exception(*__c._M_impl); }
  friend exception_ptr* _Get_coroutine_exception(const basic_await_context* __c)
    { return _Get_coroutine_exception(*__c->_M_impl); }
  friend void** _Get_coroutine_async_result(const basic_await_context& __c)
    { return _Get_coroutine_async_result(*__c._M_impl); }
  friend void** _Get_coroutine_async_result(const basic_await_context* __c)
    { return _Get_coroutine_async_result(*__c->_M_impl); }

  _Executor _M_executor;
  shared_ptr<__await_context_impl_base> _M_impl;
  error_code* _M_error_code = nullptr;
};

template <class _Executor, class _R, class... _Args>
  struct handler_type<basic_await_context<_Executor>, _R(_Args...)>;

typedef basic_await_context<executor> await_context;

} // inline namespace concurrency_v1
} // namespace experimental
} // namespace std

#include <experimental/bits/await_context.h>

#endif
