via.h 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. #pragma once
  2. /*
  3. * Copyright 2018-present Facebook, Inc.
  4. *
  5. * Licensed under the Apache License, Version 2.0 (the "License");
  6. * you may not use this file except in compliance with the License.
  7. * You may obtain a copy of the License at
  8. *
  9. * http://www.apache.org/licenses/LICENSE-2.0
  10. *
  11. * Unless required by applicable law or agreed to in writing, software
  12. * distributed under the License is distributed on an "AS IS" BASIS,
  13. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  14. * See the License for the specific language governing permissions and
  15. * limitations under the License.
  16. */
  17. #include <folly/experimental/pushmi/executor.h>
  18. #include <folly/experimental/pushmi/o/extension_operators.h>
  19. #include <folly/experimental/pushmi/piping.h>
  20. namespace pushmi {
  21. namespace detail {
  22. template <class Executor>
  23. struct via_fn_base {
  24. Executor exec;
  25. bool done;
  26. explicit via_fn_base(Executor ex) : exec(std::move(ex)), done(false) {}
  27. via_fn_base& via_fn_base_ref() {
  28. return *this;
  29. }
  30. };
  31. template <class Executor, class Out>
  32. struct via_fn_data : public Out, public via_fn_base<Executor> {
  33. via_fn_data(Out out, Executor exec)
  34. : Out(std::move(out)), via_fn_base<Executor>(std::move(exec)) {}
  35. using Out::done;
  36. using Out::error;
  37. using typename Out::properties;
  38. };
  39. template <class Out, class Executor>
  40. auto make_via_fn_data(Out out, Executor ex) -> via_fn_data<Executor, Out> {
  41. return {std::move(out), std::move(ex)};
  42. }
  43. struct via_fn {
  44. private:
  45. template <class Out>
  46. struct on_value_impl {
  47. template <class V>
  48. struct impl {
  49. V v_;
  50. Out out_;
  51. void operator()(any) {
  52. ::pushmi::set_value(out_, std::move(v_));
  53. }
  54. };
  55. template <class Data, class V>
  56. void operator()(Data& data, V&& v) const {
  57. if (data.via_fn_base_ref().done) {
  58. return;
  59. }
  60. ::pushmi::submit(
  61. data.via_fn_base_ref().exec,
  62. ::pushmi::make_receiver(impl<std::decay_t<V>>{
  63. (V &&) v, std::move(static_cast<Out&>(data))}));
  64. }
  65. };
  66. template <class Out>
  67. struct on_error_impl {
  68. template <class E>
  69. struct impl {
  70. E e_;
  71. Out out_;
  72. void operator()(any) noexcept {
  73. ::pushmi::set_error(out_, std::move(e_));
  74. }
  75. };
  76. template <class Data, class E>
  77. void operator()(Data& data, E e) const noexcept {
  78. if (data.via_fn_base_ref().done) {
  79. return;
  80. }
  81. data.via_fn_base_ref().done = true;
  82. ::pushmi::submit(
  83. data.via_fn_base_ref().exec,
  84. ::pushmi::make_receiver(
  85. impl<E>{std::move(e), std::move(static_cast<Out&>(data))}));
  86. }
  87. };
  88. template <class Out>
  89. struct on_done_impl {
  90. struct impl {
  91. Out out_;
  92. void operator()(any) {
  93. ::pushmi::set_done(out_);
  94. }
  95. };
  96. template <class Data>
  97. void operator()(Data& data) const {
  98. if (data.via_fn_base_ref().done) {
  99. return;
  100. }
  101. data.via_fn_base_ref().done = true;
  102. ::pushmi::submit(
  103. data.via_fn_base_ref().exec,
  104. ::pushmi::make_receiver(impl{std::move(static_cast<Out&>(data))}));
  105. }
  106. };
  107. template <class In, class ExecutorFactory>
  108. struct executor_impl {
  109. ExecutorFactory ef_;
  110. template <class Data>
  111. auto operator()(Data&) const {
  112. return ef_();
  113. }
  114. };
  115. template <class In, class ExecutorFactory>
  116. struct out_impl {
  117. ExecutorFactory ef_;
  118. PUSHMI_TEMPLATE(class Out)
  119. (requires Receiver<Out>)
  120. auto operator()(Out out) const {
  121. auto exec = ef_();
  122. return ::pushmi::detail::receiver_from_fn<In>()(
  123. make_via_fn_data(std::move(out), std::move(exec)),
  124. on_value_impl<Out>{},
  125. on_error_impl<Out>{},
  126. on_done_impl<Out>{});
  127. }
  128. };
  129. template <class ExecutorFactory>
  130. struct in_impl {
  131. ExecutorFactory ef_;
  132. PUSHMI_TEMPLATE(class In)
  133. (requires Sender<In>)
  134. auto operator()(In in) const {
  135. return ::pushmi::detail::sender_from(
  136. std::move(in),
  137. ::pushmi::detail::submit_transform_out<In>(
  138. out_impl<In, ExecutorFactory>{ef_}),
  139. ::pushmi::on_executor(executor_impl<In, ExecutorFactory>{ef_}));
  140. }
  141. };
  142. public:
  143. PUSHMI_TEMPLATE(class ExecutorFactory)
  144. (requires Invocable<ExecutorFactory&>&&
  145. Executor<invoke_result_t<ExecutorFactory&>>&&
  146. FifoSequence<invoke_result_t<ExecutorFactory&>>)
  147. auto operator()(ExecutorFactory ef) const {
  148. return in_impl<ExecutorFactory>{std::move(ef)};
  149. }
  150. };
  151. } // namespace detail
  152. namespace operators {
  153. PUSHMI_INLINE_VAR constexpr detail::via_fn via{};
  154. } // namespace operators
  155. } // namespace pushmi