@@ -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,128 @@ 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+ _InputSender _Input_sender;
5595+ // Clang complains about incomplete type, so for now no _OutputSenderState*
5596+ _WrappedReceiver_t* _Wrapped_receiver;
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+ _TRY_BEGIN
5609+ _STD construct_at(_Inner_receiver._Op_state3, _EXEC connect(_STD move(_Inner_receiver._Input_sender),
5610+ _STD move(*_Inner_receiver._Wrapped_receiver)));
5611+ _EXEC start(*_Inner_receiver._Op_state3);
5612+ _CATCH_ALL
5613+ _EXEC set_error(
5614+ _STD move(_Inner_receiver._Wrapped_receiver->_Input_receiver), _STD current_exception());
5615+ _CATCH_END
5616+ }
5617+ };
5618+
5619+ template <scheduler _Scheduler, sender _InputSender, receiver _InputReceiver>
5620+ struct _OutputSenderState {
5621+ using _WrappedReceiver_t = _WrappedReceiver<_Scheduler, _InputReceiver>;
5622+ using _InnerReceiver_t = _InnerReceiver<_Scheduler, _InputSender, _InputReceiver>;
5623+
5624+ _WrappedReceiver_t _Wrapped_receiver;
5625+ _InnerReceiver_t _Inner_receiver;
5626+ union {
5627+ char _Dummy = 0;
5628+ invoke_result_t<connect_t, invoke_result_t<schedule_t, _Scheduler>, _InnerReceiver_t> _Op_state2;
5629+ invoke_result_t<connect_t, _InputSender, _WrappedReceiver_t> _Op_state3;
5630+ };
5631+
5632+ explicit constexpr _OutputSenderState(_WrappedReceiver_t _Wrapped_receiver_, _InputSender _Input_sender)
5633+ : _Wrapped_receiver(_STD move(_Wrapped_receiver_)),
5634+ _Inner_receiver(
5635+ {_STD move(_Input_sender), _STD addressof(_Wrapped_receiver), _STD addressof(_Op_state3)}) {
5636+ _STD construct_at(_STD addressof(_Op_state2),
5637+ _EXEC connect(_EXEC schedule(_Wrapped_receiver._Sched), _STD move(_Inner_receiver)));
5638+ }
5639+
5640+ friend constexpr void tag_invoke(start_t, _OutputSenderState& _State) {
5641+ _EXEC start(_State._Op_state2);
5642+ }
5643+ };
5644+
5645+ template <scheduler _Scheduler, sender _InputSender>
5646+ struct _OutputSender {
5647+ _Scheduler _Sched;
5648+ _InputSender _Input_sender;
5649+
5650+ template <receiver _InputReceiver>
5651+ _NODISCARD friend constexpr auto
5652+ tag_invoke(connect_t, _OutputSender _Output_sender, _InputReceiver&& _Input_receiver) noexcept(
5653+ is_nothrow_move_constructible_v<_Scheduler>&& is_nothrow_move_constructible_v<_InputSender>&&
5654+ is_nothrow_constructible_v<remove_cvref_t<_InputReceiver>, _InputReceiver>) {
5655+ return _OutputSenderState<_Scheduler, _InputSender, _InputReceiver>{
5656+ _WrappedReceiver<_Scheduler, _InputReceiver>{
5657+ _STD move(_Output_sender._Sched), _STD forward<_InputReceiver>(_Input_receiver)},
5658+ _STD move(_Output_sender._Input_sender)};
5659+ }
5660+ };
5661+
5662+ struct _Cpo {
5663+ template <scheduler _Scheduler, sender _InputSender>
5664+ _NODISCARD constexpr auto operator()(_Scheduler&& _Sched, _InputSender&& _Input_sender) const noexcept {
5665+ if constexpr (_Tag_invocable_to_sender<_Cpo, _Scheduler, _InputSender>) {
5666+ return tag_invoke(
5667+ *this, _STD forward<_Scheduler>(_Sched), _STD forward<_InputSender>(_Input_sender));
5668+ } else {
5669+ return _OutputSender<_Scheduler, _InputSender>{
5670+ _STD forward<_Scheduler>(_Sched), _STD forward<_InputSender>(_Input_sender)};
5671+ }
5672+ }
5673+ };
5674+ } // namespace _On
5675+ using on_t = _On::_Cpo;
5676+
5677+ inline namespace _Cpos {
5678+ inline constexpr _On::_Cpo on;
5679+ }
5680+
5681+ template <scheduler _Scheduler, sender _InputSender>
5682+ struct sender_traits<_On::_OutputSender<_Scheduler, _InputSender>>
5683+ : decltype(_Get_sender_traits_derived<_InputSender>()) {};
55435684} // namespace execution
55445685#endif // __cpp_lib_executors
55455686_STD_END
0 commit comments