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