Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .cursorignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
*
!doc/
!doc/**
!example/
!example/**
!include/
!include/**
!src/
!src/**
!test/
!test/**
58 changes: 0 additions & 58 deletions .github/workflows/claude.yml

This file was deleted.

106 changes: 106 additions & 0 deletions include/boost/capy/async_result.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail 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)
//
// Official repository: https://github.com/cppalliance/capy
//

#ifndef BOOST_CAPY_ASYNC_RESULT_HPP
#define BOOST_CAPY_ASYNC_RESULT_HPP

#include <boost/capy/detail/config.hpp>

#ifdef BOOST_CAPY_HAS_CORO

#include <coroutine>
#include <exception>
#include <functional>
#include <memory>
#include <variant>

namespace boost {
namespace capy {

template<class T>
class async_result
{
public:
struct impl_base
{
virtual ~impl_base() = default;
virtual void start(std::function<void()> on_done) = 0;
virtual T get_result() = 0;
};

private:
std::unique_ptr<impl_base> impl_;

public:
explicit async_result(std::unique_ptr<impl_base> p) : impl_(std::move(p)) {}

async_result(async_result&&) = default;
async_result& operator=(async_result&&) = default;

bool await_ready() const noexcept { return false; }

void await_suspend(std::coroutine_handle<> h)
{
impl_->start([h]{ h.resume(); });
}

T await_resume()
{
return impl_->get_result();
}
};

//-----------------------------------------------------------------------------

template<class T, class DeferredOp>
struct async_result_impl : capy::async_result<T>::impl_base
{
DeferredOp op_;
std::variant<std::exception_ptr, T> result_;

explicit async_result_impl(DeferredOp&& op)
: op_(std::forward<DeferredOp>(op))
{
}

void start(std::function<void()> on_done) override
{
std::move(op_)(
[this, on_done = std::move(on_done)](auto&&... args) mutable
{
result_.template emplace<1>(T{std::forward<decltype(args)>(args)...});
on_done();
});
}

T get_result() override
{
if (result_.index() == 0 && std::get<0>(result_))
std::rethrow_exception(std::get<0>(result_));
return std::move(std::get<1>(result_));
}
};

//-----------------------------------------------------------------------------

template<class T, class DeferredOp>
capy::async_result<T>
make_async_result(DeferredOp&& op)
{
using impl_type = async_result_impl<T, std::decay_t<DeferredOp>>;
return capy::async_result<T>(
std::make_unique<impl_type>(std::forward<DeferredOp>(op)));
}

} // capy
} // boost

#endif

#endif
12 changes: 12 additions & 0 deletions include/boost/capy/detail/config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,10 @@

#include <boost/config.hpp>

#if __has_include(<version>)
# include <version>
#endif

namespace boost {
namespace capy {

Expand Down Expand Up @@ -40,6 +44,14 @@ namespace capy {

//------------------------------------------------

#if defined(__cpp_lib_coroutine) && __cpp_lib_coroutine >= 201902L
# define BOOST_CAPY_HAS_CORO 1
#elif defined(__cpp_impl_coroutine) && __cpp_impl_coroutines >= 201902L
# define BOOST_CAPY_HAS_CORO 1
#endif

//------------------------------------------------

// Add source location to error codes
#ifdef BOOST_CAPY_NO_SOURCE_LOCATION
# define BOOST_CAPY_ERR(ev) (::boost::system::error_code(ev))
Expand Down
103 changes: 103 additions & 0 deletions include/boost/capy/task.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail 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)
//
// Official repository: https://github.com/cppalliance/capy
//

#ifndef BOOST_CAPY_TASK_HPP
#define BOOST_CAPY_TASK_HPP

#include <boost/capy/detail/config.hpp>

#ifdef BOOST_CAPY_HAS_CORO

#include <coroutine>
#include <exception>
#include <functional>
#include <utility>
#include <variant>

namespace boost {
namespace capy {

template<class T>
class task
{
public:
struct promise_type
{
std::variant<std::monostate, T, std::exception_ptr> result_;
std::function<void()> on_done_;

task get_return_object()
{
return task{std::coroutine_handle<promise_type>::from_promise(*this)};
}

std::suspend_always initial_suspend() noexcept { return {}; }

auto final_suspend() noexcept
{
struct awaiter
{
promise_type* p_;
bool await_ready() noexcept { return false; }
void await_suspend(std::coroutine_handle<>) noexcept
{
if (p_->on_done_)
p_->on_done_();
}
void await_resume() noexcept {}
};
return awaiter{this};
}

void return_value(T v) { result_.template emplace<1>(std::move(v)); }
void unhandled_exception() { result_.template emplace<2>(std::current_exception()); }
};

private:
std::coroutine_handle<promise_type> h_;

public:
explicit task(std::coroutine_handle<promise_type> h) : h_(h) {}
~task() { if (h_) h_.destroy(); }

task(task&& o) noexcept : h_(std::exchange(o.h_, {})) {}
task& operator=(task&&) = delete;

// For awaiting from another task<U>
bool await_ready() const noexcept { return false; }

std::coroutine_handle<> await_suspend(std::coroutine_handle<> caller) noexcept
{
h_.promise().on_done_ = [caller]{ caller.resume(); };
return h_;
}

T await_resume()
{
auto& r = h_.promise().result_;
if (r.index() == 2)
std::rethrow_exception(std::get<2>(r));
return std::move(std::get<1>(r));
}

// For external drivers
std::coroutine_handle<promise_type> handle() const noexcept { return h_; }

std::coroutine_handle<promise_type> release() noexcept
{
return std::exchange(h_, {});
}
};

} // capy
} // boost

#endif

#endif
2 changes: 2 additions & 0 deletions test/unit/application.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@

#include "test_suite.hpp"

#include <iostream>

namespace boost {
namespace capy {

Expand Down
35 changes: 35 additions & 0 deletions test/unit/async_result.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
//
// Copyright (c) 2025 Vinnie Falco (vinnie dot falco at gmail 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)
//
// Official repository: https://github.com/cppalliance/beast2
//

// Test that header file is self-contained.
#include <boost/capy/async_result.hpp>

#ifdef BOOST_CAPY_HAS_CORO

#include "test_suite.hpp"

namespace boost {
namespace capy {

struct async_result_test
{
void
run()
{
}
};

TEST_SUITE(
async_result_test,
"boost.capy.async_result");

} // capy
} // boost

#endif
Loading