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