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