// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information. #pragma once /*! \file rx-tap.hpp \brief inspect calls to on_next, on_error and on_completed. \tparam MakeObserverArgN... these args are passed to make_observer. \param an these args are passed to make_observer. \return Observable that emits the same items as the source observable to both the subscriber and the observer. \note If an on_error method is not supplied the observer will ignore errors rather than call std::terminate() \sample \snippet tap.cpp tap sample \snippet output.txt tap sample If the source observable generates an error, the observer passed to tap is called: \snippet tap.cpp error tap sample \snippet output.txt error tap sample */ #if !defined(RXCPP_OPERATORS_RX_TAP_HPP) #define RXCPP_OPERATORS_RX_TAP_HPP #include "../rx-includes.hpp" namespace rxcpp { namespace operators { namespace detail { template struct tap_invalid_arguments {}; template struct tap_invalid : public rxo::operator_base> { using type = observable, tap_invalid>; }; template using tap_invalid_t = typename tap_invalid::type; template struct tap_observer_factory; template struct tap_observer_factory> { using source_value_type = rxu::decay_t; using out_type = decltype(make_observer(*((ArgN*)nullptr)...)); auto operator()(ArgN&&... an) -> out_type const { return make_observer(std::forward(an)...); } }; template> struct tap { using source_value_type = rxu::decay_t; using args_type = rxu::decay_t; using factory_type = Factory; using out_type = typename factory_type::out_type; out_type out; tap(args_type a) : out(rxu::apply(std::move(a), factory_type())) { } template struct tap_observer { using this_type = tap_observer; using value_type = source_value_type; using dest_type = rxu::decay_t; using factory_type = Factory; using out_type = typename factory_type::out_type; using observer_type = observer; dest_type dest; out_type out; tap_observer(dest_type d, out_type o) : dest(std::move(d)) , out(std::move(o)) { } void on_next(source_value_type v) const { out.on_next(v); dest.on_next(v); } void on_error(rxu::error_ptr e) const { out.on_error(e); dest.on_error(e); } void on_completed() const { out.on_completed(); dest.on_completed(); } static subscriber> make(dest_type d, out_type o) { return make_subscriber(d, this_type(d, std::move(o))); } }; template auto operator()(Subscriber dest) const -> decltype(tap_observer::make(std::move(dest), out)) { return tap_observer::make(std::move(dest), out); } }; } /*! @copydoc rx-tap.hpp */ template auto tap(AN&&... an) -> operator_factory { return operator_factory(std::make_tuple(std::forward(an)...)); } } template<> struct member_overload { template>, class SourceValue = rxu::value_type_t, class Tap = rxo::detail::tap...>>> static auto member(Observable&& o, MakeObserverArgN&&... an) -> decltype(o.template lift(Tap(std::make_tuple(std::forward(an)...)))) { return o.template lift(Tap(std::make_tuple(std::forward(an)...))); } template static operators::detail::tap_invalid_t member(const AN&...) { std::terminate(); return {}; static_assert(sizeof...(AN) == 10000, "tap takes (MakeObserverArgN...)"); } }; } #endif