switch_on_error.h 2.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980
  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 <folly/experimental/pushmi/piping.h>
  19. namespace pushmi {
  20. namespace detail {
  21. struct switch_on_error_fn {
  22. private:
  23. template <class ErrorSelector>
  24. struct on_error_impl {
  25. ErrorSelector es_;
  26. PUSHMI_TEMPLATE(class Out, class E)
  27. (requires Receiver<Out>&& Invocable<const ErrorSelector&, E>&&
  28. SenderTo<pushmi::invoke_result_t<ErrorSelector&, E>, Out>)
  29. void operator()(Out& out, E&& e) const noexcept {
  30. static_assert(
  31. ::pushmi::NothrowInvocable<const ErrorSelector&, E>,
  32. "switch_on_error - error selector function must be noexcept");
  33. auto next = es_((E &&) e);
  34. ::pushmi::submit(next, out);
  35. }
  36. };
  37. template <class In, class ErrorSelector>
  38. struct out_impl {
  39. ErrorSelector es_;
  40. PUSHMI_TEMPLATE(class Out)
  41. (requires Receiver<Out>)
  42. auto operator()(Out out) const {
  43. return ::pushmi::detail::receiver_from_fn<In>()(
  44. std::move(out),
  45. // copy 'es' to allow multiple calls to submit
  46. ::pushmi::on_error(on_error_impl<ErrorSelector>{es_}));
  47. }
  48. };
  49. template <class ErrorSelector>
  50. struct in_impl {
  51. ErrorSelector es_;
  52. PUSHMI_TEMPLATE(class In)
  53. (requires Sender<In>)
  54. auto operator()(In in) const {
  55. return ::pushmi::detail::sender_from(
  56. std::move(in),
  57. ::pushmi::detail::submit_transform_out<In>(
  58. out_impl<In, ErrorSelector>{es_}));
  59. }
  60. };
  61. public:
  62. PUSHMI_TEMPLATE(class ErrorSelector)
  63. (requires SemiMovable<ErrorSelector>)
  64. auto operator()(ErrorSelector es) const {
  65. return in_impl<ErrorSelector>{std::move(es)};
  66. }
  67. };
  68. } // namespace detail
  69. namespace operators {
  70. PUSHMI_INLINE_VAR constexpr detail::switch_on_error_fn switch_on_error{};
  71. } // namespace operators
  72. } // namespace pushmi