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
2 changes: 1 addition & 1 deletion bench/beman/ioaw_read_stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ struct ioaw_read_stream
}

boost::capy::io_result<std::size_t>
await_resume() noexcept { return {{}, 0}; }
await_resume() noexcept { return {std::error_code(), 0}; }
};

template <boost::capy::MutableBufferSequence MB>
Expand Down
2 changes: 1 addition & 1 deletion bench/beman/ioaw_sync_read_stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ struct ioaw_sync_read_stream
boost::capy::io_result<std::size_t>
await_resume() noexcept
{
return {{}, 0};
return {std::error_code(), 0};
}
};

Expand Down
4 changes: 2 additions & 2 deletions bench/beman/sender_awaitable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ struct [[nodiscard]] sender_awaitable
return io_result<T>{
std::get<2>(result_)};
return io_result<T>{
{},
std::error_code(),
std::get<0>(
std::get<1>(
std::move(result_)))};
Expand All @@ -357,7 +357,7 @@ struct [[nodiscard]] sender_awaitable
return io_result<value_tuple>{
std::get<2>(result_)};
return io_result<value_tuple>{
{},
std::error_code(),
std::get<1>(
std::move(result_))};
}
Expand Down
2 changes: 1 addition & 1 deletion bench/stdexec/ioaw_read_stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ struct ioaw_read_stream
}

boost::capy::io_result<std::size_t>
await_resume() noexcept { return {{}, 0}; }
await_resume() noexcept { return {std::error_code(), 0}; }
};

template <boost::capy::MutableBufferSequence MB>
Expand Down
2 changes: 1 addition & 1 deletion bench/stdexec/ioaw_sync_read_stream.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ struct ioaw_sync_read_stream
boost::capy::io_result<std::size_t>
await_resume() noexcept
{
return {{}, 0};
return {std::error_code(), 0};
}
};

Expand Down
4 changes: 2 additions & 2 deletions bench/stdexec/sender_awaitable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -341,7 +341,7 @@ struct [[nodiscard]] sender_awaitable
return io_result<T>{
std::get<2>(result_), T{}};
return io_result<T>{
{},
std::error_code(),
std::get<0>(
std::get<1>(
std::move(result_)))};
Expand All @@ -356,7 +356,7 @@ struct [[nodiscard]] sender_awaitable
return io_result<value_tuple>{
std::get<2>(result_), value_tuple{}};
return io_result<value_tuple>{
{},
std::error_code(),
std::get<1>(
std::move(result_))};
}
Expand Down
2 changes: 1 addition & 1 deletion doc/modules/ROOT/pages/4.coroutines/4f.composition.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ include::example$snippets/4f_composition.cpp[tag=when_all_basic,indent=0]
include::example$snippets/4f_composition.cpp[tag=when_all_void_mix,indent=0]
----

When all children are `io_task<>`, just check `r.ec`:
When all children are `io_task<>`, just check the error code:

[source,cpp]
----
Expand Down
2 changes: 1 addition & 1 deletion doc/modules/ROOT/pages/8.examples/8g.parallel-fetch.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ include::example$parallel-fetch/parallel_fetch.cpp[tag=when_all_dashboard,indent
include::example$parallel-fetch/parallel_fetch.cpp[tag=when_all_void,indent=0]
----

`io_task<>` children return `io_result<>` (just an error code, no payload). Check `r.ec` to detect failure.
`io_task<>` children return `io_result<>` (just an error code, no payload). Check `std::get<0>(r)` to detect failure.

=== Error Propagation

Expand Down
4 changes: 2 additions & 2 deletions doc/modules/ROOT/pages/9.design/9i.TypeEraseAwaitable.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ std::coroutine_handle<> await_suspend(std::coroutine_handle<> h, io_env const* e

io_result<size_t> await_resume() {
if(!awaitable_active_)
return {{}, 0}; // short-circuited
return {std::error_code(), 0}; // short-circuited
auto r = vt_->await_resume(cached_awaitable_);
vt_->destroy_awaitable(cached_awaitable_);
awaitable_active_ = false;
Expand Down Expand Up @@ -130,7 +130,7 @@ std::coroutine_handle<> await_suspend(std::coroutine_handle<> h, io_env const* e

io_result<size_t> await_resume() {
if(!active_ops_)
return {{}, 0}; // short-circuited
return {std::error_code(), 0}; // short-circuited
auto r = active_ops_->await_resume(cached_awaitable_);
active_ops_->destroy(cached_awaitable_);
active_ops_ = nullptr;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ as their postconditions never say that the requested number of bytes will indeed
processed.

Each stream operation that may encounter a contingency await-returns
a type which is a specialization of `capy::io_result`. These objects can be _destructured_
an instance of `capy::io_result`. These objects can be _destructured_
using a structured binding. The first binding of such destructuring is of type
`std::error_code`. This binding, call it `ec`, is used to signal if and which
contingency occured:
Expand Down
2 changes: 1 addition & 1 deletion doc/unlisted/coroutines-when-all.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ auto r = co_await when_all(
task_void(),
task_void()
);
if (r.ec)
if (std::get<0>(r))
// handle error
----

Expand Down
8 changes: 4 additions & 4 deletions doc/unlisted/coroutines-when-any.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -233,10 +233,10 @@ io_task<Response> fetch_with_cancel_support()
for (auto& chunk : data_source)
{
if (token.stop_requested())
co_return io_result<Response>{{}, partial_response()};
co_return io_result<Response>{std::error_code(), partial_response()};
co_await send_chunk(chunk);
}
co_return io_result<Response>{{}, complete_response()};
co_return io_result<Response>{std::error_code(), complete_response()};
}

task<> example()
Expand Down Expand Up @@ -333,7 +333,7 @@ io_task<Response> fetch_with_redundancy(Request req)
if constexpr (!std::is_same_v<std::decay_t<decltype(v)>, std::error_code>)
resp = v;
}, result);
co_return io_result<Response>{{}, std::move(resp)};
co_return io_result<Response>{std::error_code(), std::move(resp)};
}
----

Expand All @@ -357,7 +357,7 @@ io_task<Connection> get_connection(std::vector<ConnectionPool>& pools)

auto& [index, conn] = std::get<1>(result);
std::cout << "Got connection from pool " << index << "\n";
co_return io_result<Connection>{{}, std::move(conn)};
co_return io_result<Connection>{std::error_code(), std::move(conn)};
}
----

