@@ -5338,6 +5338,25 @@ namespace execution {
53385338 template <class _Sender>
53395339 struct sender_traits : decltype(_Get_sender_traits_base<_Sender>()) {};
53405340
5341+ template <class _Sender>
5342+ _NODISCARD _CONSTEVAL auto _Get_sender_traits_derived() noexcept {
5343+ if constexpr (_Has_sender_types<sender_traits<_Sender>>) {
5344+ return _Typed_sender<sender_traits<_Sender>>{};
5345+ } else if constexpr (derived_from<_Sender, sender_base>) {
5346+ return _Sender_traits_base{};
5347+ #if 0 // TRANSITION: coroutine support
5348+ } else if constexpr (_Is_awaitable<_Sender>) {
5349+ if constexpr (is_void_v<_Await_result_t<_Sender>>) {
5350+ return _Void_sender<false>{};
5351+ } else {
5352+ return _Sender_of<false, _Await_result_t<_Sender>>{};
5353+ }
5354+ #endif // 0 TRANSITION: coroutine support
5355+ } else {
5356+ return _No_sender_traits{};
5357+ }
5358+ }
5359+
53415360 template <class _Sender>
53425361 concept sender = move_constructible<remove_cvref_t<_Sender>> && !requires {
53435362 typename sender_traits<remove_cvref_t<_Sender>>::_Unspecialized;
@@ -5540,6 +5559,127 @@ namespace execution {
55405559 _NODISCARD constexpr _Just_done_sender just_done() noexcept {
55415560 return {};
55425561 };
5562+
5563+ template <class _Tag, class... _Args>
5564+ concept _Tag_invocable_to_sender = tag_invocable<_Tag, _Args...> && sender<tag_invoke_result_t<_Tag, _Args...>>;
5565+
5566+ namespace _On {
5567+ template <scheduler _Scheduler, receiver _InputReceiver>
5568+ struct _WrappedReceiver {
5569+ _Scheduler _Sched;
5570+ _InputReceiver _Input_receiver;
5571+
5572+ friend constexpr void tag_invoke(set_done_t, _WrappedReceiver _Wrapped_receiver) noexcept {
5573+ _EXEC set_done(_STD move(_Wrapped_receiver._Input_receiver));
5574+ }
5575+ template <class _Error>
5576+ friend constexpr void tag_invoke(set_error_t, _WrappedReceiver _Wrapped_receiver, _Error&& _Err) noexcept {
5577+ _EXEC set_error(_STD move(_Wrapped_receiver._Input_receiver), _STD forward<_Error>(_Err));
5578+ }
5579+ template <class... _ArgTys>
5580+ friend constexpr void tag_invoke(
5581+ set_value_t, _WrappedReceiver _Wrapped_receiver, _ArgTys&&... _Args) noexcept {
5582+ _EXEC set_value(_STD move(_Wrapped_receiver._Input_receiver), _STD forward<_ArgTys>(_Args)...);
5583+ }
5584+ _NODISCARD friend constexpr auto tag_invoke(
5585+ get_scheduler_t, const _WrappedReceiver& _Wrapped_receiver) noexcept {
5586+ return _Wrapped_receiver._Sched;
5587+ }
5588+ };
5589+
5590+ template <scheduler _Scheduler, sender _InputSender, receiver _InputReceiver>
5591+ struct _InnerReceiver {
5592+ using _WrappedReceiver_t = _WrappedReceiver<_Scheduler, _InputReceiver>;
5593+
5594+ // Clang complains about incomplete type, so for now no _OutputSenderState*
5595+ _WrappedReceiver_t* _Wrapped_receiver;
5596+ _InputSender* _Input_sender;
5597+ invoke_result_t<connect_t, _InputSender, _WrappedReceiver_t>* _Op_state3;
5598+
5599+ friend constexpr void tag_invoke(set_done_t, _InnerReceiver _Inner_receiver) noexcept {
5600+ _EXEC set_done(_STD move(_Inner_receiver._Wrapped_receiver->_Input_receiver));
5601+ }
5602+ template <class _Error>
5603+ friend constexpr void tag_invoke(set_error_t, _InnerReceiver _Inner_receiver, _Error&& _Err) noexcept {
5604+ _EXEC set_error(
5605+ _STD move(_Inner_receiver._Wrapped_receiver->_Input_receiver), _STD forward<_Error>(_Err));
5606+ }
5607+ friend constexpr void tag_invoke(set_value_t, _InnerReceiver _Inner_receiver) noexcept {
5608+ auto* _Wrapped_receiver = _Inner_receiver._Wrapped_receiver;
5609+ _TRY_BEGIN
5610+ // *this is stored inside of `_Op_state2` so the call below will invalidate it. store the members
5611+ auto* _Input_sender = _Inner_receiver._Input_sender;
5612+ auto* _Op_state3 = _Inner_receiver._Op_state3;
5613+ _STD construct_at(_Op_state3, _EXEC connect(_STD move(*_Input_sender), _STD move(*_Wrapped_receiver)));
5614+ _EXEC start(*_Op_state3);
5615+ _CATCH_ALL
5616+ _EXEC set_error(_STD move(_Wrapped_receiver->_Input_receiver), _STD current_exception());
5617+ _CATCH_END
5618+ }
5619+ };
5620+
5621+ template <scheduler _Scheduler, sender _InputSender, receiver _InputReceiver>
5622+ struct _OutputSenderState {
5623+ using _WrappedReceiver_t = _WrappedReceiver<_Scheduler, _InputReceiver>;
5624+ using _InnerReceiver_t = _InnerReceiver<_Scheduler, _InputSender, _InputReceiver>;
5625+
5626+ _WrappedReceiver_t _Wrapped_receiver;
5627+ _InputSender _Input_sender;
5628+ union {
5629+ invoke_result_t<connect_t, invoke_result_t<schedule_t, _Scheduler>, _InnerReceiver_t> _Op_state2;
5630+ invoke_result_t<connect_t, _InputSender, _WrappedReceiver_t> _Op_state3;
5631+ };
5632+
5633+ explicit constexpr _OutputSenderState(_WrappedReceiver_t _Wrapped_receiver_, _InputSender _Input_sender_)
5634+ : _Wrapped_receiver(_STD move(_Wrapped_receiver_)), _Input_sender(_STD move(_Input_sender_)),
5635+ _Op_state2(_EXEC connect(_EXEC schedule(_Wrapped_receiver._Sched),
5636+ _InnerReceiver_t{_STD addressof(_Wrapped_receiver), _STD addressof(_Input_sender),
5637+ _STD addressof(_Op_state3)})) {}
5638+
5639+ friend constexpr void tag_invoke(start_t, _OutputSenderState& _State) {
5640+ _EXEC start(_State._Op_state2);
5641+ }
5642+ };
5643+
5644+ template <scheduler _Scheduler, sender _InputSender>
5645+ struct _OutputSender {
5646+ _Scheduler _Sched;
5647+ _InputSender _Input_sender;
5648+
5649+ template <receiver _InputReceiver>
5650+ _NODISCARD friend constexpr auto
5651+ tag_invoke(connect_t, _OutputSender _Output_sender, _InputReceiver&& _Input_receiver) noexcept(
5652+ is_nothrow_move_constructible_v<_Scheduler>&& is_nothrow_move_constructible_v<_InputSender>&&
5653+ is_nothrow_constructible_v<remove_cvref_t<_InputReceiver>, _InputReceiver>) {
5654+ return _OutputSenderState<_Scheduler, _InputSender, _InputReceiver>{
5655+ _WrappedReceiver<_Scheduler, _InputReceiver>{
5656+ _STD move(_Output_sender._Sched), _STD forward<_InputReceiver>(_Input_receiver)},
5657+ _STD move(_Output_sender._Input_sender)};
5658+ }
5659+ };
5660+
5661+ struct _Cpo {
5662+ template <scheduler _Scheduler, sender _InputSender>
5663+ _NODISCARD constexpr auto operator()(_Scheduler&& _Sched, _InputSender&& _Input_sender) const noexcept {
5664+ if constexpr (_Tag_invocable_to_sender<_Cpo, _Scheduler, _InputSender>) {
5665+ return tag_invoke(
5666+ *this, _STD forward<_Scheduler>(_Sched), _STD forward<_InputSender>(_Input_sender));
5667+ } else {
5668+ return _OutputSender<_Scheduler, _InputSender>{
5669+ _STD forward<_Scheduler>(_Sched), _STD forward<_InputSender>(_Input_sender)};
5670+ }
5671+ }
5672+ };
5673+ } // namespace _On
5674+ using on_t = _On::_Cpo;
5675+
5676+ inline namespace _Cpos {
5677+ inline constexpr _On::_Cpo on;
5678+ }
5679+
5680+ template <scheduler _Scheduler, sender _InputSender>
5681+ struct sender_traits<_On::_OutputSender<_Scheduler, _InputSender>>
5682+ : decltype(_Get_sender_traits_derived<_InputSender>()) {};
55435683} // namespace execution
55445684#endif // __cpp_lib_executors
55455685_STD_END
0 commit comments