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
7 changes: 6 additions & 1 deletion include/beman/execution/detail/let.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -169,14 +169,19 @@ struct let_t {
template <typename C, typename... A>
struct apply_decayed<C(A...)> {
using sender_type = ::beman::execution::detail::call_result_t<Fun, ::std::decay_t<A>...>;
using completions = ::std::conditional_t<
noexcept(::std::declval<Fun>()(std::declval<::std::decay_t<A>>()...)),
::beman::execution::completion_signatures<>,
::beman::execution::completion_signatures<::beman::execution::set_error_t(::std::exception_ptr)>>;
};
template <typename>
struct get_completions;
template <template <typename...> class L, typename... C>
struct get_completions<L<C...>> {
using type = ::beman::execution::detail::meta::unique<::beman::execution::detail::meta::combine<
::beman::execution::completion_signatures<>,
::beman::execution::completion_signatures_of_t<typename apply_decayed<C>::sender_type, Env...>...>>;
::beman::execution::completion_signatures_of_t<typename apply_decayed<C>::sender_type, Env...>...,
typename apply_decayed<C>::completions...>>;
};

using upstream_env = typename let_upstream_env_helper<Child, 0 < sizeof...(Env), Env...>::type;
Expand Down
9 changes: 9 additions & 0 deletions tests/beman/execution/exec-just.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <memory_resource>
#include <string>
#include <test/execution.hpp>
#include <test/completion_test.hpp>
#ifdef BEMAN_HAS_MODULES
import beman.execution;
import beman.execution.detail;
Expand Down Expand Up @@ -201,6 +202,13 @@ auto test_just_allocator() -> void {
test::use(state);
ASSERT(resource.count == 2u);
}

auto test_completion_signatures() -> void {
test_std::sync_wait(test::completion_test(test_std::just()));
test_std::sync_wait(test::completion_test(test_std::just(1, 2, 3)));
test_std::sync_wait(test::completion_test(test_std::just_error(1)));
test_std::sync_wait(test::completion_test(test_std::just_stopped()));
}
} // namespace

