Skip to content
Open
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 include/exec/repeat_until.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,4 +304,15 @@ namespace STDEXEC {
return STDEXEC::get_completion_signatures<__sndr_t, _Env...>();
}
};

template <>
struct __sexpr_impl<exec::repeat_t> : __sexpr_defaults {
template <class _Sender, class... _Env>
static consteval auto get_completion_signatures() {
static_assert(sender_expr_for<_Sender, exec::repeat_t>);
using __sndr_t =
__detail::__transform_sender_result_t<exec::repeat_t, set_value_t, _Sender, env<>>;
return STDEXEC::get_completion_signatures<__sndr_t, _Env...>();
}
};
} // namespace STDEXEC
42 changes: 42 additions & 0 deletions test/exec/test_repeat_until.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

#include "exec/repeat_until.hpp"
#include "exec/static_thread_pool.hpp"
#include "stdexec/__detail/__sync_wait.hpp"
#include "stdexec/execution.hpp"

#include <test_common/receivers.hpp>
Expand Down Expand Up @@ -269,6 +270,47 @@ namespace {
} while (!done);
}

TEST_CASE("repeat composes with completion signatures") {
ex::sender auto only_stopped = ex::just_stopped() | exec::repeat();
static_assert(
std::same_as<ex::value_types_of_t<decltype(only_stopped)>, ex::__detail::__not_a_variant>,
"Expect no value completions");
static_assert(
std::same_as<ex::error_types_of_t<decltype(only_stopped)>, std::variant<std::exception_ptr>>,
"Missing added set_error_t(std::exception_ptr)");
static_assert(
ex::sender_of<decltype(only_stopped), ex::set_stopped_t()>,
"Missing set_stopped_t() from upstream");

// operator| and sync_wait require valid completion signatures
ex::sync_wait(only_stopped | ex::upon_stopped([]() noexcept { return -1; }));


ex::sender auto only_error = ex::just_error(-1) | exec::repeat();
static_assert(
std::same_as<ex::value_types_of_t<decltype(only_error)>, ex::__detail::__not_a_variant>,
"Expect no value completions");
static_assert(
std::same_as<
ex::error_types_of_t<decltype(only_error)>,
std::variant<int, std::exception_ptr>
>,
"Missing added set_error_t(std::exception_ptr)");

// set_stopped_t is always added as a consequence of the internal trampoline_scheduler
using SC = ex::completion_signatures_of_t<ex::schedule_result_t<exec::trampoline_scheduler>>;
static_assert(
!ex::sender_of<SC, ex::set_stopped_t()>
|| ex::sender_of<decltype(only_error), ex::set_stopped_t()>,
"Missing added set_error_t(std::exception_ptr)");

// operator| and sync_wait require valid completion signatures
ex::sync_wait(
only_error //
| ex::upon_stopped([]() { return -1; })
| ex::upon_error([](const auto) { return -1; }));
}

TEST_CASE(
"repeat_until works correctly when the child operation sends type which throws when "
"decay-copied, and when converted to bool, and which is only rvalue convertible to bool",
Expand Down