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 // 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> 294 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 { 304 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