15cee9157SPatrick Williams /*
25cee9157SPatrick Williams * Copyright (c) 2022-2024 NVIDIA Corporation
35cee9157SPatrick Williams *
45cee9157SPatrick Williams * Licensed under the Apache License Version 2.0 with LLVM Exceptions
55cee9157SPatrick Williams * (the "License"); you may not use this file except in compliance with
65cee9157SPatrick Williams * the License. You may obtain a copy of the License at
75cee9157SPatrick Williams *
85cee9157SPatrick Williams * https://llvm.org/LICENSE.txt
95cee9157SPatrick Williams *
105cee9157SPatrick Williams * Unless required by applicable law or agreed to in writing, software
115cee9157SPatrick Williams * distributed under the License is distributed on an "AS IS" BASIS,
125cee9157SPatrick Williams * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
135cee9157SPatrick Williams * See the License for the specific language governing permissions and
145cee9157SPatrick Williams * limitations under the License.
155cee9157SPatrick Williams */
165cee9157SPatrick Williams #pragma once
175cee9157SPatrick Williams
185cee9157SPatrick Williams #include "../functional.hpp"
195cee9157SPatrick Williams #include "__concepts.hpp"
205cee9157SPatrick Williams #include "__diagnostics.hpp"
215cee9157SPatrick Williams #include "__env.hpp"
225cee9157SPatrick Williams #include "__execution_fwd.hpp"
235cee9157SPatrick Williams #include "__tag_invoke.hpp"
245cee9157SPatrick Williams
255cee9157SPatrick Williams #include <exception>
265cee9157SPatrick Williams
275cee9157SPatrick Williams namespace stdexec
285cee9157SPatrick Williams {
295cee9157SPatrick Williams /////////////////////////////////////////////////////////////////////////////
305cee9157SPatrick Williams // [execution.receivers]
315cee9157SPatrick Williams namespace __rcvrs
325cee9157SPatrick Williams {
335cee9157SPatrick Williams struct set_value_t
345cee9157SPatrick Williams {
355cee9157SPatrick Williams template <class _Fn, class... _Args>
365cee9157SPatrick Williams using __f = __minvoke<_Fn, _Args...>;
375cee9157SPatrick Williams
385cee9157SPatrick Williams template <__same_as<set_value_t> _Self, class _Receiver, class... _As>
395cee9157SPatrick Williams STDEXEC_ATTRIBUTE((host, device, always_inline))
tag_invoke(_Self,_Receiver && __rcvr,_As &&...__as)405cee9157SPatrick Williams friend auto tag_invoke(_Self, _Receiver&& __rcvr, _As&&... __as) noexcept
415cee9157SPatrick Williams -> decltype(static_cast<_Receiver&&>(__rcvr).set_value(
425cee9157SPatrick Williams static_cast<_As&&>(__as)...))
435cee9157SPatrick Williams {
445cee9157SPatrick Williams static_assert(noexcept(static_cast<_Receiver&&>(__rcvr).set_value(
455cee9157SPatrick Williams static_cast<_As&&>(__as)...)),
465cee9157SPatrick Williams "set_value member functions must be noexcept");
475cee9157SPatrick Williams static_assert(
485cee9157SPatrick Williams __same_as<decltype(static_cast<_Receiver&&>(__rcvr).set_value(
495cee9157SPatrick Williams static_cast<_As&&>(__as)...)),
505cee9157SPatrick Williams void>,
515cee9157SPatrick Williams "set_value member functions must return void");
525cee9157SPatrick Williams static_cast<_Receiver&&>(__rcvr).set_value(static_cast<_As&&>(__as)...);
535cee9157SPatrick Williams }
545cee9157SPatrick Williams
555cee9157SPatrick Williams template <class _Receiver, class... _As>
565cee9157SPatrick Williams requires tag_invocable<set_value_t, _Receiver, _As...>
57*06f265f6SPatrick Williams STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__rcvrs::set_value_t58*06f265f6SPatrick Williams void operator()(_Receiver&& __rcvr, _As&&... __as) const noexcept
595cee9157SPatrick Williams {
605cee9157SPatrick Williams static_assert(nothrow_tag_invocable<set_value_t, _Receiver, _As...>);
615cee9157SPatrick Williams (void)tag_invoke(stdexec::set_value_t{},
625cee9157SPatrick Williams static_cast<_Receiver&&>(__rcvr),
635cee9157SPatrick Williams static_cast<_As&&>(__as)...);
645cee9157SPatrick Williams }
655cee9157SPatrick Williams };
665cee9157SPatrick Williams
675cee9157SPatrick Williams struct set_error_t
685cee9157SPatrick Williams {
695cee9157SPatrick Williams template <class _Fn, class... _Args>
705cee9157SPatrick Williams requires(sizeof...(_Args) == 1)
715cee9157SPatrick Williams using __f = __minvoke<_Fn, _Args...>;
725cee9157SPatrick Williams
735cee9157SPatrick Williams template <__same_as<set_error_t> _Self, class _Receiver, class _Error>
745cee9157SPatrick Williams STDEXEC_ATTRIBUTE((host, device, always_inline))
tag_invoke(_Self,_Receiver && __rcvr,_Error && __err)755cee9157SPatrick Williams friend auto tag_invoke(_Self, _Receiver&& __rcvr, _Error&& __err) noexcept
765cee9157SPatrick Williams -> decltype(static_cast<_Receiver&&>(__rcvr).set_error(
775cee9157SPatrick Williams static_cast<_Error&&>(__err)))
785cee9157SPatrick Williams {
795cee9157SPatrick Williams static_assert(noexcept(static_cast<_Receiver&&>(__rcvr).set_error(
805cee9157SPatrick Williams static_cast<_Error&&>(__err))),
815cee9157SPatrick Williams "set_error member functions must be noexcept");
825cee9157SPatrick Williams static_assert(
835cee9157SPatrick Williams __same_as<decltype(static_cast<_Receiver&&>(__rcvr).set_error(
845cee9157SPatrick Williams static_cast<_Error&&>(__err))),
855cee9157SPatrick Williams void>,
865cee9157SPatrick Williams "set_error member functions must return void");
875cee9157SPatrick Williams static_cast<_Receiver&&>(__rcvr).set_error(
885cee9157SPatrick Williams static_cast<_Error&&>(__err));
895cee9157SPatrick Williams }
905cee9157SPatrick Williams
915cee9157SPatrick Williams template <class _Receiver, class _Error>
925cee9157SPatrick Williams requires tag_invocable<set_error_t, _Receiver, _Error>
93*06f265f6SPatrick Williams STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__rcvrs::set_error_t94*06f265f6SPatrick Williams void operator()(_Receiver&& __rcvr, _Error&& __err) const noexcept
955cee9157SPatrick Williams {
965cee9157SPatrick Williams static_assert(nothrow_tag_invocable<set_error_t, _Receiver, _Error>);
975cee9157SPatrick Williams (void)tag_invoke(stdexec::set_error_t{},
985cee9157SPatrick Williams static_cast<_Receiver&&>(__rcvr),
995cee9157SPatrick Williams static_cast<_Error&&>(__err));
1005cee9157SPatrick Williams }
1015cee9157SPatrick Williams };
1025cee9157SPatrick Williams
1035cee9157SPatrick Williams struct set_stopped_t
1045cee9157SPatrick Williams {
1055cee9157SPatrick Williams template <class _Fn, class... _Args>
1065cee9157SPatrick Williams requires(sizeof...(_Args) == 0)
1075cee9157SPatrick Williams using __f = __minvoke<_Fn, _Args...>;
1085cee9157SPatrick Williams
1095cee9157SPatrick Williams template <__same_as<set_stopped_t> _Self, class _Receiver>
1105cee9157SPatrick Williams STDEXEC_ATTRIBUTE((host, device, always_inline))
tag_invoke(_Self,_Receiver && __rcvr)1115cee9157SPatrick Williams friend auto tag_invoke(_Self, _Receiver&& __rcvr) noexcept
1125cee9157SPatrick Williams -> decltype(static_cast<_Receiver&&>(__rcvr).set_stopped())
1135cee9157SPatrick Williams {
1145cee9157SPatrick Williams static_assert(noexcept(static_cast<_Receiver&&>(__rcvr).set_stopped()),
1155cee9157SPatrick Williams "set_stopped member functions must be noexcept");
1165cee9157SPatrick Williams static_assert(
1175cee9157SPatrick Williams __same_as<decltype(static_cast<_Receiver&&>(__rcvr).set_stopped()),
1185cee9157SPatrick Williams void>,
1195cee9157SPatrick Williams "set_stopped member functions must return void");
1205cee9157SPatrick Williams static_cast<_Receiver&&>(__rcvr).set_stopped();
1215cee9157SPatrick Williams }
1225cee9157SPatrick Williams
1235cee9157SPatrick Williams template <class _Receiver>
1245cee9157SPatrick Williams requires tag_invocable<set_stopped_t, _Receiver>
125*06f265f6SPatrick Williams STDEXEC_ATTRIBUTE((host, device, always_inline))
operator ()stdexec::__rcvrs::set_stopped_t126*06f265f6SPatrick Williams void operator()(_Receiver&& __rcvr) const noexcept
1275cee9157SPatrick Williams {
1285cee9157SPatrick Williams static_assert(nothrow_tag_invocable<set_stopped_t, _Receiver>);
1295cee9157SPatrick Williams (void)tag_invoke(stdexec::set_stopped_t{},
1305cee9157SPatrick Williams static_cast<_Receiver&&>(__rcvr));
1315cee9157SPatrick Williams }
1325cee9157SPatrick Williams };
1335cee9157SPatrick Williams } // namespace __rcvrs
1345cee9157SPatrick Williams
1355cee9157SPatrick Williams using __rcvrs::set_error_t;
1365cee9157SPatrick Williams using __rcvrs::set_stopped_t;
1375cee9157SPatrick Williams using __rcvrs::set_value_t;
1385cee9157SPatrick Williams inline constexpr set_value_t set_value{};
1395cee9157SPatrick Williams inline constexpr set_error_t set_error{};
1405cee9157SPatrick Williams inline constexpr set_stopped_t set_stopped{};
1415cee9157SPatrick Williams
1425cee9157SPatrick Williams struct receiver_t
1435cee9157SPatrick Williams {
1445cee9157SPatrick Williams using receiver_concept = receiver_t; // NOT TO SPEC
1455cee9157SPatrick Williams };
1465cee9157SPatrick Williams
1475cee9157SPatrick Williams namespace __detail
1485cee9157SPatrick Williams {
1495cee9157SPatrick Williams template <class _Receiver>
1505cee9157SPatrick Williams concept __enable_receiver = //
1515cee9157SPatrick Williams (STDEXEC_NVHPC(requires { typename _Receiver::receiver_concept; }&&) //
1525cee9157SPatrick Williams derived_from<typename _Receiver::receiver_concept, receiver_t>) ||
1535cee9157SPatrick Williams requires { typename _Receiver::is_receiver; } // back-compat, NOT TO SPEC
1545cee9157SPatrick Williams || STDEXEC_IS_BASE_OF(receiver_t,
1555cee9157SPatrick Williams _Receiver); // NOT TO SPEC, for receiver_adaptor
1565cee9157SPatrick Williams } // namespace __detail
1575cee9157SPatrick Williams
1585cee9157SPatrick Williams template <class _Receiver>
1595cee9157SPatrick Williams inline constexpr bool enable_receiver =
1605cee9157SPatrick Williams __detail::__enable_receiver<_Receiver>; // NOT TO SPEC
1615cee9157SPatrick Williams
1625cee9157SPatrick Williams template <class _Receiver>
1635cee9157SPatrick Williams concept receiver = //
1645cee9157SPatrick Williams enable_receiver<__decay_t<_Receiver>> //
1655cee9157SPatrick Williams && environment_provider<__cref_t<_Receiver>> //
1665cee9157SPatrick Williams && move_constructible<__decay_t<_Receiver>> //
1675cee9157SPatrick Williams && constructible_from<__decay_t<_Receiver>, _Receiver>;
1685cee9157SPatrick Williams
1695cee9157SPatrick Williams namespace __detail
1705cee9157SPatrick Williams {
1715cee9157SPatrick Williams template <class _Receiver, class _Tag, class... _Args>
1725cee9157SPatrick Williams auto __try_completion(_Tag (*)(_Args...))
1735cee9157SPatrick Williams -> __mexception<_MISSING_COMPLETION_SIGNAL_<_Tag(_Args...)>,
1745cee9157SPatrick Williams _WITH_RECEIVER_<_Receiver>>;
1755cee9157SPatrick Williams
1765cee9157SPatrick Williams template <class _Receiver, class _Tag, class... _Args>
1775cee9157SPatrick Williams requires nothrow_tag_invocable<_Tag, _Receiver, _Args...>
1785cee9157SPatrick Williams auto __try_completion(_Tag (*)(_Args...)) -> __msuccess;
1795cee9157SPatrick Williams
1805cee9157SPatrick Williams template <class _Receiver, class... _Sigs>
1815cee9157SPatrick Williams auto __try_completions(completion_signatures<_Sigs...>*) //
1825cee9157SPatrick Williams -> decltype((
1835cee9157SPatrick Williams __msuccess(), ...,
1845cee9157SPatrick Williams __detail::__try_completion<_Receiver>(static_cast<_Sigs*>(nullptr))));
1855cee9157SPatrick Williams } // namespace __detail
1865cee9157SPatrick Williams
1875cee9157SPatrick Williams template <class _Receiver, class _Completions>
1885cee9157SPatrick Williams concept receiver_of = //
1895cee9157SPatrick Williams receiver<_Receiver> && //
1905cee9157SPatrick Williams requires(_Completions* __completions) {
1915cee9157SPatrick Williams {
1925cee9157SPatrick Williams __detail::__try_completions<__decay_t<_Receiver>>(__completions)
1935cee9157SPatrick Williams } -> __ok;
1945cee9157SPatrick Williams };
1955cee9157SPatrick Williams
1965cee9157SPatrick Williams template <class _Receiver, class _Sender>
1975cee9157SPatrick Williams concept __receiver_from =
1985cee9157SPatrick Williams receiver_of<_Receiver,
1995cee9157SPatrick Williams __completion_signatures_of_t<_Sender, env_of_t<_Receiver>>>;
2005cee9157SPatrick Williams
2015cee9157SPatrick Williams /// A utility for calling set_value with the result of a function invocation:
2025cee9157SPatrick Williams template <bool _CanThrow = false, class _Receiver, class _Fun, class... _As>
__set_value_invoke(_Receiver && __rcvr,_Fun && __fun,_As &&...__as)2035cee9157SPatrick Williams void __set_value_invoke(_Receiver&& __rcvr, _Fun&& __fun,
2045cee9157SPatrick Williams _As&&... __as) noexcept(!_CanThrow)
2055cee9157SPatrick Williams {
2065cee9157SPatrick Williams if constexpr (_CanThrow || __nothrow_invocable<_Fun, _As...>)
2075cee9157SPatrick Williams {
2085cee9157SPatrick Williams if constexpr (same_as<void, __invoke_result_t<_Fun, _As...>>)
2095cee9157SPatrick Williams {
2105cee9157SPatrick Williams __invoke(static_cast<_Fun&&>(__fun), static_cast<_As&&>(__as)...);
2115cee9157SPatrick Williams stdexec::set_value(static_cast<_Receiver&&>(__rcvr));
2125cee9157SPatrick Williams }
2135cee9157SPatrick Williams else
2145cee9157SPatrick Williams {
2155cee9157SPatrick Williams set_value(static_cast<_Receiver&&>(__rcvr),
2165cee9157SPatrick Williams __invoke(static_cast<_Fun&&>(__fun),
2175cee9157SPatrick Williams static_cast<_As&&>(__as)...));
2185cee9157SPatrick Williams }
2195cee9157SPatrick Williams }
2205cee9157SPatrick Williams else
2215cee9157SPatrick Williams {
2225cee9157SPatrick Williams try
2235cee9157SPatrick Williams {
2245cee9157SPatrick Williams stdexec::__set_value_invoke<true>(static_cast<_Receiver&&>(__rcvr),
2255cee9157SPatrick Williams static_cast<_Fun&&>(__fun),
2265cee9157SPatrick Williams static_cast<_As&&>(__as)...);
2275cee9157SPatrick Williams }
2285cee9157SPatrick Williams catch (...)
2295cee9157SPatrick Williams {
2305cee9157SPatrick Williams stdexec::set_error(static_cast<_Receiver&&>(__rcvr),
2315cee9157SPatrick Williams std::current_exception());
2325cee9157SPatrick Williams }
2335cee9157SPatrick Williams }
2345cee9157SPatrick Williams }
2355cee9157SPatrick Williams } // namespace stdexec
236