Skip to content

Commit

Permalink
✨ Add into_variant
Browse files Browse the repository at this point in the history
  • Loading branch information
elbeno committed Nov 26, 2024
1 parent 6c1c364 commit 27377f7
Show file tree
Hide file tree
Showing 5 changed files with 380 additions and 0 deletions.
23 changes: 23 additions & 0 deletions docs/sender_adaptors.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,29 @@ NOTE: The incited scheduler must produce a sender which completes
asynchronously. A synchronous scheduler would require no incitement, and
`continue_on` would be correct.

=== `into_variant`

Found in the header: `async/into_variant.hpp`

`into_variant` adapts a sender that has several possible value completions into
a sender with a single value completion that is a variant of tuples, where each
tuple represents one of the original sender's value completions.

[source,cpp]
----
auto sndr = async::make_variant_sender(
selection,
[] { return async::just(42, 17); },
[] { return async::just(2.718f, 3.14f); })
| async::into_variant();
// sndr will complete with set_value(variant<tuple<int, int>, tuple<float, float>>)
----

NOTE: Some sender consumers (like
xref:sender_consumers.adoc#_sync_wait[`sync_wait`]) require the sender to have
one possible value completion.

=== `let_error`

Found in the header: `async/let_error.hpp`
Expand Down
4 changes: 4 additions & 0 deletions docs/synopsis.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,9 @@ in pipe-composition syntax.
==== https://github.com/intel/cpp-baremetal-senders-and-receivers/blob/main/include/async/incite_on.hpp[incite_on.hpp]
* `incite_on` - a xref:sender_adaptors.adoc#_incite_on[sender adaptor] that incites execution on another scheduler

==== https://github.com/intel/cpp-baremetal-senders-and-receivers/blob/main/include/async/into_variant.hpp[into_variant.hpp]
* `into_variant` - a xref:sender_adaptors.adoc#_into_variant[sender adaptor] that collapses value completions into a variant

==== https://github.com/intel/cpp-baremetal-senders-and-receivers/blob/main/include/async/just.hpp[just.hpp]
* `just` - a xref:sender_factories.adoc#_just[sender factory] that sends on the value channel
* `just_error` - a xref:sender_factories.adoc#_just_error[sender factory] that sends on the error channel
Expand Down Expand Up @@ -230,6 +233,7 @@ contains traits and metaprogramming constructs used by many senders.
* xref:schedulers.adoc#_inline_scheduler[`inline_scheduler`] - https://github.com/intel/cpp-baremetal-senders-and-receivers/blob/main/include/async/schedulers/inline_scheduler.hpp[`#include <async/schedulers/inline_scheduler.hpp>`]
* `inplace_stop_source` - https://github.com/intel/cpp-baremetal-senders-and-receivers/blob/main/include/async/schedulers/stop_token.hpp[`#include <async/stop_token.hpp>`]
* `inplace_stop_token`- https://github.com/intel/cpp-baremetal-senders-and-receivers/blob/main/include/async/schedulers/stop_token.hpp[`#include <async/stop_token.hpp>`]
* xref:sender_adaptors.adoc#_into_variant[`into_variant`] - https://github.com/intel/cpp-baremetal-senders-and-receivers/blob/main/include/async/into_variant.hpp[`#include <async/into_variant.hpp>`]
* xref:sender_factories.adoc#_just[`just`] - https://github.com/intel/cpp-baremetal-senders-and-receivers/blob/main/include/async/just.hpp[`#include <async/just.hpp>`]
* xref:sender_factories.adoc#_just_error[`just_error`] - https://github.com/intel/cpp-baremetal-senders-and-receivers/blob/main/include/async/just.hpp[`#include <async/just.hpp>`]
* xref:sender_factories.adoc#_just_error_result_of[`just_error_result_of`] - https://github.com/intel/cpp-baremetal-senders-and-receivers/blob/main/include/async/just_result_of.hpp[`#include <async/just_result_of.hpp>`]
Expand Down
130 changes: 130 additions & 0 deletions include/async/into_variant.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
#pragma once

#include <async/completion_tags.hpp>
#include <async/compose.hpp>
#include <async/concepts.hpp>
#include <async/connect.hpp>
#include <async/debug.hpp>
#include <async/env.hpp>
#include <async/type_traits.hpp>

#include <stdx/ct_string.hpp>
#include <stdx/tuple.hpp>
#include <stdx/type_traits.hpp>

#include <type_traits>
#include <utility>
#include <variant>

namespace async {
namespace _into_variant {
template <stdx::ct_string Name, typename S, typename V, typename Rcvr>
struct receiver {
using is_receiver = void;
using sender_t = S;

[[nodiscard]] constexpr auto
query(async::get_env_t) const -> forwarding_env<env_of_t<Rcvr>> {
return forward_env_of(r);
}

template <typename... Args> auto set_value(Args &&...args) && -> void {
debug_signal<set_value_t::name, debug::erased_context_for<receiver>>(
get_env(r));
std::move(r).set_value(
V{stdx::make_tuple(std::forward<Args>(args)...)});
}

template <typename... Args> auto set_error(Args &&...args) && -> void {
debug_signal<set_error_t::name, debug::erased_context_for<receiver>>(
get_env(r));
std::move(r).set_error(std::forward<Args>(args)...);
}
auto set_stopped() && -> void {
debug_signal<set_stopped_t::name, debug::erased_context_for<receiver>>(
get_env(r));
std::move(r).set_stopped();
}

[[no_unique_address]] Rcvr r;
};

namespace detail {
template <typename... As> using discard_signatures = completion_signatures<>;

template <typename... Ts>
using decayed_tuple = stdx::tuple<std::decay_t<Ts>...>;

template <typename S, typename Env, template <typename...> typename V>
using variant_t = value_types_of_t<S, Env, decayed_tuple, V>;
} // namespace detail

template <stdx::ct_string Name, typename S, template <typename...> typename V>
struct sender {
using is_sender = void;

template <async::receiver R>
[[nodiscard]] constexpr auto connect(R &&r) && {
check_connect<sender &&, R>();
using env_t = env_of_t<std::remove_cvref_t<R>>;
using variant_t = detail::variant_t<S, env_t, V>;
return async::connect(
std::move(s), receiver<Name, S, variant_t, std::remove_cvref_t<R>>{
std::forward<R>(r)});
}

template <async::receiver R>
requires multishot_sender<S>
[[nodiscard]] constexpr auto connect(R &&r) const & {
check_connect<sender const &, R>();
using env_t = env_of_t<std::remove_cvref_t<R>>;
using variant_t = detail::variant_t<S, env_t, V>;
return async::connect(
s, receiver<Name, S, variant_t, std::remove_cvref_t<R>>{
std::forward<R>(r)});
}

template <typename Env>
[[nodiscard]] constexpr static auto get_completion_signatures(Env const &) {
using variant_t = detail::variant_t<S, Env, V>;
return transform_completion_signatures_of<
S, Env, completion_signatures<set_value_t(variant_t)>,
detail::discard_signatures>{};
}

[[no_unique_address]] S s;
};

template <stdx::ct_string Name, template <typename...> typename V>
struct pipeable {
private:
template <async::sender S, stdx::same_as_unqualified<pipeable> Self>
friend constexpr auto operator|(S &&s, Self &&) -> async::sender auto {
return sender<Name, std::remove_cvref_t<S>, V>{std::forward<S>(s)};
}
};
} // namespace _into_variant

template <stdx::ct_string Name = "into_variant",
template <typename...> typename V = std::variant>
[[nodiscard]] constexpr auto into_variant() {
return _compose::adaptor<_into_variant::pipeable<Name, V>>{};
}

template <stdx::ct_string Name = "into_variant",
template <typename...> typename V = std::variant, sender S>
[[nodiscard]] constexpr auto into_variant(S &&s) -> sender auto {
return std::forward<S>(s) | into_variant<Name, V>();
}

struct into_variant_t;

template <stdx::ct_string Name, typename... Ts>
struct debug::context_for<_into_variant::receiver<Name, Ts...>> {
using tag = into_variant_t;
constexpr static auto name = Name;
using type = _into_variant::receiver<Name, Ts...>;
using children = stdx::type_list<debug::erased_context_for<
connect_result_t<typename type::sender_t &&, type &&>>>;
};
} // namespace async
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ add_tests(
freestanding_sync_wait
hosted_sync_wait
incite_on
into_variant
just
just_error
just_error_result_of
Expand Down
Loading

0 comments on commit 27377f7

Please sign in to comment.