]> git.sesse.net Git - casparcg/blob - dependencies64/RxCpp/include/rxcpp/rx-observer.hpp
* Added RxCpp library for LINQ api, replacing Boost.Range based iterations where...
[casparcg] / dependencies64 / RxCpp / include / rxcpp / rx-observer.hpp
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 #if !defined(RXCPP_RX_OBSERVER_HPP)
6 #define RXCPP_RX_OBSERVER_HPP
7
8 #include "rx-includes.hpp"
9
10 namespace rxcpp {
11
12
13 template<class T>
14 struct observer_base
15 {
16     typedef T value_type;
17     typedef tag_observer observer_tag;
18 };
19
20 namespace detail {
21 template<class T>
22 struct OnNextEmpty
23 {
24     void operator()(const T&) const {}
25 };
26 struct OnErrorEmpty
27 {
28     void operator()(std::exception_ptr) const {
29         // error implicitly ignored, abort
30         abort();
31     }
32 };
33 struct OnCompletedEmpty
34 {
35     void operator()() const {}
36 };
37
38 template<class T, class F>
39 struct is_on_next_of
40 {
41     struct not_void {};
42     template<class CT, class CF>
43     static auto check(int) -> decltype((*(CF*)nullptr)(*(CT*)nullptr));
44     template<class CT, class CF>
45     static not_void check(...);
46
47     typedef decltype(check<T, typename std::decay<F>::type>(0)) detail_result;
48     static const bool value = std::is_same<detail_result, void>::value;
49 };
50
51 template<class F>
52 struct is_on_error
53 {
54     struct not_void {};
55     template<class CF>
56     static auto check(int) -> decltype((*(CF*)nullptr)(*(std::exception_ptr*)nullptr));
57     template<class CF>
58     static not_void check(...);
59
60     static const bool value = std::is_same<decltype(check<typename std::decay<F>::type>(0)), void>::value;
61 };
62
63 template<class F>
64 struct is_on_completed
65 {
66     struct not_void {};
67     template<class CF>
68     static auto check(int) -> decltype((*(CF*)nullptr)());
69     template<class CF>
70     static not_void check(...);
71
72     static const bool value = std::is_same<decltype(check<typename std::decay<F>::type>(0)), void>::value;
73 };
74
75 }
76
77 template<class T, class OnNext, class OnError = detail::OnErrorEmpty, class OnCompleted = detail::OnCompletedEmpty>
78 class static_observer
79 {
80 public:
81     typedef static_observer<T, OnNext, OnError, OnCompleted> this_type;
82     typedef typename std::decay<OnNext>::type on_next_t;
83     typedef typename std::decay<OnError>::type on_error_t;
84     typedef typename std::decay<OnCompleted>::type on_completed_t;
85
86 private:
87     on_next_t onnext;
88     on_error_t onerror;
89     on_completed_t oncompleted;
90
91 public:
92     static_assert(detail::is_on_next_of<T, on_next_t>::value,     "Function supplied for on_next must be a function with the signature void(T);");
93     static_assert(detail::is_on_error<on_error_t>::value,         "Function supplied for on_error must be a function with the signature void(std::exception_ptr);");
94     static_assert(detail::is_on_completed<on_completed_t>::value, "Function supplied for on_completed must be a function with the signature void();");
95
96     explicit static_observer(on_next_t n, on_error_t e = on_error_t(), on_completed_t c = on_completed_t())
97         : onnext(std::move(n))
98         , onerror(std::move(e))
99         , oncompleted(std::move(c))
100     {
101     }
102     static_observer(const this_type& o)
103         : onnext(o.onnext)
104         , onerror(o.onerror)
105         , oncompleted(o.oncompleted)
106     {
107     }
108     static_observer(this_type&& o)
109         : onnext(std::move(o.onnext))
110         , onerror(std::move(o.onerror))
111         , oncompleted(std::move(o.oncompleted))
112     {
113     }
114     this_type& operator=(this_type o) {
115         onnext = std::move(o.onnext);
116         onerror = std::move(o.onerror);
117         oncompleted = std::move(o.oncompleted);
118         return *this;
119     }
120
121     // use V so that std::move can be used safely
122     template<class V>
123     void on_next(V v) const {
124         onnext(std::move(v));
125     }
126     void on_error(std::exception_ptr e) const {
127         onerror(e);
128     }
129     void on_completed() const {
130         oncompleted();
131     }
132 };
133
134 template<class T>
135 class dynamic_observer
136 {
137 public:
138     typedef tag_dynamic_observer dynamic_observer_tag;
139
140 private:
141     typedef dynamic_observer<T> this_type;
142     typedef observer_base<T> base_type;
143
144     struct virtual_observer : public std::enable_shared_from_this<virtual_observer>
145     {
146         virtual void on_next(T) const =0;
147         virtual void on_error(std::exception_ptr e) const =0;
148         virtual void on_completed() const =0;
149     };
150
151     template<class Observer>
152     struct specific_observer : public virtual_observer
153     {
154         explicit specific_observer(Observer o)
155             : destination(std::move(o))
156         {
157         }
158
159         Observer destination;
160         virtual void on_next(T t) const {
161             destination.on_next(std::move(t));
162         }
163         virtual void on_error(std::exception_ptr e) const {
164             destination.on_error(e);
165         }
166         virtual void on_completed() const {
167             destination.on_completed();
168         }
169     };
170
171     std::shared_ptr<virtual_observer> destination;
172
173     template<class Observer>
174     static auto make_destination(Observer o)
175         -> std::shared_ptr<virtual_observer> {
176         return std::make_shared<specific_observer<Observer>>(std::move(o));
177     }
178
179 public:
180     dynamic_observer()
181     {
182     }
183     dynamic_observer(const this_type& o)
184         : destination(o.destination)
185     {
186     }
187     dynamic_observer(this_type&& o)
188         : destination(std::move(o.destination))
189     {
190     }
191
192     template<class Observer>
193     explicit dynamic_observer(Observer o)
194         : destination(make_destination(std::move(o)))
195     {
196     }
197
198     this_type& operator=(this_type o) {
199         destination = std::move(o.destination);
200         return *this;
201     }
202
203     // perfect forwarding delays the copy of the value.
204     template<class V>
205     void on_next(V&& v) const {
206         if (destination) {
207             destination->on_next(std::forward<V>(v));
208         }
209     }
210     void on_error(std::exception_ptr e) const {
211         if (destination) {
212             destination->on_error(e);
213         }
214     }
215     void on_completed() const {
216         if (destination) {
217             destination->on_completed();
218         }
219     }
220 };
221
222
223 template<class T, class I>
224 class observer : public observer_base<T>
225 {
226     typedef observer<T, I> this_type;
227     typedef typename std::decay<I>::type inner_t;
228
229     inner_t inner;
230
231     observer();
232 public:
233     ~observer()
234     {
235     }
236     observer(const this_type& o)
237         : inner(o.inner)
238     {
239     }
240     observer(this_type&& o)
241         : inner(std::move(o.inner))
242     {
243     }
244     explicit observer(inner_t inner)
245         : inner(std::move(inner))
246     {
247     }
248     this_type& operator=(this_type o) {
249         inner = std::move(o.inner);
250         return *this;
251     }
252     template<class V>
253     void on_next(V&& v) const {
254         inner.on_next(std::forward<V>(v));
255     }
256     void on_error(std::exception_ptr e) const {
257         inner.on_error(e);
258     }
259     void on_completed() const {
260         inner.on_completed();
261     }
262     observer<T> as_dynamic() const {
263         return observer<T>(dynamic_observer<T>(inner));
264     }
265 };
266 template<class T>
267 class observer<T, void> : public observer_base<T>
268 {
269     typedef observer this_type;
270 public:
271     observer()
272     {
273     }
274     template<class V>
275     void on_next(V&&) const {
276     }
277     void on_error(std::exception_ptr) const {
278     }
279     void on_completed() const {
280     }
281 };
282
283 template<class T>
284 auto make_observer()
285     ->     observer<T, void> {
286     return observer<T, void>();
287 }
288
289 template<class T, class U, class I>
290 auto make_observer(observer<U, I> o)
291     ->      observer<T, I> {
292     return  observer<T, I>(std::move(o));
293 }
294 template<class T, class Observer>
295 auto make_observer(Observer ob)
296     -> typename std::enable_if<
297         !detail::is_on_next_of<T, Observer>::value &&
298         !is_observer<Observer>::value,
299             observer<T, Observer>>::type {
300     return  observer<T, Observer>(std::move(ob));
301 }
302 template<class T, class OnNext>
303 auto make_observer(OnNext on)
304     -> typename std::enable_if<
305         detail::is_on_next_of<T, OnNext>::value,
306             observer<T, static_observer<T, OnNext>>>::type {
307     return  observer<T, static_observer<T, OnNext>>(
308                         static_observer<T, OnNext>(std::move(on)));
309 }
310 template<class T, class OnNext, class OnError>
311 auto make_observer(OnNext on, OnError oe)
312     -> typename std::enable_if<
313         detail::is_on_next_of<T, OnNext>::value &&
314         detail::is_on_error<OnError>::value,
315             observer<T, static_observer<T, OnNext, OnError>>>::type {
316     return  observer<T, static_observer<T, OnNext, OnError>>(
317                         static_observer<T, OnNext, OnError>(std::move(on), std::move(oe)));
318 }
319 template<class T, class OnNext, class OnCompleted>
320 auto make_observer(OnNext on, OnCompleted oc)
321     -> typename std::enable_if<
322         detail::is_on_next_of<T, OnNext>::value &&
323         detail::is_on_completed<OnCompleted>::value,
324             observer<T, static_observer<T, OnNext, detail::OnErrorEmpty, OnCompleted>>>::type {
325     return  observer<T, static_observer<T, OnNext, detail::OnErrorEmpty, OnCompleted>>(
326                         static_observer<T, OnNext, detail::OnErrorEmpty, OnCompleted>(std::move(on), detail::OnErrorEmpty(), std::move(oc)));
327 }
328 template<class T, class OnNext, class OnError, class OnCompleted>
329 auto make_observer(OnNext on, OnError oe, OnCompleted oc)
330     -> typename std::enable_if<
331         detail::is_on_next_of<T, OnNext>::value &&
332         detail::is_on_error<OnError>::value &&
333         detail::is_on_completed<OnCompleted>::value,
334             observer<T, static_observer<T, OnNext, OnError, OnCompleted>>>::type {
335     return  observer<T, static_observer<T, OnNext, OnError, OnCompleted>>(
336                         static_observer<T, OnNext, OnError, OnCompleted>(std::move(on), std::move(oe), std::move(oc)));
337 }
338
339
340 template<class T, class Observer>
341 auto make_observer_dynamic(Observer o)
342     -> typename std::enable_if<
343         is_observer<Observer>::value,
344             observer<T>>::type {
345     return  observer<T>(dynamic_observer<T>(std::move(o)));
346 }
347 template<class T, class OnNext>
348 auto make_observer_dynamic(OnNext&& on)
349     -> typename std::enable_if<
350         detail::is_on_next_of<T, OnNext>::value,
351             observer<T, dynamic_observer<T>>>::type {
352     return  observer<T, dynamic_observer<T>>(
353                         dynamic_observer<T>(make_observer<T>(std::forward<OnNext>(on))));
354 }
355 template<class T, class OnNext, class OnError>
356 auto make_observer_dynamic(OnNext&& on, OnError&& oe)
357     -> typename std::enable_if<
358         detail::is_on_next_of<T, OnNext>::value &&
359         detail::is_on_error<OnError>::value,
360             observer<T, dynamic_observer<T>>>::type {
361     return  observer<T, dynamic_observer<T>>(
362                         dynamic_observer<T>(make_observer<T>(std::forward<OnNext>(on), std::forward<OnError>(oe))));
363 }
364 template<class T, class OnNext, class OnCompleted>
365 auto make_observer_dynamic(OnNext&& on, OnCompleted&& oc)
366     -> typename std::enable_if<
367         detail::is_on_next_of<T, OnNext>::value &&
368         detail::is_on_completed<OnCompleted>::value,
369             observer<T, dynamic_observer<T>>>::type {
370     return  observer<T, dynamic_observer<T>>(
371                         dynamic_observer<T>(make_observer<T>(std::forward<OnNext>(on), std::forward<OnCompleted>(oc))));
372 }
373 template<class T, class OnNext, class OnError, class OnCompleted>
374 auto make_observer_dynamic(OnNext&& on, OnError&& oe, OnCompleted&& oc)
375     -> typename std::enable_if<
376         detail::is_on_next_of<T, OnNext>::value &&
377         detail::is_on_error<OnError>::value &&
378         detail::is_on_completed<OnCompleted>::value,
379             observer<T, dynamic_observer<T>>>::type {
380     return  observer<T, dynamic_observer<T>>(
381                         dynamic_observer<T>(make_observer<T>(std::forward<OnNext>(on), std::forward<OnError>(oe), std::forward<OnCompleted>(oc))));
382 }
383
384 namespace detail {
385
386 template<class F>
387 struct maybe_from_result
388 {
389     typedef decltype((*(F*)nullptr)()) decl_result_type;
390     typedef typename std::decay<decl_result_type>::type result_type;
391     typedef rxu::maybe<result_type> type;
392 };
393
394 }
395
396 template<class F, class OnError>
397 auto on_exception(const F& f, const OnError& c)
398     ->  typename std::enable_if<detail::is_on_error<OnError>::value, typename detail::maybe_from_result<F>::type>::type {
399     typename detail::maybe_from_result<F>::type r;
400     try {
401         r.reset(f());
402     } catch (...) {
403         c(std::current_exception());
404     }
405     return r;
406 }
407
408 template<class F, class Subscriber>
409 auto on_exception(const F& f, const Subscriber& s)
410     ->  typename std::enable_if<is_subscriber<Subscriber>::value, typename detail::maybe_from_result<F>::type>::type {
411     typename detail::maybe_from_result<F>::type r;
412     try {
413         r.reset(f());
414     } catch (...) {
415         s.on_error(std::current_exception());
416     }
417     return r;
418 }
419
420 }
421
422 #endif