Expand Down
27 changes: 25 additions & 2 deletions doc/unlisted/library-io-result.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,30 @@ Features:
* Structured bindings for clean syntax
* Error code is always present
* Additional values (bytes transferred, etc.) included
* `[[nodiscard]]` prevents ignoring results
* An alias for `std::tuple`, so the whole standard tuple API
applies: `std::tie`, `std::apply`, `std::get`, comparisons
* Library awaitables mark `await_resume` `[[nodiscard]]`, so
discarding a result is diagnosed

== Rebinding with std::tie

When a coroutine performs several operations in sequence,
`std::tie` reassigns into existing variables instead of
introducing a new binding per operation:

[source,cpp]
----
std::error_code ec;
std::size_t n = 0;

std::tie(ec, n) = co_await s.read_some(buf);
if (ec)
co_return ec;

std::tie(ec, n) = co_await s.write(buf);
if (ec)
co_return ec;
----

== io_result Variants

Expand Down Expand Up @@ -185,7 +208,7 @@ io_task<std::size_t> read_all(stream& s, buffer& buf)
buf.commit(n);
total += n;
}
co_return {{}, total}; // Success with total bytes
co_return {std::error_code(), total}; // Success with total bytes
}
----

Expand Down
4 changes: 2 additions & 2 deletions example/asio/any_stream.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -82,8 +82,8 @@ run_example(
writer(client_stream, total_bytes),
reader(server_stream, total_bytes));

if(r.ec)
std::printf("example error: %s\n", r.ec.message().c_str());
if(std::get<0>(r))
std::printf("example error: %s\n", std::get<0>(r).message().c_str());
else
std::printf("example complete!\n");
}
Expand Down
8 changes: 4 additions & 4 deletions example/asio/api/capy_streams.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,8 +114,8 @@ class asio_socket
boost::system::error_code ec,
std::size_t n) mutable
{
result_.ec = ec;
std::get<0>(result_.values) = n;
std::get<0>(result_) = ec;
std::get<1>(result_) = n;
ex.post(cont_);
}));

Expand Down Expand Up @@ -178,8 +178,8 @@ class asio_socket
boost::system::error_code ec,
std::size_t n) mutable
{
result_.ec = ec;
std::get<0>(result_.values) = n;
std::get<0>(result_) = ec;
std::get<1>(result_) = n;
ex.post(cont_);
}));

Expand Down
20 changes: 10 additions & 10 deletions example/asio/api/use_capy.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -162,31 +162,31 @@ class capy_awaitable
private:
void store_result(boost::system::error_code ec)
{
result_.ec = ec;
std::get<0>(result_) = ec;
}

template<typename T1>
void store_result(boost::system::error_code ec, T1&& t1)
{
result_.ec = ec;
std::get<0>(result_.values) = std::forward<T1>(t1);
std::get<0>(result_) = ec;
std::get<1>(result_) = std::forward<T1>(t1);
}

template<typename T1, typename T2>
void store_result(boost::system::error_code ec, T1&& t1, T2&& t2)
{
result_.ec = ec;
std::get<0>(result_.values) = std::forward<T1>(t1);
std::get<1>(result_.values) = std::forward<T2>(t2);
std::get<0>(result_) = ec;
std::get<1>(result_) = std::forward<T1>(t1);
std::get<2>(result_) = std::forward<T2>(t2);
}

template<typename T1, typename T2, typename T3>
void store_result(boost::system::error_code ec, T1&& t1, T2&& t2, T3&& t3)
{
result_.ec = ec;
std::get<0>(result_.values) = std::forward<T1>(t1);
std::get<1>(result_.values) = std::forward<T2>(t2);
std::get<2>(result_.values) = std::forward<T3>(t3);
std::get<0>(result_) = ec;
std::get<1>(result_) = std::forward<T1>(t1);
std::get<2>(result_) = std::forward<T2>(t2);
std::get<3>(result_) = std::forward<T3>(t3);
}
};

