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-finally.hpp
6 
7     \brief Add a new action at the end of the new observable that is returned.
8 
9     \tparam LastCall the type of the action function
10 
11     \param lc the action function
12 
13     \return Observable that emits the same items as the source observable, then invokes the given action.
14 
15     \sample
16     \snippet finally.cpp finally sample
17     \snippet output.txt finally sample
18 
19     If the source observable generates an error, the final action is still being called:
20     \snippet finally.cpp error finally sample
21     \snippet output.txt error finally sample
22 */
23 
24 #if !defined(RXCPP_OPERATORS_RX_FINALLY_HPP)
25 #define RXCPP_OPERATORS_RX_FINALLY_HPP
26 
27 #include "../rx-includes.hpp"
28 
29 namespace rxcpp {
30 
31 namespace operators {
32 
33 namespace detail {
34 
35 template<class... AN>
36 struct finally_invalid_arguments {};
37 
38 template<class... AN>
39 struct finally_invalid : public rxo::operator_base<finally_invalid_arguments<AN...>> {
40     using type = observable<finally_invalid_arguments<AN...>, finally_invalid<AN...>>;
41 };
42 template<class... AN>
43 using finally_invalid_t = typename finally_invalid<AN...>::type;
44 
45 template<class T, class LastCall>
46 struct finally
47 {
48     typedef rxu::decay_t<T> source_value_type;
49     typedef rxu::decay_t<LastCall> last_call_type;
50     last_call_type last_call;
51 
finallyrxcpp::operators::detail::finally52     finally(last_call_type lc)
53         : last_call(std::move(lc))
54     {
55     }
56 
57     template<class Subscriber>
58     struct finally_observer
59     {
60         typedef finally_observer<Subscriber> this_type;
61         typedef source_value_type value_type;
62         typedef rxu::decay_t<Subscriber> dest_type;
63         typedef observer<value_type, this_type> observer_type;
64         dest_type dest;
65 
finally_observerrxcpp::operators::detail::finally::finally_observer66         finally_observer(dest_type d)
67             : dest(std::move(d))
68         {
69         }
on_nextrxcpp::operators::detail::finally::finally_observer70         void on_next(source_value_type v) const {
71             dest.on_next(v);
72         }
on_errorrxcpp::operators::detail::finally::finally_observer73         void on_error(rxu::error_ptr e) const {
74             dest.on_error(e);
75         }
on_completedrxcpp::operators::detail::finally::finally_observer76         void on_completed() const {
77             dest.on_completed();
78         }
79 
makerxcpp::operators::detail::finally::finally_observer80         static subscriber<value_type, observer_type> make(dest_type d, const last_call_type& lc) {
81             auto dl = d.get_subscription();
82             composite_subscription cs;
83             dl.add(cs);
84             cs.add([=](){
85                 dl.unsubscribe();
86                 lc();
87             });
88             return make_subscriber<value_type>(cs, this_type(d));
89         }
90     };
91 
92     template<class Subscriber>
operator ()rxcpp::operators::detail::finally93     auto operator()(Subscriber dest) const
94         -> decltype(finally_observer<Subscriber>::make(std::move(dest), last_call)) {
95         return      finally_observer<Subscriber>::make(std::move(dest), last_call);
96     }
97 };
98 
99 }
100 
101 /*! @copydoc rx-finally.hpp
102 */
103 template<class... AN>
finally(AN &&...an)104 auto finally(AN&&... an)
105     ->      operator_factory<finally_tag, AN...> {
106      return operator_factory<finally_tag, AN...>(std::make_tuple(std::forward<AN>(an)...));
107 }
108 
109 }
110 
111 template<>
112 struct member_overload<finally_tag>
113 {
114     template<class Observable, class LastCall,
115         class SourceValue = rxu::value_type_t<Observable>,
116         class Enabled = rxu::enable_if_all_true_type_t<
117             is_observable<Observable>>,
118         class Finally = rxo::detail::finally<SourceValue, rxu::decay_t<LastCall>>>
memberrxcpp::member_overload119     static auto member(Observable&& o, LastCall&& lc)
120         -> decltype(o.template lift<SourceValue>(Finally(std::forward<LastCall>(lc)))) {
121         return      o.template lift<SourceValue>(Finally(std::forward<LastCall>(lc)));
122     }
123 
124     template<class... AN>
memberrxcpp::member_overload125     static operators::detail::finally_invalid_t<AN...> member(const AN&...) {
126         std::terminate();
127         return {};
128         static_assert(sizeof...(AN) == 10000, "finally takes (LastCall)");
129     }
130 };
131 
132 }
133 
134 #endif
135