318 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			318 lines
		
	
	
		
			8.9 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| // Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.
 | |
| 
 | |
| #pragma once
 | |
| 
 | |
| #if !defined(RXCPP_RX_PREDEF_HPP)
 | |
| #define RXCPP_RX_PREDEF_HPP
 | |
| 
 | |
| #include "rx-includes.hpp"
 | |
| #include "rx-observable-fwd.hpp"
 | |
| 
 | |
| namespace rxcpp {
 | |
| 
 | |
| //
 | |
| // create a typedef for rxcpp_trace_type to override the default
 | |
| //
 | |
| inline auto trace_activity() -> decltype(rxcpp_trace_activity(trace_tag()))& {
 | |
|     static decltype(rxcpp_trace_activity(trace_tag())) trace;
 | |
|     return trace;
 | |
| }
 | |
| 
 | |
| 
 | |
| struct tag_action {};
 | |
| template<class T, class C = rxu::types_checked>
 | |
| struct is_action : public std::false_type {};
 | |
| 
 | |
| template<class T>
 | |
| struct is_action<T, typename rxu::types_checked_from<typename T::action_tag>::type>
 | |
|     : public std::is_convertible<typename T::action_tag*, tag_action*> {};
 | |
| 
 | |
| 
 | |
| struct tag_worker {};
 | |
| template<class T>
 | |
| class is_worker
 | |
| {
 | |
|     struct not_void {};
 | |
|     template<class C>
 | |
|     static typename C::worker_tag* check(int);
 | |
|     template<class C>
 | |
|     static not_void check(...);
 | |
| public:
 | |
|     static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_worker*>::value;
 | |
| };
 | |
| 
 | |
| struct tag_scheduler {};
 | |
| template<class T>
 | |
| class is_scheduler
 | |
| {
 | |
|     struct not_void {};
 | |
|     template<class C>
 | |
|     static typename C::scheduler_tag* check(int);
 | |
|     template<class C>
 | |
|     static not_void check(...);
 | |
| public:
 | |
|     static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_scheduler*>::value;
 | |
| };
 | |
| 
 | |
| struct tag_schedulable {};
 | |
| template<class T>
 | |
| class is_schedulable
 | |
| {
 | |
|     struct not_void {};
 | |
|     template<class C>
 | |
|     static typename C::schedulable_tag* check(int);
 | |
|     template<class C>
 | |
|     static not_void check(...);
 | |
| public:
 | |
|     static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_schedulable*>::value;
 | |
| };
 | |
| 
 | |
| namespace detail
 | |
| {
 | |
| 
 | |
| struct stateless_observer_tag {};
 | |
| 
 | |
| }
 | |
| 
 | |
| // state with optional overrides
 | |
| template<class T, class State = void, class OnNext = void, class OnError = void, class OnCompleted = void>
 | |
| class observer;
 | |
| 
 | |
| // no state with optional overrides
 | |
| template<class T, class OnNext, class OnError, class OnCompleted>
 | |
| class observer<T, detail::stateless_observer_tag, OnNext, OnError, OnCompleted>;
 | |
| 
 | |
| // virtual functions forward to dynamically allocated shared observer instance.
 | |
| template<class T>
 | |
| class observer<T, void, void, void, void>;
 | |
| 
 | |
| struct tag_observer {};
 | |
| template<class T>
 | |
| class is_observer
 | |
| {
 | |
|     template<class C>
 | |
|     static typename C::observer_tag* check(int);
 | |
|     template<class C>
 | |
|     static void check(...);
 | |
| public:
 | |
|     static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_observer*>::value;
 | |
| };
 | |
| 
 | |
| struct tag_dynamic_observer {};
 | |
| template<class T>
 | |
| class is_dynamic_observer
 | |
| {
 | |
|     struct not_void {};
 | |
|     template<class C>
 | |
|     static typename C::dynamic_observer_tag* check(int);
 | |
|     template<class C>
 | |
|     static not_void check(...);
 | |
| public:
 | |
|     static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_dynamic_observer*>::value;
 | |
| };
 | |
| 
 | |
| struct tag_subscriber {};
 | |
| template<class T>
 | |
| class is_subscriber
 | |
| {
 | |
|     struct not_void {};
 | |
|     template<class C>
 | |
|     static typename C::subscriber_tag* check(int);
 | |
|     template<class C>
 | |
|     static not_void check(...);
 | |
| public:
 | |
|     static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_subscriber*>::value;
 | |
| };
 | |
| 
 | |
| struct tag_dynamic_observable {};
 | |
| template<class T>
 | |
| class is_dynamic_observable
 | |
| {
 | |
|     struct not_void {};
 | |
|     template<class C>
 | |
|     static typename C::dynamic_observable_tag* check(int);
 | |
|     template<class C>
 | |
|     static not_void check(...);
 | |
| public:
 | |
|     static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_dynamic_observable*>::value;
 | |
| };
 | |
| 
 | |
| template<class Selector, class Default, template<class... TN> class SO, class... AN>
 | |
| struct defer_observable;
 | |
| 
 | |
| struct tag_observable {};
 | |
| template<class T>
 | |
| struct observable_base {
 | |
|     typedef tag_observable observable_tag;
 | |
|     typedef T value_type;
 | |
| };
 | |
| 
 | |
| namespace detail {
 | |
| 
 | |
| template<class T, class =rxu::types_checked>
 | |
| struct is_observable : std::false_type
 | |
| {
 | |
| };
 | |
| 
 | |
| template<class T>
 | |
| struct is_observable<T, rxu::types_checked_t<typename T::observable_tag>> 
 | |
|     : std::is_convertible<typename T::observable_tag*, tag_observable*>
 | |
| {
 | |
| };
 | |
| 
 | |
| }
 | |
| 
 | |
| template<class T, class Decayed = rxu::decay_t<T>>
 | |
| struct is_observable : detail::is_observable<Decayed>
 | |
| {
 | |
| };
 | |
| 
 | |
| template<class Observable, class DecayedObservable = rxu::decay_t<Observable>>
 | |
| using observable_tag_t = typename DecayedObservable::observable_tag;
 | |
| 
 | |
| // extra indirection for vs2013 support
 | |
| template<class Types, class =rxu::types_checked>
 | |
| struct expand_observable_tags { struct type; };
 | |
| template<class... ObservableN>
 | |
| struct expand_observable_tags<rxu::types<ObservableN...>, rxu::types_checked_t<typename ObservableN::observable_tag...>> 
 | |
| {
 | |
|     using type = rxu::types<typename ObservableN::observable_tag...>;
 | |
| };
 | |
| template<class... ObservableN>
 | |
| using observable_tags_t = typename expand_observable_tags<rxu::types<ObservableN...>>::type;
 | |
| 
 | |
| template<class... ObservableN>
 | |
| using all_observables = rxu::all_true_type<is_observable<ObservableN>...>;
 | |
| 
 | |
| struct tag_dynamic_connectable_observable : public tag_dynamic_observable {};
 | |
| 
 | |
| template<class T>
 | |
| class is_dynamic_connectable_observable
 | |
| {
 | |
|     struct not_void {};
 | |
|     template<class C>
 | |
|     static typename C::dynamic_observable_tag* check(int);
 | |
|     template<class C>
 | |
|     static not_void check(...);
 | |
| public:
 | |
|     static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_dynamic_connectable_observable*>::value;
 | |
| };
 | |
| 
 | |
| template<class T>
 | |
| class dynamic_connectable_observable;
 | |
| 
 | |
| template<class T,
 | |
|     class SourceObservable = typename std::conditional<std::is_same<T, void>::value,
 | |
|         void, dynamic_connectable_observable<T>>::type>
 | |
| class connectable_observable;
 | |
| 
 | |
| struct tag_connectable_observable : public tag_observable {};
 | |
| template<class T>
 | |
| class is_connectable_observable
 | |
| {
 | |
|     template<class C>
 | |
|     static typename C::observable_tag check(int);
 | |
|     template<class C>
 | |
|     static void check(...);
 | |
| public:
 | |
|     static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_connectable_observable>::value;
 | |
| };
 | |
| 
 | |
| struct tag_dynamic_grouped_observable : public tag_dynamic_observable {};
 | |
| 
 | |
| template<class T>
 | |
| class is_dynamic_grouped_observable
 | |
| {
 | |
|     struct not_void {};
 | |
|     template<class C>
 | |
|     static typename C::dynamic_observable_tag* check(int);
 | |
|     template<class C>
 | |
|     static not_void check(...);
 | |
| public:
 | |
|     static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_dynamic_grouped_observable*>::value;
 | |
| };
 | |
| 
 | |
| template<class K, class T>
 | |
| class dynamic_grouped_observable;
 | |
| 
 | |
| template<class K, class T,
 | |
|     class SourceObservable = typename std::conditional<std::is_same<T, void>::value,
 | |
|         void, dynamic_grouped_observable<K, T>>::type>
 | |
| class grouped_observable;
 | |
| 
 | |
| template<class K, class T, class Source>
 | |
| grouped_observable<K, T> make_dynamic_grouped_observable(Source&& s);
 | |
| 
 | |
| struct tag_grouped_observable : public tag_observable {};
 | |
| template<class T>
 | |
| class is_grouped_observable
 | |
| {
 | |
|     template<class C>
 | |
|     static typename C::observable_tag check(int);
 | |
|     template<class C>
 | |
|     static void check(...);
 | |
| public:
 | |
|     static const bool value = std::is_convertible<decltype(check<rxu::decay_t<T>>(0)), tag_grouped_observable>::value;
 | |
| };
 | |
| 
 | |
| template<class Source, class Function>
 | |
| struct is_operator_factory_for {
 | |
|     using function_type = rxu::decay_t<Function>;
 | |
|     using source_type = rxu::decay_t<Source>;
 | |
| 
 | |
| // check methods instead of void_t for vs2013 support
 | |
| 
 | |
|     struct tag_not_valid;
 | |
|     template<class CS, class CO>
 | |
|     static auto check(int) -> decltype((*(CS*)nullptr)((*(CO*)nullptr)));
 | |
|     template<class CS, class CO>
 | |
|     static tag_not_valid check(...);
 | |
| 
 | |
|     using type = decltype(check<function_type, source_type>(0));
 | |
| 
 | |
|     static const bool value = !std::is_same<type, tag_not_valid>::value && is_observable<source_type>::value;
 | |
| };
 | |
| 
 | |
| //
 | |
| // this type is the default used by operators that subscribe to
 | |
| // multiple sources. It assumes that the sources are already synchronized
 | |
| //
 | |
| struct identity_observable
 | |
| {
 | |
|     template<class Observable>
 | |
|     auto operator()(Observable o)
 | |
|         -> Observable {
 | |
|         return      std::move(o);
 | |
|         static_assert(is_observable<Observable>::value, "only support observables");
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<class T>
 | |
| struct identity_for
 | |
| {
 | |
|     T operator()(T t) {
 | |
|         return      std::move(t);
 | |
|     }
 | |
| };
 | |
| 
 | |
| template<class T, class Seed, class Accumulator>
 | |
| struct is_accumulate_function_for {
 | |
| 
 | |
|     typedef rxu::decay_t<Accumulator> accumulator_type;
 | |
|     typedef rxu::decay_t<Seed> seed_type;
 | |
|     typedef T source_value_type;
 | |
| 
 | |
|     struct tag_not_valid {};
 | |
|     template<class CS, class CV, class CRS>
 | |
|     static auto check(int) -> decltype((*(CRS*)nullptr)(*(CS*)nullptr, *(CV*)nullptr));
 | |
|     template<class CS, class CV, class CRS>
 | |
|     static tag_not_valid check(...);
 | |
| 
 | |
|     typedef decltype(check<seed_type, source_value_type, accumulator_type>(0)) type;
 | |
|     static const bool value = std::is_same<type, seed_type>::value;
 | |
| };
 | |
| 
 | |
| }
 | |
| 
 | |
| #endif
 |