1 // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
2
3 #pragma once
4
5 /*! \file rx-retry.hpp
6
7 \brief Retry this observable for the given number of times.
8
9 \tparam Count the type of the counter (optional)
10
11 \param t the total number of tries (optional), i.e. retry(2) means one normal try, before an error occurs, and one retry. If not specified, infinitely retries the source observable. Specifying 0 returns immediately without subscribing
12
13 \return An observable that mirrors the source observable, resubscribing to it if it calls on_error up to a specified number of retries.
14
15 \sample
16 \snippet retry.cpp retry count sample
17 \snippet output.txt retry count sample
18 */
19
20 #if !defined(RXCPP_OPERATORS_RX_RETRY_HPP)
21 #define RXCPP_OPERATORS_RX_RETRY_HPP
22
23 #include "../rx-includes.hpp"
24 #include "rx-retry-repeat-common.hpp"
25
26 namespace rxcpp {
27
28 namespace operators {
29
30 namespace detail {
31
32 template<class... AN>
33 struct retry_invalid_arguments {};
34
35 template<class... AN>
36 struct retry_invalid : public rxo::operator_base<retry_invalid_arguments<AN...>> {
37 using type = observable<retry_invalid_arguments<AN...>, retry_invalid<AN...>>;
38 };
39 template<class... AN>
40 using retry_invalid_t = typename retry_invalid<AN...>::type;
41
42 // Contain retry variations in a namespace
43 namespace retry {
44 struct event_handlers {
45 template <typename State>
on_errorrxcpp::operators::detail::retry::event_handlers46 static inline void on_error(State& state, rxu::error_ptr& e) {
47 state->update();
48 // Use specialized predicate for finite/infinte case
49 if (state->completed_predicate()) {
50 state->out.on_error(e);
51 } else {
52 state->do_subscribe();
53 }
54 }
55
56 template <typename State>
on_completedrxcpp::operators::detail::retry::event_handlers57 static inline void on_completed(State& state) {
58 state->out.on_completed();
59 }
60 };
61
62 // Finite repeat case (explicitely limited with the number of times)
63 template <class T, class Observable, class Count>
64 using finite = ::rxcpp::operators::detail::retry_repeat_common::finite
65 <event_handlers, T, Observable, Count>;
66
67 // Infinite repeat case
68 template <class T, class Observable>
69 using infinite = ::rxcpp::operators::detail::retry_repeat_common::infinite
70 <event_handlers, T, Observable>;
71
72 }
73 } // detail
74
75 /*! @copydoc rx-retry.hpp
76 */
77 template<class... AN>
retry(AN &&...an)78 auto retry(AN&&... an)
79 -> operator_factory<retry_tag, AN...> {
80 return operator_factory<retry_tag, AN...>(std::make_tuple(std::forward<AN>(an)...));
81 }
82
83 }
84
85 template<>
86 struct member_overload<retry_tag>
87 {
88 template<class Observable,
89 class Enabled = rxu::enable_if_all_true_type_t<is_observable<Observable>>,
90 class SourceValue = rxu::value_type_t<Observable>,
91 class Retry = rxo::detail::retry::infinite<SourceValue, rxu::decay_t<Observable>>,
92 class Value = rxu::value_type_t<Retry>,
93 class Result = observable<Value, Retry>
94 >
memberrxcpp::member_overload95 static Result member(Observable&& o) {
96 return Result(Retry(std::forward<Observable>(o)));
97 }
98
99 template<class Observable,
100 class Count,
101 class Enabled = rxu::enable_if_all_true_type_t<is_observable<Observable>>,
102 class SourceValue = rxu::value_type_t<Observable>,
103 class Retry = rxo::detail::retry::finite<SourceValue, rxu::decay_t<Observable>, rxu::decay_t<Count>>,
104 class Value = rxu::value_type_t<Retry>,
105 class Result = observable<Value, Retry>
106 >
memberrxcpp::member_overload107 static Result member(Observable&& o, Count&& c) {
108 return Result(Retry(std::forward<Observable>(o), std::forward<Count>(c)));
109 }
110
111 template<class... AN>
memberrxcpp::member_overload112 static operators::detail::retry_invalid_t<AN...> member(const AN&...) {
113 std::terminate();
114 return {};
115 static_assert(sizeof...(AN) == 10000, "retry takes (optional Count)");
116 }
117 };
118
119 }
120
121 #endif
122