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-map.hpp
      6 
      7     \brief For each item from this observable use Selector to produce an item to emit from the new observable that is returned.
      8 
      9     \tparam Selector the type of the transforming function
     10 
     11     \param s the selector function
     12 
     13     \return  Observable that emits the items from the source observable, transformed by the specified function.
     14 
     15     \sample
     16     \snippet map.cpp map sample
     17     \snippet output.txt map sample
     18 */
     19 
     20 #if !defined(RXCPP_OPERATORS_RX_MAP_HPP)
     21 #define RXCPP_OPERATORS_RX_MAP_HPP
     22 
     23 #include "../rx-includes.hpp"
     24 
     25 namespace rxcpp {
     26 
     27 namespace operators {
     28 
     29 namespace detail {
     30 
     31 template<class... AN>
     32 struct map_invalid_arguments {};
     33 
     34 template<class... AN>
     35 struct map_invalid : public rxo::operator_base<map_invalid_arguments<AN...>> {
     36     using type = observable<map_invalid_arguments<AN...>, map_invalid<AN...>>;
     37 };
     38 template<class... AN>
     39 using map_invalid_t = typename map_invalid<AN...>::type;
     40 
     41 template<class T, class Selector>
     42 struct map
     43 {
     44     typedef rxu::decay_t<T> source_value_type;
     45     typedef rxu::decay_t<Selector> select_type;
     46     typedef decltype((*(select_type*)nullptr)(*(source_value_type*)nullptr)) value_type;
     47     select_type selector;
     48 
     49     map(select_type s)
     50         : selector(std::move(s))
     51     {
     52     }
     53 
     54     template<class Subscriber>
     55     struct map_observer
     56     {
     57         typedef map_observer<Subscriber> this_type;
     58         typedef decltype((*(select_type*)nullptr)(*(source_value_type*)nullptr)) value_type;
     59         typedef rxu::decay_t<Subscriber> dest_type;
     60         typedef observer<source_value_type, this_type> observer_type;
     61         dest_type dest;
     62         mutable select_type selector;
     63 
     64         map_observer(dest_type d, select_type s)
     65             : dest(std::move(d))
     66             , selector(std::move(s))
     67         {
     68         }
     69         template<class Value>
     70         void on_next(Value&& v) const {
     71             auto selected = on_exception(
     72                 [&](){
     73                     return this->selector(std::forward<Value>(v));},
     74                 dest);
     75             if (selected.empty()) {
     76                 return;
     77             }
     78             dest.on_next(std::move(selected.get()));
     79         }
     80         void on_error(rxu::error_ptr e) const {
     81             dest.on_error(e);
     82         }
     83         void on_completed() const {
     84             dest.on_completed();
     85         }
     86 
     87         static subscriber<source_value_type, observer_type> make(dest_type d, select_type s) {
     88             auto cs = d.get_subscription();
     89             return make_subscriber<source_value_type>(std::move(cs), observer_type(this_type(std::move(d), std::move(s))));
     90         }
     91     };
     92 
     93     template<class Subscriber>
     94     auto operator()(Subscriber dest) const
     95         -> decltype(map_observer<Subscriber>::make(std::move(dest), selector)) {
     96         return      map_observer<Subscriber>::make(std::move(dest), selector);
     97     }
     98 };
     99 
    100 }
    101 
    102 /*! @copydoc rx-map.hpp
    103 */
    104 template<class... AN>
    105 auto map(AN&&... an)
    106     -> operator_factory<map_tag, AN...> {
    107     return operator_factory<map_tag, AN...>(std::make_tuple(std::forward<AN>(an)...));
    108 }
    109 
    110 /*! @copydoc rx-map.hpp
    111 */
    112 template<class... AN>
    113 auto transform(AN&&... an)
    114     -> operator_factory<map_tag, AN...> {
    115     return operator_factory<map_tag, AN...>(std::make_tuple(std::forward<AN>(an)...));
    116 }
    117 
    118 }
    119 
    120 template<>
    121 struct member_overload<map_tag>
    122 {
    123     template<class Observable, class Selector,
    124         class Enabled = rxu::enable_if_all_true_type_t<
    125             is_observable<Observable>>,
    126         class ResolvedSelector = rxu::decay_t<Selector>,
    127         class SourceValue = rxu::value_type_t<Observable>,
    128         class Map = rxo::detail::map<SourceValue, ResolvedSelector>,
    129         class Value = rxu::value_type_t<Map>>
    130     static auto member(Observable&& o, Selector&& s)
    131         -> decltype(o.template lift<Value>(Map(std::forward<Selector>(s)))) {
    132         return      o.template lift<Value>(Map(std::forward<Selector>(s)));
    133     }
    134 
    135     template<class... AN>
    136     static operators::detail::map_invalid_t<AN...> member(const AN...) {
    137         std::terminate();
    138         return {};
    139         static_assert(sizeof...(AN) == 10000, "map takes Selector");
    140     }
    141 };
    142 
    143 }
    144 
    145 #endif
    146