Expand Down
4 changes: 2 additions & 2 deletions example/asio/use_capy_example.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -95,8 +95,8 @@ run_example(
writer(client, total_bytes),
reader(server, total_bytes));

if (r.ec)
std::printf("example error: %s\n", r.ec.message().c_str());
if (std::get<0>(r))
std::printf("example error: %s\n", std::get<0>(r).message().c_str());
else
std::printf("example complete!\n");
}
Expand Down
4 changes: 2 additions & 2 deletions example/async-mutex/async_mutex.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -72,9 +72,9 @@ int main()
auto r = co_await capy::when_all(
worker(0), worker(1), worker(2),
worker(3), worker(4), worker(5));
if(r.ec)
if(std::get<0>(r))
std::cerr << "when_all error: "
<< r.ec.message() << "\n";
<< std::get<0>(r).message() << "\n";
};

// Run on a strand so async_mutex operations are single-threaded
Expand Down
2 changes: 1 addition & 1 deletion example/cuda/datamovement/cuda_datamovement.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ class cuda_device_stream
}
auto n = buf.size();
self->offset_ += n;
return {{}, n};
return {std::error_code(), n};
}
};
return awaitable{this, *capy::begin(buffers)};
Expand Down
4 changes: 2 additions & 2 deletions example/cuda/pipeline/sender_awaitable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -342,7 +342,7 @@ struct [[nodiscard]] sender_awaitable
return io_result<T>{
std::get<2>(result_), T{}};
return io_result<T>{
{},
std::error_code(),
std::get<0>(
std::get<1>(
std::move(result_)))};
Expand All @@ -357,7 +357,7 @@ struct [[nodiscard]] sender_awaitable
return io_result<value_tuple>{
std::get<2>(result_), value_tuple{}};
return io_result<value_tuple>{
{},
std::error_code(),
std::get<1>(
std::move(result_))};
}
Expand Down
2 changes: 1 addition & 1 deletion example/custom-executor/custom_executor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ static_assert(capy::Executor<run_loop::executor_type>);
capy::io_task<int> compute(int x)
{
std::cout << " computing " << x << " * " << x << "\n";
co_return capy::io_result<int>{{}, x * x};
co_return capy::io_result<int>{std::error_code(), x * x};
}

capy::task<> run_tasks()
Expand Down
6 changes: 3 additions & 3 deletions example/parallel-fetch/parallel_fetch.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ capy::task<> fetch_user_dashboard(std::string username)

auto wrap = [](auto inner) -> capy::io_task<decltype(inner.await_resume())> {
co_return capy::io_result<decltype(inner.await_resume())>{
{}, co_await std::move(inner)};
std::error_code(), co_await std::move(inner)};
};

// tag::when_all_dashboard[]
Expand Down Expand Up @@ -94,7 +94,7 @@ capy::task<std::string> fetch_with_side_effects()
auto r = co_await capy::when_all(
log_access("api/data"),
update_metrics("api_calls"));
if (r.ec)
if (std::get<0>(r))
co_return "error";
// end::when_all_void[]

Expand All @@ -115,7 +115,7 @@ capy::io_task<int> might_fail(bool should_fail, std::string name)
}

std::cout << "Task " << name << " completed\n";
co_return capy::io_result<int>{{}, 42};
co_return capy::io_result<int>{std::error_code(), 42};
}

capy::task<> demonstrate_error_handling()
Expand Down
2 changes: 1 addition & 1 deletion example/parallel-tasks/parallel_tasks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ capy::io_task<long long> partial_sum(int lo, int hi)
long long sum = 0;
for (int i = lo; i < hi; ++i)
sum += i;
co_return capy::io_result<long long>{{}, sum};
co_return capy::io_result<long long>{std::error_code(), sum};
}

int main()
Expand Down
4 changes: 2 additions & 2 deletions example/sender-bridge/sender_awaitable.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ struct [[nodiscard]] sender_awaitable
return io_result<T>{
std::get<2>(result_)};
return io_result<T>{
{},
std::error_code(),
std::get<0>(
std::get<1>(
std::move(result_)))};
Expand All @@ -335,7 +335,7 @@ struct [[nodiscard]] sender_awaitable
return io_result<value_tuple>{
std::get<2>(result_)};
return io_result<value_tuple>{
{},
std::error_code(),
std::get<1>(
std::move(result_))};
}
Expand Down
2 changes: 1 addition & 1 deletion example/timeout-cancellation/timeout_cancellation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ capy::io_task<std::string> await_fetch(fetch_channel& ch)
ch.cancelled.store(true);
co_return capy::io_result<std::string>{ec, {}};
}
co_return capy::io_result<std::string>{{}, std::move(ch.result)};
co_return capy::io_result<std::string>{std::error_code(), std::move(ch.result)};
}
// end::race_await_fetch[]

Expand Down
Loading
Loading