xref: /openbmc/sdbusplus/include/sdbusplus/async/stdexec/sequence_senders.hpp (revision a23d26bd8cd0cc40ff6311e86e0de2c7f43f55ea)
15932cd67SPatrick Williams /*
25932cd67SPatrick Williams  * Copyright (c) 2023 Maikel Nadolski
35932cd67SPatrick Williams  * Copyright (c) 2023 NVIDIA Corporation
45932cd67SPatrick Williams  *
55932cd67SPatrick Williams  * Licensed under the Apache License Version 2.0 with LLVM Exceptions
65932cd67SPatrick Williams  * (the "License"); you may not use this file except in compliance with
75932cd67SPatrick Williams  * the License. You may obtain a copy of the License at
85932cd67SPatrick Williams  *
95932cd67SPatrick Williams  *   https://llvm.org/LICENSE.txt
105932cd67SPatrick Williams  *
115932cd67SPatrick Williams  * Unless required by applicable law or agreed to in writing, software
125932cd67SPatrick Williams  * distributed under the License is distributed on an "AS IS" BASIS,
135932cd67SPatrick Williams  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
145932cd67SPatrick Williams  * See the License for the specific language governing permissions and
155932cd67SPatrick Williams  * limitations under the License.
165932cd67SPatrick Williams  */
175932cd67SPatrick Williams #pragma once
185932cd67SPatrick Williams 
195932cd67SPatrick Williams #include "../stdexec/execution.hpp"
205932cd67SPatrick Williams 
215932cd67SPatrick Williams namespace exec
225932cd67SPatrick Williams {
234c2d73ddSPatrick Williams struct sequence_sender_t : stdexec::sender_t
245932cd67SPatrick Williams {};
255932cd67SPatrick Williams 
264c2d73ddSPatrick Williams using sequence_tag [[deprecated("Renamed to exec::sequence_sender_t")]] =
274c2d73ddSPatrick Williams     exec::sequence_sender_t;
284c2d73ddSPatrick Williams 
295932cd67SPatrick Williams namespace __sequence_sndr
305932cd67SPatrick Williams {
315932cd67SPatrick Williams using namespace stdexec;
325932cd67SPatrick Williams 
335932cd67SPatrick Williams template <class _Haystack>
345932cd67SPatrick Williams struct __mall_contained_in_impl
355932cd67SPatrick Williams {
365932cd67SPatrick Williams     template <class... _Needles>
375cee9157SPatrick Williams     using __f = __mand<__mapply<__mcontains<_Needles>, _Haystack>...>;
385932cd67SPatrick Williams };
395932cd67SPatrick Williams 
405932cd67SPatrick Williams template <class _Needles, class _Haystack>
415932cd67SPatrick Williams using __mall_contained_in =
425932cd67SPatrick Williams     __mapply<__mall_contained_in_impl<_Haystack>, _Needles>;
435932cd67SPatrick Williams 
445932cd67SPatrick Williams template <class _Needles, class _Haystack>
455cee9157SPatrick Williams concept __all_contained_in = __v<__mall_contained_in<_Needles, _Haystack>>;
465932cd67SPatrick Williams 
475932cd67SPatrick Williams // This concept checks if a given sender satisfies the requirements to be
485932cd67SPatrick Williams // returned from `set_next`.
495932cd67SPatrick Williams template <class _Sender, class _Env = empty_env>
505932cd67SPatrick Williams concept next_sender =        //
515932cd67SPatrick Williams     sender_in<_Sender, _Env> //
525932cd67SPatrick Williams     &&
535932cd67SPatrick Williams     __all_contained_in<completion_signatures_of_t<_Sender, _Env>,
545932cd67SPatrick Williams                        completion_signatures<set_value_t(), set_stopped_t()>>;
555932cd67SPatrick Williams 
565932cd67SPatrick Williams // This is a sequence-receiver CPO that is used to apply algorithms on an input
575932cd67SPatrick Williams // sender and it returns a next-sender. `set_next` is usually called in a
585932cd67SPatrick Williams // context where a sender will be connected to a receiver. Since calling
595932cd67SPatrick Williams // `set_next` usually involves constructing senders it is allowed to throw an
605cee9157SPatrick Williams // excpetion, which needs to be handled by a calling sequence-operation. The
615932cd67SPatrick Williams // returned object is a sender that can complete with `set_value_t()` or
625932cd67SPatrick Williams // `set_stopped_t()`.
635932cd67SPatrick Williams struct set_next_t
645932cd67SPatrick Williams {
655932cd67SPatrick Williams     template <receiver _Receiver, sender _Item>
665932cd67SPatrick Williams         requires tag_invocable<set_next_t, _Receiver&, _Item>
operator ()exec::__sequence_sndr::set_next_t675932cd67SPatrick Williams     auto operator()(_Receiver& __rcvr, _Item&& __item) const
685932cd67SPatrick Williams         noexcept(nothrow_tag_invocable<set_next_t, _Receiver&, _Item>)
695932cd67SPatrick Williams             -> tag_invoke_result_t<set_next_t, _Receiver&, _Item>
705932cd67SPatrick Williams     {
715932cd67SPatrick Williams         static_assert(
725932cd67SPatrick Williams             next_sender<tag_invoke_result_t<set_next_t, _Receiver&, _Item>>,
735932cd67SPatrick Williams             "The sender returned from set_next is required to complete with set_value_t() or "
745932cd67SPatrick Williams             "set_stopped_t()");
756e675883SPatrick Williams         return tag_invoke(*this, __rcvr, static_cast<_Item&&>(__item));
765932cd67SPatrick Williams     }
775932cd67SPatrick Williams };
785932cd67SPatrick Williams } // namespace __sequence_sndr
795932cd67SPatrick Williams 
805932cd67SPatrick Williams using __sequence_sndr::set_next_t;
815932cd67SPatrick Williams inline constexpr set_next_t set_next;
825932cd67SPatrick Williams 
835932cd67SPatrick Williams template <class _Receiver, class _Sender>
845932cd67SPatrick Williams using next_sender_of_t = decltype(exec::set_next(
855932cd67SPatrick Williams     stdexec::__declval<stdexec::__decay_t<_Receiver>&>(),
865932cd67SPatrick Williams     stdexec::__declval<_Sender>()));
875932cd67SPatrick Williams 
885932cd67SPatrick Williams namespace __sequence_sndr
895932cd67SPatrick Williams {
905932cd67SPatrick Williams 
915932cd67SPatrick Williams template <class _ReceiverId>
925932cd67SPatrick Williams struct __stopped_means_break
935932cd67SPatrick Williams {
945932cd67SPatrick Williams     struct __t
955932cd67SPatrick Williams     {
964c2d73ddSPatrick Williams         using receiver_concept = stdexec::receiver_t;
975932cd67SPatrick Williams         using __id = __stopped_means_break;
985932cd67SPatrick Williams         using _Receiver = stdexec::__t<_ReceiverId>;
995932cd67SPatrick Williams         using _Token = stop_token_of_t<env_of_t<_Receiver>>;
1006e675883SPatrick Williams         STDEXEC_ATTRIBUTE((no_unique_address))
1016e675883SPatrick Williams         _Receiver __rcvr_;
1025932cd67SPatrick Williams 
get_envexec::__sequence_sndr::__stopped_means_break::__t1035cee9157SPatrick Williams         auto get_env() const noexcept -> env_of_t<_Receiver>
1045932cd67SPatrick Williams         {
1055cee9157SPatrick Williams             return stdexec::get_env(__rcvr_);
1065932cd67SPatrick Williams         }
1075932cd67SPatrick Williams 
set_valueexec::__sequence_sndr::__stopped_means_break::__t1085cee9157SPatrick Williams         void set_value() noexcept
1095cee9157SPatrick Williams             requires __callable<set_value_t, _Receiver>
1105932cd67SPatrick Williams         {
1115cee9157SPatrick Williams             return stdexec::set_value(static_cast<_Receiver&&>(__rcvr_));
1125932cd67SPatrick Williams         }
1135932cd67SPatrick Williams 
set_stoppedexec::__sequence_sndr::__stopped_means_break::__t1145cee9157SPatrick Williams         void set_stopped() noexcept
1155cee9157SPatrick Williams             requires __callable<set_value_t, _Receiver> &&
1165932cd67SPatrick Williams                      (unstoppable_token<_Token> ||
1175cee9157SPatrick Williams                       __callable<set_stopped_t, _Receiver>)
1185932cd67SPatrick Williams         {
1195932cd67SPatrick Williams             if constexpr (unstoppable_token<_Token>)
1205932cd67SPatrick Williams             {
1215cee9157SPatrick Williams                 stdexec::set_value(static_cast<_Receiver&&>(__rcvr_));
1225932cd67SPatrick Williams             }
1235932cd67SPatrick Williams             else
1245932cd67SPatrick Williams             {
1255932cd67SPatrick Williams                 auto __token =
1265cee9157SPatrick Williams                     stdexec::get_stop_token(stdexec::get_env(__rcvr_));
1275932cd67SPatrick Williams                 if (__token.stop_requested())
1285932cd67SPatrick Williams                 {
1295cee9157SPatrick Williams                     stdexec::set_stopped(static_cast<_Receiver&&>(__rcvr_));
1305932cd67SPatrick Williams                 }
1315932cd67SPatrick Williams                 else
1325932cd67SPatrick Williams                 {
1335cee9157SPatrick Williams                     stdexec::set_value(static_cast<_Receiver&&>(__rcvr_));
1345932cd67SPatrick Williams                 }
1355932cd67SPatrick Williams             }
1365932cd67SPatrick Williams         }
1375932cd67SPatrick Williams     };
1385932cd67SPatrick Williams };
1395932cd67SPatrick Williams 
1405932cd67SPatrick Williams template <class _Rcvr>
1415932cd67SPatrick Williams using __stopped_means_break_t =
1425932cd67SPatrick Williams     __t<__stopped_means_break<__id<__decay_t<_Rcvr>>>>;
1435932cd67SPatrick Williams } // namespace __sequence_sndr
1445932cd67SPatrick Williams 
1455932cd67SPatrick Williams template <class _Sender>
1465932cd67SPatrick Williams concept __enable_sequence_sender =                    //
1474c2d73ddSPatrick Williams     requires { typename _Sender::sender_concept; } && //
1484c2d73ddSPatrick Williams     stdexec::same_as<typename _Sender::sender_concept, sequence_sender_t>;
1495932cd67SPatrick Williams 
1505932cd67SPatrick Williams template <class _Sender>
1515932cd67SPatrick Williams inline constexpr bool enable_sequence_sender =
1525932cd67SPatrick Williams     __enable_sequence_sender<_Sender>;
1535932cd67SPatrick Williams 
1545932cd67SPatrick Williams template <class... _Senders>
1555932cd67SPatrick Williams struct item_types
1565932cd67SPatrick Williams {};
1575932cd67SPatrick Williams 
1585932cd67SPatrick Williams template <class _Tp>
1595932cd67SPatrick Williams concept __has_item_typedef = requires { typename _Tp::item_types; };
1605932cd67SPatrick Williams 
1615932cd67SPatrick Williams /////////////////////////////////////////////////////////////////////////////
1625932cd67SPatrick Williams // [execution.sndtraits]
1635932cd67SPatrick Williams namespace __sequence_sndr
1645932cd67SPatrick Williams {
1655932cd67SPatrick Williams struct get_item_types_t;
1665932cd67SPatrick Williams template <class _Sender, class _Env>
1675932cd67SPatrick Williams using __tfx_sender =
1685932cd67SPatrick Williams     transform_sender_result_t<__late_domain_of_t<_Sender, _Env>, _Sender, _Env>;
1695932cd67SPatrick Williams 
1705932cd67SPatrick Williams template <class _Sender, class _Env>
1715932cd67SPatrick Williams concept __with_tag_invoke = //
1725932cd67SPatrick Williams     tag_invocable<get_item_types_t, __tfx_sender<_Sender, _Env>, _Env>;
1735932cd67SPatrick Williams template <class _Sender, class _Env>
1745932cd67SPatrick Williams using __member_alias_t = //
1755932cd67SPatrick Williams     typename __decay_t<__tfx_sender<_Sender, _Env>>::item_types;
1765932cd67SPatrick Williams 
1775932cd67SPatrick Williams template <class _Sender, class _Env>
1785932cd67SPatrick Williams concept __with_member_alias = __mvalid<__member_alias_t, _Sender, _Env>;
1795932cd67SPatrick Williams 
1805932cd67SPatrick Williams struct get_item_types_t
1815932cd67SPatrick Williams {
1825932cd67SPatrick Williams     template <class _Sender, class _Env>
__implexec::__sequence_sndr::get_item_types_t1835932cd67SPatrick Williams     static auto __impl()
1845932cd67SPatrick Williams     {
1855932cd67SPatrick Williams         static_assert(sizeof(_Sender),
1865932cd67SPatrick Williams                       "Incomplete type used with get_item_types");
1875932cd67SPatrick Williams         static_assert(sizeof(_Env), "Incomplete type used with get_item_types");
1885932cd67SPatrick Williams         using _TfxSender = __tfx_sender<_Sender, _Env>;
1895932cd67SPatrick Williams         if constexpr (__with_tag_invoke<_Sender, _Env>)
1905932cd67SPatrick Williams         {
1915932cd67SPatrick Williams             using _Result =
1925932cd67SPatrick Williams                 tag_invoke_result_t<get_item_types_t, _TfxSender, _Env>;
1936e675883SPatrick Williams             return static_cast<_Result (*)()>(nullptr);
1945932cd67SPatrick Williams         }
1955932cd67SPatrick Williams         else if constexpr (__with_member_alias<_TfxSender, _Env>)
1965932cd67SPatrick Williams         {
1975932cd67SPatrick Williams             using _Result = __member_alias_t<_TfxSender, _Env>;
1986e675883SPatrick Williams             return static_cast<_Result (*)()>(nullptr);
1995932cd67SPatrick Williams         }
2005932cd67SPatrick Williams         else if constexpr (sender_in<_TfxSender, _Env> &&
2015932cd67SPatrick Williams                            !enable_sequence_sender<
2025932cd67SPatrick Williams                                stdexec::__decay_t<_TfxSender>>)
2035932cd67SPatrick Williams         {
2045932cd67SPatrick Williams             using _Result = item_types<stdexec::__decay_t<_TfxSender>>;
2056e675883SPatrick Williams             return static_cast<_Result (*)()>(nullptr);
2065932cd67SPatrick Williams         }
2075932cd67SPatrick Williams         else if constexpr (__is_debug_env<_Env>)
2085932cd67SPatrick Williams         {
2095932cd67SPatrick Williams             using __tag_invoke::tag_invoke;
2105932cd67SPatrick Williams             // This ought to cause a hard error that indicates where the problem
2115932cd67SPatrick Williams             // is.
2125932cd67SPatrick Williams             using _Completions [[maybe_unused]] =
2135932cd67SPatrick Williams                 tag_invoke_result_t<get_item_types_t,
2145932cd67SPatrick Williams                                     __tfx_sender<_Sender, _Env>, _Env>;
2156e675883SPatrick Williams             return static_cast<__debug::__completion_signatures (*)()>(nullptr);
2165932cd67SPatrick Williams         }
2175932cd67SPatrick Williams         else
2185932cd67SPatrick Williams         {
2195932cd67SPatrick Williams             using _Result =
2205932cd67SPatrick Williams                 __mexception<_UNRECOGNIZED_SENDER_TYPE_<>,
2215932cd67SPatrick Williams                              _WITH_SENDER_<_Sender>, _WITH_ENVIRONMENT_<_Env>>;
2226e675883SPatrick Williams             return static_cast<_Result (*)()>(nullptr);
2235932cd67SPatrick Williams         }
2245932cd67SPatrick Williams     }
2255932cd67SPatrick Williams 
2261f7438aaSPatrick Williams     template <class _Sender, class _Env = empty_env>
operator ()exec::__sequence_sndr::get_item_types_t2275cee9157SPatrick Williams     constexpr auto operator()(_Sender&&, _Env&& = {}) const noexcept
2285932cd67SPatrick Williams         -> decltype(__impl<_Sender, _Env>()())
2295932cd67SPatrick Williams     {
2305932cd67SPatrick Williams         return {};
2315932cd67SPatrick Williams     }
2325932cd67SPatrick Williams };
2335932cd67SPatrick Williams } // namespace __sequence_sndr
2345932cd67SPatrick Williams 
2355932cd67SPatrick Williams using __sequence_sndr::get_item_types_t;
2365932cd67SPatrick Williams inline constexpr get_item_types_t get_item_types{};
2375932cd67SPatrick Williams 
2385cee9157SPatrick Williams template <class _Sender, class... _Env>
2395932cd67SPatrick Williams using item_types_of_t = decltype(get_item_types(stdexec::__declval<_Sender>(),
2405cee9157SPatrick Williams                                                 stdexec::__declval<_Env>()...));
2415932cd67SPatrick Williams 
2425cee9157SPatrick Williams template <class _Sender, class... _Env>
2435932cd67SPatrick Williams concept sequence_sender =                   //
2445cee9157SPatrick Williams     stdexec::sender_in<_Sender, _Env...> && //
2455932cd67SPatrick Williams     enable_sequence_sender<stdexec::__decay_t<_Sender>>;
2465932cd67SPatrick Williams 
2475cee9157SPatrick Williams template <class _Sender, class... _Env>
2485932cd67SPatrick Williams concept has_sequence_item_types =
2495cee9157SPatrick Williams     requires(_Sender&& __sndr, _Env&&... __env) {
2506e675883SPatrick Williams         get_item_types(static_cast<_Sender &&>(__sndr),
2515cee9157SPatrick Williams                        static_cast<_Env &&>(__env)...);
2525932cd67SPatrick Williams     };
2535932cd67SPatrick Williams 
2545cee9157SPatrick Williams template <class _Sender, class... _Env>
2555932cd67SPatrick Williams concept sequence_sender_in =                     //
2565cee9157SPatrick Williams     stdexec::sender_in<_Sender, _Env...> &&      //
2575cee9157SPatrick Williams     has_sequence_item_types<_Sender, _Env...> && //
2585cee9157SPatrick Williams     sequence_sender<_Sender, _Env...>;
2595932cd67SPatrick Williams 
2605932cd67SPatrick Williams template <class _Receiver>
2615932cd67SPatrick Williams struct _WITH_RECEIVER_
2625932cd67SPatrick Williams {};
2635932cd67SPatrick Williams 
2645932cd67SPatrick Williams template <class _Item>
2655932cd67SPatrick Williams struct _MISSING_SET_NEXT_OVERLOAD_FOR_ITEM_
2665932cd67SPatrick Williams {};
2675932cd67SPatrick Williams 
2685932cd67SPatrick Williams template <class _Receiver, class _Item>
2695cee9157SPatrick Williams auto __try_item(_Item*) //
2705932cd67SPatrick Williams     -> stdexec::__mexception<_MISSING_SET_NEXT_OVERLOAD_FOR_ITEM_<_Item>,
2715932cd67SPatrick Williams                              _WITH_RECEIVER_<_Receiver>>;
2725932cd67SPatrick Williams 
2735932cd67SPatrick Williams template <class _Receiver, class _Item>
2745932cd67SPatrick Williams     requires stdexec::__callable<set_next_t, _Receiver&, _Item>
2756e675883SPatrick Williams auto __try_item(_Item*) -> stdexec::__msuccess;
2765932cd67SPatrick Williams 
2775932cd67SPatrick Williams template <class _Receiver, class... _Items>
2785cee9157SPatrick Williams auto __try_items(exec::item_types<_Items...>*) //
2795932cd67SPatrick Williams     -> decltype((stdexec::__msuccess(), ...,
2806e675883SPatrick Williams                  exec::__try_item<_Receiver>(static_cast<_Items*>(nullptr))));
2815932cd67SPatrick Williams 
2825932cd67SPatrick Williams template <class _Receiver, class _Items>
2835932cd67SPatrick Williams concept __sequence_receiver_of =
2845932cd67SPatrick Williams     requires(_Items* __items) {
2855932cd67SPatrick Williams         {
2865932cd67SPatrick Williams             exec::__try_items<stdexec::__decay_t<_Receiver>>(__items)
2875932cd67SPatrick Williams         } -> stdexec::__ok;
2885932cd67SPatrick Williams     };
2895932cd67SPatrick Williams 
2905932cd67SPatrick Williams template <class _Receiver, class _SequenceItems>
2915932cd67SPatrick Williams concept sequence_receiver_of =      //
2925932cd67SPatrick Williams     stdexec::receiver<_Receiver> && //
2935932cd67SPatrick Williams     __sequence_receiver_of<_Receiver, _SequenceItems>;
2945932cd67SPatrick Williams 
2955932cd67SPatrick Williams template <class _Completions>
2965cee9157SPatrick Williams using __to_sequence_completions_t = //
2975cee9157SPatrick Williams     stdexec::__transform_completion_signatures<
2985cee9157SPatrick Williams         _Completions,
2995cee9157SPatrick Williams         stdexec::__mconst<
3005cee9157SPatrick Williams             stdexec::completion_signatures<stdexec::set_value_t()>>::__f,
3015cee9157SPatrick Williams         stdexec::__sigs::__default_set_error,
3025cee9157SPatrick Williams         stdexec::completion_signatures<stdexec::set_stopped_t()>,
3035cee9157SPatrick Williams         stdexec::__concat_completion_signatures>;
3045932cd67SPatrick Williams 
3055cee9157SPatrick Williams template <class _Sender, class... _Env>
3065cee9157SPatrick Williams using __item_completion_signatures = //
3075cee9157SPatrick Williams     stdexec::transform_completion_signatures<
3085cee9157SPatrick Williams         stdexec::__completion_signatures_of_t<_Sender, _Env...>,
3095932cd67SPatrick Williams         stdexec::completion_signatures<stdexec::set_value_t()>,
3105932cd67SPatrick Williams         stdexec::__mconst<stdexec::completion_signatures<>>::__f>;
3115932cd67SPatrick Williams 
3125cee9157SPatrick Williams template <class _Sequence, class... _Env>
3135cee9157SPatrick Williams using __sequence_completion_signatures = //
3145cee9157SPatrick Williams     stdexec::transform_completion_signatures<
3155cee9157SPatrick Williams         stdexec::__completion_signatures_of_t<_Sequence, _Env...>,
3165932cd67SPatrick Williams         stdexec::completion_signatures<stdexec::set_value_t()>,
3175cee9157SPatrick Williams         stdexec::__mconst<stdexec::completion_signatures<>>::__f>;
3185cee9157SPatrick Williams 
3195cee9157SPatrick Williams template <class _Sequence, class... _Env>
3205cee9157SPatrick Williams using __sequence_completion_signatures_of_t = //
3215932cd67SPatrick Williams     stdexec::__mapply<
3225cee9157SPatrick Williams         stdexec::__mtransform<
3235cee9157SPatrick Williams             stdexec::__mbind_back_q<__item_completion_signatures, _Env...>,
3245cee9157SPatrick Williams             stdexec::__mbind_back<
3255cee9157SPatrick Williams                 stdexec::__mtry_q<stdexec::__concat_completion_signatures>,
3265cee9157SPatrick Williams                 __sequence_completion_signatures<_Sequence, _Env...>>>,
3275cee9157SPatrick Williams         item_types_of_t<_Sequence, _Env...>>;
3285932cd67SPatrick Williams 
3295932cd67SPatrick Williams template <class _Receiver, class _Sender>
3305932cd67SPatrick Williams concept sequence_receiver_from =                                              //
3315932cd67SPatrick Williams     stdexec::receiver<_Receiver> &&                                           //
3325932cd67SPatrick Williams     stdexec::sender_in<_Sender, stdexec::env_of_t<_Receiver>> &&              //
3335932cd67SPatrick Williams     sequence_receiver_of<
3345932cd67SPatrick Williams         _Receiver, item_types_of_t<_Sender, stdexec::env_of_t<_Receiver>>> && //
3355932cd67SPatrick Williams     ((sequence_sender_in<_Sender, stdexec::env_of_t<_Receiver>> &&
3365932cd67SPatrick Williams       stdexec::receiver_of<_Receiver,
3375932cd67SPatrick Williams                            stdexec::completion_signatures_of_t<
3385932cd67SPatrick Williams                                _Sender, stdexec::env_of_t<_Receiver>>>) || //
3395932cd67SPatrick Williams      (!sequence_sender_in<_Sender, stdexec::env_of_t<_Receiver>> &&
3405932cd67SPatrick Williams       stdexec::__receiver_from<
3415932cd67SPatrick Williams           __sequence_sndr::__stopped_means_break_t<_Receiver>,
3425932cd67SPatrick Williams           next_sender_of_t<_Receiver, _Sender>>));
3435932cd67SPatrick Williams 
3445932cd67SPatrick Williams namespace __sequence_sndr
3455932cd67SPatrick Williams {
3465932cd67SPatrick Williams struct subscribe_t;
3475932cd67SPatrick Williams 
3485932cd67SPatrick Williams template <class _Env>
3495932cd67SPatrick Williams using __single_sender_completion_sigs =
3505932cd67SPatrick Williams     __if_c<unstoppable_token<stop_token_of_t<_Env>>,
3515932cd67SPatrick Williams            completion_signatures<set_value_t()>,
3525932cd67SPatrick Williams            completion_signatures<set_value_t(), set_stopped_t()>>;
3535932cd67SPatrick Williams 
3545932cd67SPatrick Williams template <class _Sender, class _Receiver>
3555cee9157SPatrick Williams concept __next_connectable =
3565932cd67SPatrick Williams     receiver<_Receiver> &&                                           //
3575932cd67SPatrick Williams     sender_in<_Sender, env_of_t<_Receiver>> &&                       //
3585932cd67SPatrick Williams     !sequence_sender_in<_Sender, env_of_t<_Receiver>> &&             //
3595932cd67SPatrick Williams     sequence_receiver_of<_Receiver,
3605932cd67SPatrick Williams                          item_types<stdexec::__decay_t<_Sender>>> && //
3615cee9157SPatrick Williams     sender_to<next_sender_of_t<_Receiver, _Sender>,
3625932cd67SPatrick Williams               __stopped_means_break_t<_Receiver>>;
3635932cd67SPatrick Williams 
3645932cd67SPatrick Williams template <class _Sender, class _Receiver>
3655932cd67SPatrick Williams concept __subscribeable_with_tag_invoke =
3665932cd67SPatrick Williams     receiver<_Receiver> &&                              //
3675932cd67SPatrick Williams     sequence_sender_in<_Sender, env_of_t<_Receiver>> && //
3685932cd67SPatrick Williams     sequence_receiver_from<_Receiver, _Sender> &&       //
3695932cd67SPatrick Williams     tag_invocable<subscribe_t, _Sender, _Receiver>;
3705932cd67SPatrick Williams 
3715932cd67SPatrick Williams struct subscribe_t
3725932cd67SPatrick Williams {
3735932cd67SPatrick Williams     template <class _Sender, class _Receiver>
3745932cd67SPatrick Williams     using __tfx_sndr = __tfx_sender<_Sender, env_of_t<_Receiver>>;
3755932cd67SPatrick Williams 
3765932cd67SPatrick Williams     template <class _Sender, class _Receiver>
__select_implexec::__sequence_sndr::subscribe_t3775932cd67SPatrick Williams     static constexpr auto __select_impl() noexcept
3785932cd67SPatrick Williams     {
3795932cd67SPatrick Williams         using _Domain = __late_domain_of_t<_Sender, env_of_t<_Receiver&>>;
3805932cd67SPatrick Williams         constexpr bool _NothrowTfxSender =
3815932cd67SPatrick Williams             __nothrow_callable<transform_sender_t, _Domain, _Sender,
3825932cd67SPatrick Williams                                env_of_t<_Receiver&>>;
3835932cd67SPatrick Williams         using _TfxSender = __tfx_sndr<_Sender, _Receiver>;
3845cee9157SPatrick Williams         if constexpr (__next_connectable<_TfxSender, _Receiver>)
3855932cd67SPatrick Williams         {
3865932cd67SPatrick Williams             using _Result =
3875cee9157SPatrick Williams                 connect_result_t<next_sender_of_t<_Receiver, _TfxSender>,
3885932cd67SPatrick Williams                                  __stopped_means_break_t<_Receiver>>;
3895932cd67SPatrick Williams             constexpr bool _Nothrow =
3905cee9157SPatrick Williams                 __nothrow_connectable<next_sender_of_t<_Receiver, _TfxSender>,
3915932cd67SPatrick Williams                                       __stopped_means_break_t<_Receiver>>;
3925932cd67SPatrick Williams             return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr);
3935932cd67SPatrick Williams         }
3945932cd67SPatrick Williams         else if constexpr (__subscribeable_with_tag_invoke<_TfxSender,
3955932cd67SPatrick Williams                                                            _Receiver>)
3965932cd67SPatrick Williams         {
3975932cd67SPatrick Williams             using _Result =
3985932cd67SPatrick Williams                 tag_invoke_result_t<subscribe_t, _TfxSender, _Receiver>;
3995932cd67SPatrick Williams             constexpr bool _Nothrow = //
4005932cd67SPatrick Williams                 _NothrowTfxSender &&
4015932cd67SPatrick Williams                 nothrow_tag_invocable<subscribe_t, _TfxSender, _Receiver>;
4025932cd67SPatrick Williams             return static_cast<_Result (*)() noexcept(_Nothrow)>(nullptr);
4035932cd67SPatrick Williams         }
4045932cd67SPatrick Williams         else
4055932cd67SPatrick Williams         {
4065932cd67SPatrick Williams             return static_cast<__debug::__debug_operation (*)() noexcept>(
4075932cd67SPatrick Williams                 nullptr);
4085932cd67SPatrick Williams         }
4095932cd67SPatrick Williams     }
4105932cd67SPatrick Williams 
4115932cd67SPatrick Williams     template <class _Sender, class _Receiver>
4125932cd67SPatrick Williams     using __select_impl_t = decltype(__select_impl<_Sender, _Receiver>());
4135932cd67SPatrick Williams 
4145932cd67SPatrick Williams     template <sender _Sender, receiver _Receiver>
4155cee9157SPatrick Williams         requires __next_connectable<__tfx_sndr<_Sender, _Receiver>,
4165cee9157SPatrick Williams                                     _Receiver> ||
417*36137e09SPatrick Williams                  __subscribeable_with_tag_invoke<__tfx_sndr<_Sender, _Receiver>,
418*36137e09SPatrick Williams                                                  _Receiver> ||
4195932cd67SPatrick Williams                  __is_debug_env<env_of_t<_Receiver>>
4205932cd67SPatrick Williams     auto operator()(_Sender&& __sndr, _Receiver&& __rcvr) const
4215932cd67SPatrick Williams         noexcept(__nothrow_callable<__select_impl_t<_Sender, _Receiver>>)
4225932cd67SPatrick Williams             -> __call_result_t<__select_impl_t<_Sender, _Receiver>>
4235932cd67SPatrick Williams     {
4245932cd67SPatrick Williams         using _TfxSender = __tfx_sndr<_Sender, _Receiver>;
4255932cd67SPatrick Williams         auto&& __env = get_env(__rcvr);
4265932cd67SPatrick Williams         auto __domain = __get_late_domain(__sndr, __env);
4275cee9157SPatrick Williams         if constexpr (__next_connectable<_TfxSender, _Receiver>)
4285932cd67SPatrick Williams         {
4295932cd67SPatrick Williams             static_assert(
4305cee9157SPatrick Williams                 operation_state<
4315cee9157SPatrick Williams                     connect_result_t<next_sender_of_t<_Receiver, _TfxSender>,
4325932cd67SPatrick Williams                                      __stopped_means_break_t<_Receiver>>>,
4335932cd67SPatrick Williams                 "stdexec::connect(sender, receiver) must return a type that "
4345932cd67SPatrick Williams                 "satisfies the operation_state concept");
4355932cd67SPatrick Williams             next_sender_of_t<_Receiver, _TfxSender> __next = set_next(
4366e675883SPatrick Williams                 __rcvr, transform_sender(
4376e675883SPatrick Williams                             __domain, static_cast<_Sender&&>(__sndr), __env));
4385cee9157SPatrick Williams             return stdexec::connect(
4395932cd67SPatrick Williams                 static_cast<next_sender_of_t<_Receiver, _TfxSender>&&>(__next),
4406e675883SPatrick Williams                 __stopped_means_break_t<_Receiver>{
4416e675883SPatrick Williams                     static_cast<_Receiver&&>(__rcvr)});
4425932cd67SPatrick Williams         }
4435932cd67SPatrick Williams         else if constexpr (__subscribeable_with_tag_invoke<_TfxSender,
4445932cd67SPatrick Williams                                                            _Receiver>)
4455932cd67SPatrick Williams         {
4465932cd67SPatrick Williams             static_assert(
4475932cd67SPatrick Williams                 operation_state<
4485932cd67SPatrick Williams                     tag_invoke_result_t<subscribe_t, _TfxSender, _Receiver>>,
4495932cd67SPatrick Williams                 "exec::subscribe(sender, receiver) must return a type that "
4505932cd67SPatrick Williams                 "satisfies the operation_state concept");
45106f265f6SPatrick Williams             return tag_invoke(
45206f265f6SPatrick Williams                 subscribe_t{},
45306f265f6SPatrick Williams                 transform_sender(__domain, static_cast<_Sender&&>(__sndr),
4546e675883SPatrick Williams                                  __env),
4556e675883SPatrick Williams                 static_cast<_Receiver&&>(__rcvr));
4565932cd67SPatrick Williams         }
4575932cd67SPatrick Williams         else if constexpr (enable_sequence_sender<
4585932cd67SPatrick Williams                                stdexec::__decay_t<_TfxSender>>)
4595932cd67SPatrick Williams         {
4605932cd67SPatrick Williams             // This should generate an instantiate backtrace that contains
4615932cd67SPatrick Williams             // useful debugging information.
4625932cd67SPatrick Williams             using __tag_invoke::tag_invoke;
4635932cd67SPatrick Williams             tag_invoke(*this,
4646e675883SPatrick Williams                        transform_sender(__domain,
4656e675883SPatrick Williams                                         static_cast<_Sender&&>(__sndr), __env),
4666e675883SPatrick Williams                        static_cast<_Receiver&&>(__rcvr));
4675932cd67SPatrick Williams         }
4685932cd67SPatrick Williams         else
4695932cd67SPatrick Williams         {
4705932cd67SPatrick Williams             next_sender_of_t<_Receiver, _TfxSender> __next = set_next(
4716e675883SPatrick Williams                 __rcvr, transform_sender(
4726e675883SPatrick Williams                             __domain, static_cast<_Sender&&>(__sndr), __env));
4735932cd67SPatrick Williams             return tag_invoke(
4745932cd67SPatrick Williams                 connect_t{},
4755932cd67SPatrick Williams                 static_cast<next_sender_of_t<_Receiver, _TfxSender>&&>(__next),
4766e675883SPatrick Williams                 __stopped_means_break_t<_Receiver>{
4776e675883SPatrick Williams                     static_cast<_Receiver&&>(__rcvr)});
4785932cd67SPatrick Williams         }
4795932cd67SPatrick Williams     }
4805932cd67SPatrick Williams 
queryexec::__sequence_sndr::subscribe_t4815cee9157SPatrick Williams     static constexpr auto query(stdexec::forwarding_query_t) noexcept -> bool
4825932cd67SPatrick Williams     {
4835932cd67SPatrick Williams         return false;
4845932cd67SPatrick Williams     }
4855932cd67SPatrick Williams };
4865932cd67SPatrick Williams 
4875932cd67SPatrick Williams template <class _Sender, class _Receiver>
4885932cd67SPatrick Williams using subscribe_result_t = __call_result_t<subscribe_t, _Sender, _Receiver>;
4895932cd67SPatrick Williams } // namespace __sequence_sndr
4905932cd67SPatrick Williams 
4915932cd67SPatrick Williams using __sequence_sndr::__single_sender_completion_sigs;
4925932cd67SPatrick Williams 
4935932cd67SPatrick Williams using __sequence_sndr::subscribe_t;
4945932cd67SPatrick Williams inline constexpr subscribe_t subscribe;
4955932cd67SPatrick Williams 
4965932cd67SPatrick Williams using __sequence_sndr::subscribe_result_t;
4975932cd67SPatrick Williams 
4985932cd67SPatrick Williams template <class _Sender, class _Receiver>
49906f265f6SPatrick Williams concept sequence_sender_to =
50006f265f6SPatrick Williams     sequence_receiver_from<_Receiver, _Sender> && //
5015932cd67SPatrick Williams     requires(_Sender&& __sndr, _Receiver&& __rcvr) {
5026e675883SPatrick Williams         subscribe(static_cast<_Sender &&>(__sndr),
5035cee9157SPatrick Williams                   static_cast<_Receiver &&>(__rcvr));
5045932cd67SPatrick Williams     };
5055932cd67SPatrick Williams 
5065932cd67SPatrick Williams template <class _Receiver>
5075932cd67SPatrick Williams concept __stoppable_receiver =                              //
5085932cd67SPatrick Williams     stdexec::__callable<stdexec::set_value_t, _Receiver> && //
5095932cd67SPatrick Williams     (stdexec::unstoppable_token<
5105932cd67SPatrick Williams          stdexec::stop_token_of_t<stdexec::env_of_t<_Receiver>>> ||
5115932cd67SPatrick Williams      stdexec::__callable<stdexec::set_stopped_t, _Receiver>);
5125932cd67SPatrick Williams 
5135932cd67SPatrick Williams template <class _Receiver>
5145932cd67SPatrick Williams     requires __stoppable_receiver<_Receiver>
__set_value_unless_stopped(_Receiver && __rcvr)5155932cd67SPatrick Williams void __set_value_unless_stopped(_Receiver&& __rcvr)
5165932cd67SPatrick Williams {
5175932cd67SPatrick Williams     using token_type = stdexec::stop_token_of_t<stdexec::env_of_t<_Receiver>>;
5185932cd67SPatrick Williams     if constexpr (stdexec::unstoppable_token<token_type>)
5195932cd67SPatrick Williams     {
5205932cd67SPatrick Williams         stdexec::set_value(static_cast<_Receiver&&>(__rcvr));
5215932cd67SPatrick Williams     }
5225932cd67SPatrick Williams     else
5235932cd67SPatrick Williams     {
5245932cd67SPatrick Williams         auto token = stdexec::get_stop_token(stdexec::get_env(__rcvr));
5255932cd67SPatrick Williams         if (!token.stop_requested())
5265932cd67SPatrick Williams         {
5275932cd67SPatrick Williams             stdexec::set_value(static_cast<_Receiver&&>(__rcvr));
5285932cd67SPatrick Williams         }
5295932cd67SPatrick Williams         else
5305932cd67SPatrick Williams         {
5315932cd67SPatrick Williams             stdexec::set_stopped(static_cast<_Receiver&&>(__rcvr));
5325932cd67SPatrick Williams         }
5335932cd67SPatrick Williams     }
5345932cd67SPatrick Williams }
5355932cd67SPatrick Williams } // namespace exec
536