Skip to content

Commit cb00893

Browse files
committed
asioexec::completion_token:: & ::use_sender::as_default_on
When an Asio asynchronous operation is parameterized by an executor or an I/O object it can adopt the default completion token of that executor or of the executor associated with that I/O object, if any. Adopting a default completion token means that, if the initiating function does not receive an explicit completion token parameter, it will be implicitly parameterized by a default constructed instance of that default completion token type. Given that Asio I/O objects feature a rebind_executor nested template it follows from this that one can rebind an I/O object to be associated with an executor which exposes a certain default completion token. See for example boost::asio::use_awaitable_t and asio::awaitable_t (in Boost.Asio and standalone Asio, respectively). Therefore upgraded asioexec::completion_token and ::use_sender to support the pattern embodied by the aforementioned types from Boost.Asio/standalone Asio. By using the newly-added as_default_on members thereof an I/O object may be rebound to an executor type which causes that I/O object's initiating functions (and free initiating functions parameterized thereby) to yield a sender when no completion token is explicitly provided thereto. See the newly-added unit tests for examples.
1 parent 8c9deef commit cb00893

6 files changed

Lines changed: 129 additions & 2 deletions

File tree

include/asioexec/as_default_on.hpp

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
* Copyright (c) 2025 Robert Leahy. All rights reserved.
4+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
*
6+
* Licensed under the Apache License, Version 2.0 with LLVM Exceptions (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* https://llvm.org/LICENSE.txt
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <type_traits>
22+
#include <utility>
23+
#include <asioexec/asio_config.hpp>
24+
#include <asioexec/executor_with_default.hpp>
25+
26+
namespace asioexec {
27+
28+
template <typename CompletionToken, typename IoObject>
29+
using as_default_on_t =
30+
typename std::remove_cvref_t<IoObject>::template rebind_executor<executor_with_default<
31+
std::remove_cvref_t<decltype(std::declval<IoObject&>().get_executor())>,
32+
CompletionToken>>::other;
33+
34+
namespace detail::as_default_on {
35+
36+
template <typename CompletionToken>
37+
struct t {
38+
template <typename IoObject>
39+
constexpr asioexec::as_default_on_t<CompletionToken, IoObject>
40+
operator()(IoObject&& io) const {
41+
return asioexec::as_default_on_t<CompletionToken, IoObject>((IoObject&&) io);
42+
}
43+
};
44+
45+
} // namespace detail::as_default_on
46+
47+
template <typename CompletionToken>
48+
inline constexpr detail::as_default_on::t<CompletionToken> as_default_on;
49+
50+
} // namespace asioexec

include/asioexec/completion_token.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include <tuple>
2727
#include <type_traits>
2828
#include <utility>
29+
#include <asioexec/as_default_on.hpp>
2930
#include <asioexec/asio_config.hpp>
3031
#include <stdexec/execution.hpp>
3132

@@ -485,7 +486,11 @@ namespace asioexec {
485486

486487
} // namespace detail::completion_token
487488

488-
struct completion_token_t { };
489+
struct completion_token_t {
490+
static constexpr auto as_default_on = asioexec::as_default_on<completion_token_t>;
491+
template <typename IoObject>
492+
using as_default_on_t = asioexec::as_default_on_t<completion_token_t, IoObject>;
493+
};
489494

490495
inline const completion_token_t completion_token{};
491496

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
/*
2+
* SPDX-FileCopyrightText: Copyright (c) 2025 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
3+
* Copyright (c) 2025 Robert Leahy. All rights reserved.
4+
* SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
5+
*
6+
* Licensed under the Apache License, Version 2.0 with LLVM Exceptions (the "License");
7+
* you may not use this file except in compliance with the License.
8+
* You may obtain a copy of the License at
9+
*
10+
* https://llvm.org/LICENSE.txt
11+
*
12+
* Unless required by applicable law or agreed to in writing, software
13+
* distributed under the License is distributed on an "AS IS" BASIS,
14+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
* See the License for the specific language governing permissions and
16+
* limitations under the License.
17+
*/
18+
19+
#pragma once
20+
21+
#include <asioexec/asio_config.hpp>
22+
23+
namespace asioexec {
24+
25+
template <typename Executor, typename CompletionToken>
26+
struct executor_with_default : Executor {
27+
using default_completion_token_type = CompletionToken;
28+
executor_with_default(const Executor& ex) noexcept
29+
: Executor(ex) {
30+
}
31+
};
32+
33+
} // namespace asioexec

include/asioexec/use_sender.hpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <system_error>
2424
#include <type_traits>
2525
#include <utility>
26+
#include <asioexec/as_default_on.hpp>
2627
#include <asioexec/asio_config.hpp>
2728
#include <asioexec/completion_token.hpp>
2829
#include <stdexec/execution.hpp>
@@ -196,7 +197,11 @@ namespace asioexec {
196197

197198
} // namespace detail::use_sender
198199

199-
struct use_sender_t { };
200+
struct use_sender_t {
201+
static constexpr auto as_default_on = asioexec::as_default_on<use_sender_t>;
202+
template <typename IoObject>
203+
using as_default_on_t = asioexec::as_default_on_t<use_sender_t, IoObject>;
204+
};
200205

201206
inline const use_sender_t use_sender{};
202207

test/asioexec/test_completion_token.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -968,4 +968,22 @@ namespace {
968968
CHECK(ex);
969969
}
970970

971+
TEST_CASE(
972+
"I/O objects may be transformed to use senders as their default vocabulary with only minimal "
973+
"transformations (i.e. no error adaptation)",
974+
"[asioexec][completion_token]") {
975+
bool invoked = false;
976+
asio_impl::io_context ctx;
977+
auto t = completion_token.as_default_on(asio_impl::system_timer(ctx));
978+
static_assert(
979+
std::is_same_v<decltype(t), completion_token_t::as_default_on_t<asio_impl::system_timer>>);
980+
t.expires_after(std::chrono::milliseconds(5));
981+
auto op = ::stdexec::connect(
982+
t.async_wait() | ::stdexec::then([](auto ec) { CHECK(!ec); }),
983+
expect_void_receiver_ex(invoked));
984+
::stdexec::start(op);
985+
CHECK(ctx.run() != 0);
986+
CHECK(ctx.stopped());
987+
}
988+
971989
} // namespace

test/asioexec/test_use_sender.cpp

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include <exception>
2323
#include <functional>
2424
#include <system_error>
25+
#include <type_traits>
2526
#include <utility>
2627
#include <asioexec/asio_config.hpp>
2728
#include <catch2/catch.hpp>
@@ -234,4 +235,19 @@ namespace {
234235
CHECK_THROWS_AS(std::rethrow_exception(std::move(ex)), std::system_error);
235236
}
236237

238+
TEST_CASE(
239+
"I/O objects may be transformed to use senders as their default vocabulary",
240+
"[asioexec][use_sender]") {
241+
bool invoked = false;
242+
asio_impl::io_context ctx;
243+
auto t = use_sender.as_default_on(asio_impl::system_timer(ctx));
244+
static_assert(
245+
std::is_same_v<decltype(t), use_sender_t::as_default_on_t<asio_impl::system_timer>>);
246+
t.expires_after(std::chrono::milliseconds(5));
247+
auto op = ::stdexec::connect(t.async_wait(), expect_void_receiver_ex(invoked));
248+
::stdexec::start(op);
249+
CHECK(ctx.run() != 0);
250+
CHECK(ctx.stopped());
251+
}
252+
237253
} // namespace

0 commit comments

Comments
 (0)