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_PREDEF_HPP)
6 #define RXCPP_RX_PREDEF_HPP
7
8 #include "rx-includes.hpp"
9
10 namespace rxcpp {
11
12 //
13 // create a typedef for rxcpp_trace_type to override the default
14 //
trace_activity()15 inline auto trace_activity() -> decltype(rxcpp_trace_activity(trace_tag()))& {
16 static decltype(rxcpp_trace_activity(trace_tag())) trace;
17 return trace;
18 }
19
20
21 struct tag_action {};
22 template<class T, class C = rxu::types_checked>
23 struct is_action : public std::false_type {};
24
25 template<class T>
26 struct is_action<T, typename rxu::types_checked_from<typename T::action_tag>::type>
27 : public std::is_convertible<typename T::action_tag*, tag_action*> {};
28
29
30 struct tag_worker {};
31 template<class T>
32 class is_worker
33 {
34 struct not_void {};
35 template<class C>
36 static typename C::worker_tag* check(int);
37 template<class C>
38 static not_void check(...);
39 public:
40 static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_worker*>::value;
41 };
42
43 struct tag_scheduler {};
44 template<class T>
45 class is_scheduler
46 {
47 struct not_void {};
48 template<class C>
49 static typename C::scheduler_tag* check(int);
50 template<class C>
51 static not_void check(...);
52 public:
53 static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_scheduler*>::value;
54 };
55
56 struct tag_schedulable {};
57 template<class T>
58 class is_schedulable
59 {
60 struct not_void {};
61 template<class C>
62 static typename C::schedulable_tag* check(int);
63 template<class C>
64 static not_void check(...);
65 public:
66 static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_schedulable*>::value;
67 };
68
69 namespace detail
70 {
71
72 struct stateless_observer_tag {};
73
74 }
75
76 // state with optional overrides
77 template<class T, class State = void, class OnNext = void, class OnError = void, class OnCompleted = void>
78 class observer;
79
80 // no state with optional overrides
81 template<class T, class OnNext, class OnError, class OnCompleted>
82 class observer<T, detail::stateless_observer_tag, OnNext, OnError, OnCompleted>;
83
84 // virtual functions forward to dynamically allocated shared observer instance.
85 template<class T>
86 class observer<T, void, void, void, void>;
87
88 struct tag_observer {};
89 template<class T>
90 class is_observer
91 {
92 template<class C>
93 static typename C::observer_tag* check(int);
94 template<class C>
95 static void check(...);
96 public:
97 static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_observer*>::value;
98 };
99
100 struct tag_dynamic_observer {};
101 template<class T>
102 class is_dynamic_observer
103 {
104 struct not_void {};
105 template<class C>
106 static typename C::dynamic_observer_tag* check(int);
107 template<class C>
108 static not_void check(...);
109 public:
110 static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_dynamic_observer*>::value;
111 };
112
113 struct tag_subscriber {};
114 template<class T>
115 class is_subscriber
116 {
117 struct not_void {};
118 template<class C>
119 static typename C::subscriber_tag* check(int);
120 template<class C>
121 static not_void check(...);
122 public:
123 static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_subscriber*>::value;
124 };
125
126 struct tag_dynamic_observable {};
127 template<class T>
128 class is_dynamic_observable
129 {
130 struct not_void {};
131 template<class C>
132 static typename C::dynamic_observable_tag* check(int);
133 template<class C>
134 static not_void check(...);
135 public:
136 static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_dynamic_observable*>::value;
137 };
138
139 template<class T>
140 class dynamic_observable;
141
142 template<
143 class T = void,
144 class SourceObservable = typename std::conditional<std::is_same<T, void>::value,
145 void, dynamic_observable<T>>::type>
146 class observable;
147
148 template<class T, class Source>
149 observable<T> make_observable_dynamic(Source&&);
150
151 template<class Selector, class Default, template<class... TN> class SO, class... AN>
152 struct defer_observable;
153
154 struct tag_observable {};
155 template<class T>
156 struct observable_base {
157 typedef tag_observable observable_tag;
158 typedef T value_type;
159 };
160
161 namespace detail {
162
163 template<class T, class =rxu::types_checked>
164 struct is_observable : std::false_type
165 {
166 };
167
168 template<class T>
169 struct is_observable<T, rxu::types_checked_t<typename T::observable_tag>>
170 : std::is_convertible<typename T::observable_tag*, tag_observable*>
171 {
172 };
173
174 }
175
176 template<class T, class Decayed = rxu::decay_t<T>>
177 struct is_observable : detail::is_observable<Decayed>
178 {
179 };
180
181 template<class Observable, class DecayedObservable = rxu::decay_t<Observable>>
182 using observable_tag_t = typename DecayedObservable::observable_tag;
183
184 // extra indirection for vs2013 support
185 template<class Types, class =rxu::types_checked>
186 struct expand_observable_tags { struct type; };
187 template<class... ObservableN>
188 struct expand_observable_tags<rxu::types<ObservableN...>, rxu::types_checked_t<typename ObservableN::observable_tag...>>
189 {
190 using type = rxu::types<typename ObservableN::observable_tag...>;
191 };
192 template<class... ObservableN>
193 using observable_tags_t = typename expand_observable_tags<rxu::types<ObservableN...>>::type;
194
195 template<class... ObservableN>
196 using all_observables = rxu::all_true_type<is_observable<ObservableN>...>;
197
198 struct tag_dynamic_connectable_observable : public tag_dynamic_observable {};
199
200 template<class T>
201 class is_dynamic_connectable_observable
202 {
203 struct not_void {};
204 template<class C>
205 static typename C::dynamic_observable_tag* check(int);
206 template<class C>
207 static not_void check(...);
208 public:
209 static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_dynamic_connectable_observable*>::value;
210 };
211
212 template<class T>
213 class dynamic_connectable_observable;
214
215 template<class T,
216 class SourceObservable = typename std::conditional<std::is_same<T, void>::value,
217 void, dynamic_connectable_observable<T>>::type>
218 class connectable_observable;
219
220 struct tag_connectable_observable : public tag_observable {};
221 template<class T>
222 class is_connectable_observable
223 {
224 template<class C>
225 static typename C::observable_tag check(int);
226 template<class C>
227 static void check(...);
228 public:
229 static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_connectable_observable>::value;
230 };
231
232 struct tag_dynamic_grouped_observable : public tag_dynamic_observable {};
233
234 template<class T>
235 class is_dynamic_grouped_observable
236 {
237 struct not_void {};
238 template<class C>
239 static typename C::dynamic_observable_tag* check(int);
240 template<class C>
241 static not_void check(...);
242 public:
243 static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_dynamic_grouped_observable*>::value;
244 };
245
246 template<class K, class T>
247 class dynamic_grouped_observable;
248
249 template<class K, class T,
250 class SourceObservable = typename std::conditional<std::is_same<T, void>::value,
251 void, dynamic_grouped_observable<K, T>>::type>
252 class grouped_observable;
253
254 template<class K, class T, class Source>
255 grouped_observable<K, T> make_dynamic_grouped_observable(Source&& s);
256
257 struct tag_grouped_observable : public tag_observable {};
258 template<class T>
259 class is_grouped_observable
260 {
261 template<class C>
262 static typename C::observable_tag check(int);
263 template<class C>
264 static void check(...);
265 public:
266 static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_grouped_observable>::value;
267 };
268
269 template<class Source, class Function>
270 struct is_operator_factory_for {
271 using function_type = rxu::decay_t<Function>;
272 using source_type = rxu::decay_t<Source>;
273
274 // check methods instead of void_t for vs2013 support
275
276 struct tag_not_valid;
277 template<class CS, class CO>
278 static auto check(int) -> decltype((*(CS*)nullptr)((*(CO*)nullptr)));
279 template<class CS, class CO>
280 static tag_not_valid check(...);
281
282 using type = decltype(check<function_type, source_type>(0));
283
284 static const bool value = !std::is_same<type, tag_not_valid>::value && is_observable<source_type>::value;
285 };
286
287 //
288 // this type is the default used by operators that subscribe to
289 // multiple sources. It assumes that the sources are already synchronized
290 //
291 struct identity_observable
292 {
293 template<class Observable>
operator ()rxcpp::identity_observable294 auto operator()(Observable o)
295 -> Observable {
296 return std::move(o);
297 static_assert(is_observable<Observable>::value, "only support observables");
298 }
299 };
300
301 template<class T>
302 struct identity_for
303 {
operator ()rxcpp::identity_for304 T operator()(T t) {
305 return std::move(t);
306 }
307 };
308
309 template<class T, class Seed, class Accumulator>
310 struct is_accumulate_function_for {
311
312 typedef rxu::decay_t<Accumulator> accumulator_type;
313 typedef rxu::decay_t<Seed> seed_type;
314 typedef T source_value_type;
315
316 struct tag_not_valid {};
317 template<class CS, class CV, class CRS>
318 static auto check(int) -> decltype((*(CRS*)nullptr)(*(CS*)nullptr, *(CV*)nullptr));
319 template<class CS, class CV, class CRS>
320 static tag_not_valid check(...);
321
322 typedef decltype(check<seed_type, source_value_type, accumulator_type>(0)) type;
323 static const bool value = std::is_same<type, seed_type>::value;
324 };
325
326 }
327
328 #endif
329