summaryrefslogtreecommitdiff
path: root/Rx/v2/src/rxcpp/operators/rx-lift.hpp
blob: 4d85f77f9b5181f864af13f69bcdd316303ba961 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

#pragma once

#if !defined(RXCPP_OPERATORS_RX_LIFT_HPP)
#define RXCPP_OPERATORS_RX_LIFT_HPP

#include "../rx-includes.hpp"

namespace rxcpp {

namespace detail {

template<class V, class S, class F>
struct is_lift_function_for {

    struct tag_not_valid {};
    template<class CS, class CF>
    static auto check(int) -> decltype((*(CF*)nullptr)(*(CS*)nullptr));
    template<class CS, class CF>
    static tag_not_valid check(...);

    using for_type = rxu::decay_t<S>;
    using func_type = rxu::decay_t<F>;
    using detail_result = decltype(check<for_type, func_type>(0));

    static const bool value = rxu::all_true_type<
        is_subscriber<detail_result>,
        is_subscriber<for_type>,
        std::is_convertible<V, typename rxu::value_type_from<detail_result>::type>>::value;
};

}

namespace operators {

namespace detail {

template<class ResultType, class SourceOperator, class Operator>
struct lift_traits
{
    typedef rxu::decay_t<ResultType> result_value_type;
    typedef rxu::decay_t<SourceOperator> source_operator_type;
    typedef rxu::decay_t<Operator> operator_type;

    typedef typename source_operator_type::value_type source_value_type;
};

template<class ResultType, class SourceOperator, class Operator>
struct lift_operator : public operator_base<typename lift_traits<ResultType, SourceOperator, Operator>::result_value_type>
{
    typedef lift_traits<ResultType, SourceOperator, Operator> traits;
    typedef typename traits::source_operator_type source_operator_type;
    typedef typename traits::operator_type operator_type;
    source_operator_type source;
    operator_type chain;

    lift_operator(source_operator_type s, operator_type op)
        : source(std::move(s))
        , chain(std::move(op))
    {
    }
    template<class Subscriber>
    void on_subscribe(Subscriber o) const {
        auto lifted = chain(std::move(o));
        trace_activity().lift_enter(source, chain, o, lifted);
        source.on_subscribe(std::move(lifted));
        trace_activity().lift_return(source, chain);
    }
};

template<class ResultType, class Operator>
class lift_factory
{
    typedef rxu::decay_t<Operator> operator_type;
    operator_type chain;
public:
    lift_factory(operator_type op) : chain(std::move(op)) {}
    template<class Observable>
    auto operator()(const Observable& source)
        -> decltype(source.template lift<ResultType>(chain)) {
        return      source.template lift<ResultType>(chain);
        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, ...>)");
    }
};

}

template<class ResultType, class Operator>
auto lift(Operator&& op)
    ->      detail::lift_factory<ResultType, Operator> {
    return  detail::lift_factory<ResultType, Operator>(std::forward<Operator>(op));
}

}

}

#endif