TEST(exec_just) {
Expand All @@ -211,6 +219,7 @@ TEST(exec_just) {
try {
test_just_constraints();
test_just();
test_completion_signatures();
#ifndef _MSC_VER
//-dk:TODO re-enable allocator test for MSVC++
test_just_allocator();
Expand Down
12 changes: 12 additions & 0 deletions tests/beman/execution/exec-let.test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
#include <array>
#include <cstdlib>
#include <concepts>
#include <exception>
#include <memory_resource>
#include <span>
#include <vector>
#include <test/execution.hpp>
#include <test/completion_test.hpp>
#ifdef BEMAN_HAS_MODULES
import beman.execution;
#else
Expand Down Expand Up @@ -120,6 +122,15 @@ auto test_let_value_env() -> void {
ex::sync_wait(ex::just() | ex::let_value([] { return ex::read_env(ex::get_scheduler); }) |
ex::then([](auto s) { static_assert(ex::scheduler<decltype(s)>); }));
}

auto test_completion_signatures() -> void {
test_std::sync_wait(
test::completion_test(test_std::just() | test_std::let_value([]() { return test_std::just(); })));
test_std::sync_wait(
test::completion_test(test_std::just() | test_std::let_value([]() noexcept { return test_std::just(); })));
test_std::sync_wait(test::completion_test(
test_std::just() | test_std::let_value([]() noexcept { return test_std::just_error(std::exception_ptr{}); })));
}
Comment thread
dietmarkuehl marked this conversation as resolved.
} // namespace

// ----------------------------------------------------------------------------
Expand All @@ -133,6 +144,7 @@ TEST(exec_let) {
test_let_value();
test_let_value_allocator();
test_let_value_env();
test_completion_signatures();
} catch (...) {
// NOLINTBEGIN(cert-dcl03-c,hicpp-static-assert,misc-static-assert)
ASSERT(nullptr == "let tests are not expected to throw");
Expand Down
126 changes: 126 additions & 0 deletions tests/beman/execution/include/test/completion_test.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
// tests/beman/execution/include/test/completion_test.hpp -*-C++-*-
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception

#ifndef INCLUDED_TESTS_BEMAN_EXECUTION_INCLUDE_TEST_COMPLETION_TEST
#define INCLUDED_TESTS_BEMAN_EXECUTION_INCLUDE_TEST_COMPLETION_TEST

#include <beman/execution/detail/common.hpp>
#include <test/execution.hpp>
#ifdef BEMAN_HAS_IMPORT_STD
import std;
#else
#include <concepts>
#include <cstddef>
#include <functional>
#include <utility>
#include <type_traits>
#endif
#ifdef BEMAN_HAS_MODULES
import beman.execution.detail.completion_signatures;
import beman.execution.detail.connect;
import beman.execution.detail.env_of_t;
import beman.execution.detail.get_completion_signatures;
import beman.execution.detail.get_env;
import beman.execution.detail.operation_state;
import beman.execution.detail.receiver;
import beman.execution.detail.sender;
import beman.execution.detail.set_error;
import beman.execution.detail.set_stopped;
import beman.execution.detail.set_value;
import beman.execution.detail.start;
#else
#include <beman/execution/detail/completion_signatures.hpp>
#include <beman/execution/detail/connect.hpp>
#include <beman/execution/detail/env_of_t.hpp>
#include <beman/execution/detail/get_completion_signatures.hpp>
#include <beman/execution/detail/get_env.hpp>
#include <beman/execution/detail/operation_state.hpp>
#include <beman/execution/detail/receiver.hpp>
#include <beman/execution/detail/sender.hpp>
#include <beman/execution/detail/set_error.hpp>
#include <beman/execution/detail/set_stopped.hpp>
#include <beman/execution/detail/set_value.hpp>
#include <beman/execution/detail/start.hpp>
#endif

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

namespace test {
struct completion_test_base {
virtual auto complete() const noexcept -> void = 0;
};
template <typename>
struct completion_test_function;

template <typename... T>
struct completion_test_function<::beman::execution::set_value_t(T...)> : completion_test_base {
auto set_value(T...) const noexcept -> void { this->complete(); }
};
template <typename E>
struct completion_test_function<::beman::execution::set_error_t(E)> : completion_test_base {
auto set_error(E) const noexcept -> void { this->complete(); }
};
template <>
struct completion_test_function<::beman::execution::set_stopped_t()> : completion_test_base {
auto set_stopped() const noexcept -> void { this->complete(); }
};

template <typename>
struct completion_test_receiver;
template <typename... Sigs>
struct completion_test_receiver<::beman::execution::completion_signatures<Sigs...>>
: completion_test_function<Sigs>... {};

template <::beman::execution::sender Sender>
struct completion_test {
using sender_concept = ::beman::execution::sender_t;
template <typename...>
static consteval auto get_completion_signatures() noexcept {
return ::beman::execution::completion_signatures<::beman::execution::set_value_t()>();
}

template <::beman::execution::receiver Receiver>
struct state {
using operation_state_concept = ::beman::execution::operation_state_t;
struct inner_receiver
: test::completion_test_receiver<
decltype(::beman::execution::get_completion_signatures<Sender,
::beman::execution::env_of_t<Receiver>>())> {
using receiver_concept = ::beman::execution::receiver_t;
state* st;
auto get_env() const noexcept -> ::beman::execution::env_of_t<Receiver> {
return ::beman::execution::get_env(this->st->receiver);
}
auto complete() const noexcept -> void override {
::beman::execution::set_value(std::move(this->st->receiver));
}
Comment thread
dietmarkuehl marked this conversation as resolved.
inner_receiver(state* s) : st(s) {}
};
using inner_state_t =
decltype(::beman::execution::connect(std::declval<Sender>(), std::declval<inner_receiver>()));

std::remove_cvref_t<Receiver> receiver;
inner_state_t inner_state;

template <::beman::execution::receiver R, ::beman::execution::sender S>
state(R&& r, S&& s)
: receiver(std::forward<R>(r)),
inner_state(::beman::execution::connect(std::forward<S>(s), inner_receiver(this))) {}
auto start() noexcept { ::beman::execution::start(this->inner_state); }
};

Sender sender;

template <::beman::execution::receiver Receiver>
auto connect(Receiver&& r) && {
return state<Receiver>{std::forward<Receiver>(r), std::move(this->sender)};
}
};

template <::beman::execution::sender Sender>
completion_test(Sender&& sender) -> completion_test<std::remove_cvref_t<Sender>>;
} // namespace test

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

#endif
Loading