tap.h 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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/o/extension_operators.h>
  18. #include <cassert>
  19. namespace pushmi {
  20. namespace detail {
  21. PUSHMI_TEMPLATE(class SideEffects, class Out)
  22. (requires Receiver<SideEffects>&& Receiver<Out>)
  23. struct tap_ {
  24. SideEffects sideEffects;
  25. Out out;
  26. // side effect has no effect on the properties.
  27. using properties = properties_t<Out>;
  28. PUSHMI_TEMPLATE(class... VN)
  29. (requires ReceiveValue<SideEffects, const std::remove_reference_t<VN>...>&&
  30. ReceiveValue<
  31. Out,
  32. std::remove_reference_t<VN>...>)
  33. void value(VN&&... vn) {
  34. ::pushmi::set_value(sideEffects, as_const(vn)...);
  35. ::pushmi::set_value(out, (VN &&) vn...);
  36. }
  37. PUSHMI_TEMPLATE(class E)
  38. (requires ReceiveError<SideEffects, const E>&&
  39. ReceiveError<Out, E>)
  40. void error(E e) noexcept {
  41. ::pushmi::set_error(sideEffects, as_const(e));
  42. ::pushmi::set_error(out, std::move(e));
  43. }
  44. void done() {
  45. ::pushmi::set_done(sideEffects);
  46. ::pushmi::set_done(out);
  47. }
  48. PUSHMI_TEMPLATE(class Up, class UUp = std::remove_reference_t<Up>)
  49. (requires FlowReceiver<SideEffects>&& FlowReceiver<Out>)
  50. void starting(
  51. Up&& up) {
  52. // up is not made const because sideEffects is allowed to call methods on up
  53. ::pushmi::set_starting(sideEffects, up);
  54. ::pushmi::set_starting(out, (Up &&) up);
  55. }
  56. };
  57. PUSHMI_INLINE_VAR constexpr struct make_tap_fn {
  58. PUSHMI_TEMPLATE(class SideEffects, class Out)
  59. (requires Receiver<SideEffects>&& Receiver<Out>&&
  60. Receiver<tap_<SideEffects, Out>>)
  61. auto operator()(SideEffects se, Out out) const {
  62. return tap_<SideEffects, Out>{std::move(se), std::move(out)};
  63. }
  64. } const make_tap{};
  65. struct tap_fn {
  66. private:
  67. PUSHMI_TEMPLATE(class In, class SideEffects)
  68. (requires Sender<In>&& Receiver<SideEffects>)
  69. static auto impl(
  70. In in,
  71. SideEffects sideEffects) {
  72. return ::pushmi::detail::sender_from(
  73. std::move(in),
  74. ::pushmi::detail::submit_transform_out<In>(
  75. out_impl<In, SideEffects>{std::move(sideEffects)}));
  76. }
  77. template <class... AN>
  78. struct in_impl {
  79. std::tuple<AN...> args_;
  80. PUSHMI_TEMPLATE(class In)
  81. (requires Sender<In>)
  82. auto operator()(In in) {
  83. return tap_fn::impl(
  84. std::move(in),
  85. ::pushmi::detail::receiver_from_fn<In>()(std::move(args_)));
  86. }
  87. };
  88. PUSHMI_TEMPLATE(class In, class SideEffects)
  89. (requires Sender<In>&& Receiver<SideEffects>)
  90. struct out_impl {
  91. SideEffects sideEffects_;
  92. PUSHMI_TEMPLATE(class Out)
  93. (requires Receiver<Out>&& SenderTo<In, Out>&& SenderTo<
  94. In,
  95. decltype(::pushmi::detail::receiver_from_fn<In>()(detail::make_tap(
  96. std::declval<SideEffects>(),
  97. std::declval<Out>())))>)
  98. auto operator()(Out out) const {
  99. auto gang{::pushmi::detail::receiver_from_fn<In>()(
  100. detail::make_tap(sideEffects_, std::move(out)))};
  101. return gang;
  102. }
  103. };
  104. public:
  105. template <class... AN>
  106. auto operator()(AN... an) const {
  107. return in_impl<AN...>{std::tuple<AN...>{std::move(an)...}};
  108. }
  109. };
  110. } // namespace detail
  111. namespace operators {
  112. PUSHMI_INLINE_VAR constexpr detail::tap_fn tap{};
  113. } // namespace operators
  114. } // namespace pushmi