// Copyright (c) 2023 Klemens D. Morgenstern
//
// 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 BOOST_COBALT_DETAIL_LEAF_HPP
#define BOOST_COBALT_DETAIL_LEAF_HPP

#include <boost/cobalt/detail/await_result_helper.hpp>
#include <boost/leaf/config.hpp>
#include <boost/leaf/handle_errors.hpp>

namespace boost::cobalt::detail
{

template<typename Awaitable, typename ... H>
struct [[nodiscard]] try_catch_awaitable
{
  Awaitable aw;
  std::tuple<H...> handler;

  bool await_ready() {return aw.await_ready(); }
  template<typename Promise>
  auto await_suspend(std::coroutine_handle<Promise> h) {return aw.await_suspend(h);}

  auto await_resume()
  {
    return std::apply(
        [this](auto && ... h)
        {
          return leaf::try_catch(
              [this]{return std::move(aw).await_resume();},
              std::move(h)...);
        }, std::move(handler));
  }
};

template<typename Awaitable, typename ... H>
struct [[nodiscard]] try_handle_all_awaitable
{
  Awaitable aw;
  std::tuple<H...> handler;

  bool await_ready() {return aw.await_ready(); }
  template<typename Promise>
  auto await_suspend(std::coroutine_handle<Promise> h) {return aw.await_suspend(h);}

  auto await_resume()
  {
    return std::apply(
        [this](auto && ... h)
        {
          return leaf::try_handle_all(
              [this]{return std::move(aw).await_resume();},
              std::move(h)...);
        }, std::move(handler));
  }
};



template<typename Awaitable, typename ... H>
struct [[nodiscard]] try_handle_some_awaitable
{
  Awaitable aw;
  std::tuple<H...> handler;

  bool await_ready() {return aw.await_ready(); }
  template<typename Promise>
  auto await_suspend(std::coroutine_handle<Promise> h) {return aw.await_suspend(h);}

  auto await_resume()
  {
    return std::apply(
        [this](auto && ... h)
        {
          return leaf::try_handle_some(
              [this]{return std::move(aw).await_resume();},
              std::move(h)...);
        }, std::move(handler));
  }
};

}

#endif //BOOST_COBALT_DETAIL_LEAF_HPP