Home | History | Annotate | Download | only in operators
      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-lift.hpp
      6 
      7     \brief  takes any function that will take a subscriber for this observable and produce a subscriber.
      8             this is intended to allow externally defined operators, that use make_subscriber, to be connected into the expression.
      9 
     10     \tparam ResultType  the type of the emitted results.
     11     \tparam Operator    the type of the operator.
     12 
     13     \return An observable that emitting the items from its source.
     14  */
     15 
     16 #if !defined(RXCPP_OPERATORS_RX_LIFT_HPP)
     17 #define RXCPP_OPERATORS_RX_LIFT_HPP
     18 
     19 #include "../rx-includes.hpp"
     20 
     21 namespace rxcpp {
     22 
     23 namespace detail {
     24 
     25 template<class V, class S, class F>
     26 struct is_lift_function_for {
     27 
     28     struct tag_not_valid {};
     29     template<class CS, class CF>
     30     static auto check(int) -> decltype((*(CF*)nullptr)(*(CS*)nullptr));
     31     template<class CS, class CF>
     32     static tag_not_valid check(...);
     33 
     34     using for_type = rxu::decay_t<S>;
     35     using func_type = rxu::decay_t<F>;
     36     using detail_result = decltype(check<for_type, func_type>(0));
     37 
     38     static const bool value = rxu::all_true_type<
     39         is_subscriber<detail_result>,
     40         is_subscriber<for_type>,
     41         std::is_convertible<V, typename rxu::value_type_from<detail_result>::type>>::value;
     42 };
     43 
     44 }
     45 
     46 namespace operators {
     47 
     48 namespace detail {
     49 
     50 template<class ResultType, class SourceOperator, class Operator>
     51 struct lift_traits
     52 {
     53     typedef rxu::decay_t<ResultType> result_value_type;
     54     typedef rxu::decay_t<SourceOperator> source_operator_type;
     55     typedef rxu::decay_t<Operator> operator_type;
     56 
     57     typedef typename source_operator_type::value_type source_value_type;
     58 };
     59 
     60 template<class ResultType, class SourceOperator, class Operator>
     61 struct lift_operator : public operator_base<typename lift_traits<ResultType, SourceOperator, Operator>::result_value_type>
     62 {
     63     typedef lift_traits<ResultType, SourceOperator, Operator> traits;
     64     typedef typename traits::source_operator_type source_operator_type;
     65     typedef typename traits::operator_type operator_type;
     66     source_operator_type source;
     67     operator_type chain;
     68 
     69     lift_operator(source_operator_type s, operator_type op)
     70         : source(std::move(s))
     71         , chain(std::move(op))
     72     {
     73     }
     74     template<class Subscriber>
     75     void on_subscribe(Subscriber o) const {
     76         auto lifted = chain(std::move(o));
     77         trace_activity().lift_enter(source, chain, o, lifted);
     78         source.on_subscribe(std::move(lifted));
     79         trace_activity().lift_return(source, chain);
     80     }
     81 };
     82 
     83 template<class ResultType, class Operator>
     84 class lift_factory
     85 {
     86     typedef rxu::decay_t<Operator> operator_type;
     87     operator_type chain;
     88 public:
     89     lift_factory(operator_type op) : chain(std::move(op)) {}
     90     template<class Observable>
     91     auto operator()(const Observable& source)
     92         -> decltype(source.template lift<ResultType>(chain)) {
     93         return      source.template lift<ResultType>(chain);
     94         static_assert(rxcpp::detail::is_lift_function_for<rxu::value_type_t<Observable>, subscriber<ResultType>, Operator>::value, "Function passed for lift() must have the signature subscriber<...>(subscriber<T, ...>)");
     95     }
     96 };
     97 
     98 }
     99 
    100 template<class ResultType, class Operator>
    101 auto lift(Operator&& op)
    102     ->      detail::lift_factory<ResultType, Operator> {
    103     return  detail::lift_factory<ResultType, Operator>(std::forward<Operator>(op));
    104 }
    105 
    106 }
    107 
    108 }
    109 
    110 #endif
    111