diff --git a/include/exec/just_from.hpp b/include/exec/just_from.hpp index 3e9b1c3c6..74b5ee890 100644 --- a/include/exec/just_from.hpp +++ b/include/exec/just_from.hpp @@ -71,9 +71,11 @@ namespace experimental::execution template STDEXEC_ATTRIBUTE(always_inline, host, device) - void operator()(Ts &&...ts) const noexcept + auto + operator()(Ts &&...ts) const noexcept -> STDEXEC::completion_signatures<_set_tag_t(Ts...)> { _set_tag_t()(static_cast(_rcvr), static_cast(ts)...); + return {}; } }; diff --git a/test/exec/test_just_from.cpp b/test/exec/test_just_from.cpp index b921f6b1b..4c0eb3980 100644 --- a/test/exec/test_just_from.cpp +++ b/test/exec/test_just_from.cpp @@ -21,6 +21,8 @@ #include +#include + namespace { constinit int global_int = 0; @@ -93,6 +95,93 @@ namespace CHECK(c == 44); } + TEST_CASE("just_from sinks return value completion signatures", "[just_from]") + { + SECTION("no values") + { + auto s = exec::just_from( + [](auto sink) noexcept + { + auto completions = sink(); + STATIC_REQUIRE( + std::same_as>); + return completions; + }); + auto op = ex::connect(s, expect_void_receiver{}); + ex::start(op); + } + + SECTION("multiple values") + { + auto s = exec::just_from( + [](auto sink) noexcept + { + auto completions = sink(42, 3.14); + STATIC_REQUIRE(std::same_as>); + return completions; + }); + auto [i, d] = ex::sync_wait(s).value(); + CHECK(i == 42); + CHECK(d == 3.14); + } + + SECTION("references") + { + int const value = 42; + auto s = exec::just_from( + [&value](auto sink) noexcept + { + auto completions = sink(global_int, value); + STATIC_REQUIRE( + std::same_as>); + return completions; + }); + auto op = ex::connect(s, expect_value_receiver{global_int, value}); + ex::start(op); + } + } + + TEST_CASE("just_from can return its sink result directly", "[just_from]") + { + auto sender = exec::just_from([](auto sink) noexcept { return sink(17); }); + auto [value] = ex::sync_wait(sender).value(); + CHECK(value == 17); + } + + TEST_CASE("just_error_from sinks return error completion signatures", "[just_from]") + { + auto s = exec::just_error_from( + [](auto sink) noexcept + { + auto completions = sink(42); + STATIC_REQUIRE( + std::same_as>); + return completions; + }); + ::check_err_types>(s); + int error = 0; + auto op = ex::connect(std::move(s), expect_error_receiver_ex{error}); + ex::start(op); + CHECK(error == 42); + } + + TEST_CASE("just_stopped_from sinks return stopped completion signatures", "[just_from]") + { + auto s = exec::just_stopped_from( + [](auto sink) noexcept + { + auto completions = sink(); + STATIC_REQUIRE( + std::same_as>); + return completions; + }); + ::check_sends_stopped(s); + s.submit(expect_stopped_receiver{}); + std::move(s).submit(expect_stopped_receiver{}); + } + TEST_CASE("just_from is conditionally noexcept when storing the callable", "[just_from]") { auto nothrow_fn = [](auto sink) noexcept