diff --git a/src/rpp/rpp/observables/connectable_observable.hpp b/src/rpp/rpp/observables/connectable_observable.hpp index 567afeebe..557699e4b 100644 --- a/src/rpp/rpp/observables/connectable_observable.hpp +++ b/src/rpp/rpp/observables/connectable_observable.hpp @@ -130,28 +130,40 @@ namespace rpp details::ref_count_on_subscribe_t>>{*this}; } - template Op> + template auto operator|(Op&& op) const & { - return std::forward(op)(*this); + if constexpr (std::invocable, const connectable_observable&>) + { + static_assert(rpp::constraint::observable, const connectable_observable&>>, "Result of Op should be observable"); + return std::forward(op)(*this); + } + else + return static_cast(*this) | std::forward(op); } - template Op> + template auto operator|(Op&& op)&& { - return std::forward(op)(std::move(*this)); + if constexpr (std::invocable, connectable_observable&&>) + { + static_assert(rpp::constraint::observable, connectable_observable&&>>, "Result of Op should be observable"); + return std::forward(op)(std::move(*this)); + } + else + return static_cast(*this) | std::forward(op); } template - decltype(std::declval() | std::declval()) operator|(Op&& op) const & + auto pipe(Op && op) const & { - return static_cast(*this) | std::forward(op); + return *this | std::forward(op); } template - decltype(std::declval() | std::declval()) operator|(Op&& op)&& + auto pipe(Op && op)&& { - return static_cast(*this) | std::forward(op); + return std::move(*this) | std::forward(op); } private: diff --git a/src/rpp/rpp/observables/details/chain_strategy.hpp b/src/rpp/rpp/observables/details/chain_strategy.hpp index bf6eb3b6b..0d2d1948f 100644 --- a/src/rpp/rpp/observables/details/chain_strategy.hpp +++ b/src/rpp/rpp/observables/details/chain_strategy.hpp @@ -24,6 +24,8 @@ namespace rpp::details::observables using operator_traits = typename TStrategy::template operator_traits; + static_assert(rpp::constraint::operator_chain); + public: using expected_disposable_strategy = deduce_updated_disposable_strategy; using value_type = typename operator_traits::result_type; diff --git a/src/rpp/rpp/observables/fwd.hpp b/src/rpp/rpp/observables/fwd.hpp index 8b4eabe15..6cd897baf 100644 --- a/src/rpp/rpp/observables/fwd.hpp +++ b/src/rpp/rpp/observables/fwd.hpp @@ -79,44 +79,40 @@ namespace rpp::constraint template concept observable_of_type = observable && std::same_as, std::decay_t>; - template - concept operator_observable_transform = requires(const Op& op, TObs obs) { - { - op(static_cast(obs)) - } -> rpp::constraint::observable; - }; - - template - concept operator_base = requires(const Op& op) { typename std::decay_t::template operator_traits; } && details::observables::constraint::disposable_strategy, typename details::observables::chain>::expected_disposable_strategy>>; + template + concept observables_of_same_type = rpp::constraint::observable && (rpp::constraint::observable && ...) && (std::same_as, rpp::utils::extract_observable_type_t> && ...); template - concept operator_subscribe = operator_base && requires(const Op& op, rpp::details::observers::fake_observer::template operator_traits::result_type>&& observer, const details::observables::chain>& chain) { + concept operator_subscribe = requires(const Op& op, rpp::details::observers::fake_observer::template operator_traits::result_type>&& observer, const details::observables::chain>& chain) { { op.subscribe(std::move(observer), chain) }; }; template - concept operator_lift = operator_base && requires(const Op& op, rpp::details::observers::fake_observer::template operator_traits::result_type>&& observer) { + concept operator_lift = requires(const Op& op, rpp::details::observers::fake_observer::template operator_traits::result_type>&& observer) { { op.template lift(std::move(observer)) } -> rpp::constraint::observer_of_type; }; template - concept operator_lift_with_disposable_strategy = operator_base && requires(const Op& op, rpp::details::observers::fake_observer::template operator_traits::result_type>&& observer) { + concept operator_lift_with_disposable_strategy = requires(const Op& op, rpp::details::observers::fake_observer::template operator_traits::result_type>&& observer) { { op.template lift_with_disposable_strategy(std::move(observer)) } -> rpp::constraint::observer_of_type; }; template - concept operator_chain = operator_base, Type> - && requires { typename std::decay_t::template operator_traits::result_type; } - && (operator_subscribe, Type> || operator_lift, Type> || operator_lift_with_disposable_strategy, Type, DisposableStrategy>); + concept operator_chain = + requires() { + typename std::decay_t::template operator_traits; + typename std::decay_t::template operator_traits::result_type; + } + && details::observables::constraint::disposable_strategy, + typename details::observables::chain>::expected_disposable_strategy>> + && (operator_subscribe, Type> || operator_lift, Type> || operator_lift_with_disposable_strategy, Type, DisposableStrategy>); - template - concept observables_of_same_type = rpp::constraint::observable && (rpp::constraint::observable && ...) && (std::same_as, rpp::utils::extract_observable_type_t> && ...); } // namespace rpp::constraint namespace rpp @@ -133,8 +129,3 @@ namespace rpp template... Observables> class variant_observable; } // namespace rpp - - -#define RPP_CHECK_IF_TRAIT_ASSERTS_SATISFIED(Op, Type) \ - /* operator_traits can be instantiated if all inner static_asserts are fine*/ \ - if constexpr (requires { { typename std::decay_t::template operator_traits{}}; }) diff --git a/src/rpp/rpp/observables/observable.hpp b/src/rpp/rpp/observables/observable.hpp index 6d3d6ca29..a0a0daea7 100644 --- a/src/rpp/rpp/observables/observable.hpp +++ b/src/rpp/rpp/observables/observable.hpp @@ -310,42 +310,41 @@ namespace rpp */ auto as_dynamic() && { return rpp::dynamic_observable{std::move(*this)}; } - template Op> - auto operator|(Op&& op) const & + template + requires rpp::utils::is_base_of_v, rpp::operators::details::subscribe_t> + auto operator|(Subscribe&& op) const { - RPP_CHECK_IF_TRAIT_ASSERTS_SATISFIED(Op, Type) - return inner_make_chain_operator(std::forward(op)); + return std::forward(op)(*this); } - template Op> - auto operator|(Op&& op) && - { - RPP_CHECK_IF_TRAIT_ASSERTS_SATISFIED(Op, Type) - return std::move(*this).inner_make_chain_operator(std::forward(op)); - } - - template Op> - auto operator|(Op&& op) const & - { - return std::forward(op)(*this); - } - - template Op> - auto operator|(Op&& op) && - { - return std::forward(op)(std::move(*this)); - } - - template - auto operator|(const rpp::operators::details::subscribe_t& op) const + template + requires (!rpp::utils::is_base_of_v, rpp::operators::details::subscribe_t>) + rpp::constraint::observable auto operator|(Op&& op) const & { - return op(*this); + if constexpr (requires { typename std::decay_t::template operator_traits; }) + { + using result_type = typename std::decay_t::template operator_traits::result_type; + return observable, Strategy>>{std::forward(op), m_strategy}; + } + else + { + return std::forward(op)(*this); + } } - template - auto operator|(rpp::operators::details::subscribe_t&& op) const + template + requires (!rpp::utils::is_base_of_v, rpp::operators::details::subscribe_t>) + rpp::constraint::observable auto operator|(Op&& op) && { - return std::move(op)(*this); + if constexpr (requires { typename std::decay_t::template operator_traits; }) + { + using result_type = typename std::decay_t::template operator_traits::result_type; + return observable, Strategy>>{std::forward(op), std::move(m_strategy)}; + } + else + { + return std::forward(op)(std::move(*this)); + } } template @@ -360,19 +359,6 @@ namespace rpp return std::move(*this) | std::forward(op); } - private: - template Op> - auto inner_make_chain_operator(Op&& op) const & - { - return observable::template operator_traits::result_type, details::observables::make_chain_t, Strategy>>{std::forward(op), m_strategy}; - } - - template Op> - auto inner_make_chain_operator(Op&& op) && - { - return observable::template operator_traits::result_type, details::observables::make_chain_t, Strategy>>{std::forward(op), std::move(m_strategy)}; - } - private: RPP_NO_UNIQUE_ADDRESS Strategy m_strategy; }; diff --git a/src/rpp/rpp/operators/flat_map.hpp b/src/rpp/rpp/operators/flat_map.hpp index 1f7b5266d..8044cd752 100644 --- a/src/rpp/rpp/operators/flat_map.hpp +++ b/src/rpp/rpp/operators/flat_map.hpp @@ -22,20 +22,18 @@ namespace rpp::operators::details RPP_NO_UNIQUE_ADDRESS Fn m_fn; template - requires (std::invocable> - && rpp::constraint::observable>>) auto operator()(TObservable&& observable) const & { + static_assert(std::invocable> && rpp::constraint::observable>>, "fn should return observable"); return std::forward(observable) | rpp::ops::map(m_fn) | rpp::ops::merge(); } template - requires (std::invocable> - && rpp::constraint::observable>>) auto operator()(TObservable&& observable) && { + static_assert(std::invocable> && rpp::constraint::observable>>, "fn should return observable"); return std::forward(observable) | rpp::ops::map(std::move(m_fn)) | rpp::ops::merge(); diff --git a/src/rpp/rpp/operators/multicast.hpp b/src/rpp/rpp/operators/multicast.hpp index 91adc7729..a8526dfd0 100644 --- a/src/rpp/rpp/operators/multicast.hpp +++ b/src/rpp/rpp/operators/multicast.hpp @@ -22,9 +22,9 @@ namespace rpp::operators::details RPP_NO_UNIQUE_ADDRESS Subject m_subject; template - requires std::same_as, rpp::subjects::utils::extract_subject_type_t> auto operator()(TObservable&& observable) const { + static_assert(std::same_as, rpp::subjects::utils::extract_subject_type_t>, "observable and subject should be of same type"); return rpp::connectable_observable, Subject>{std::forward(observable), m_subject}; } }; @@ -33,9 +33,10 @@ namespace rpp::operators::details struct template_multicast_t { template - requires rpp::constraint::subject>> auto operator()(TObservable&& observable) const { + static_assert(rpp::constraint::subject>>, "subject should be constructible with type of observable"); + return rpp::connectable_observable, Subject>>{std::forward(observable), Subject>{}}; diff --git a/src/rpp/rpp/operators/start_with.hpp b/src/rpp/rpp/operators/start_with.hpp index 87a72047a..773c72068 100644 --- a/src/rpp/rpp/operators/start_with.hpp +++ b/src/rpp/rpp/operators/start_with.hpp @@ -23,9 +23,9 @@ namespace rpp::operators::details rpp::utils::tuple observables{}; template - requires rpp::constraint::observables_of_same_type auto operator()(TObservable&& observable) const { + static_assert(rpp::constraint::observables_of_same_type, "observables should be of same type"); return observables.apply(&apply, std::forward(observable)); } @@ -50,9 +50,10 @@ namespace rpp::operators::details { } - template> TObservable> + template auto operator()(TObservable&& observable) const { + static_assert(rpp::constraint::observable_of_type>, "observables should be of same type"); return rpp::source::concat(rpp::source::from_iterable(container, scheduler), std::forward(observable)); } }; diff --git a/src/rpp/rpp/operators/subscribe.hpp b/src/rpp/rpp/operators/subscribe.hpp index 84ca2933d..9f9c75813 100644 --- a/src/rpp/rpp/operators/subscribe.hpp +++ b/src/rpp/rpp/operators/subscribe.hpp @@ -60,16 +60,16 @@ namespace rpp::operators::details } template - requires rpp::constraint::observer_strategy> void operator()(const Observable& observable) const & { + static_assert(rpp::constraint::observer_strategy>, "observer and observable should be of same type"); observable.subscribe(m_observer_strategy); } template - requires rpp::constraint::observer_strategy> void operator()(const Observable& observable) && { + static_assert(rpp::constraint::observer_strategy>, "observer and observable should be of same type"); observable.subscribe(std::move(m_observer_strategy)); } @@ -116,17 +116,17 @@ namespace rpp::operators::details } template - requires rpp::constraint::observer_strategy> rpp::composite_disposable_wrapper operator()(const Observable& observable) const & { + static_assert(rpp::constraint::observer_strategy>, "observer and observable should be of same type"); observable.subscribe(m_disposable, m_observer_strategy); return m_disposable; } template - requires rpp::constraint::observer_strategy> rpp::composite_disposable_wrapper operator()(const Observable& observable) && { + static_assert(rpp::constraint::observer_strategy>, "observer and observable should be of same type"); observable.subscribe(m_disposable, std::move(m_observer_strategy)); return m_disposable; } @@ -150,16 +150,16 @@ namespace rpp::operators::details } template Strategy> - requires std::invocable void operator()(const rpp::observable& observable) && { + static_assert(std::invocable, "OnNext should be suitable for type of observable"); observable.subscribe(std::move(m_on_next), std::move(m_on_error), std::move(m_on_completed)); } template Strategy> - requires std::invocable void operator()(const rpp::observable& observable) const & { + static_assert(std::invocable, "OnNext should be suitable for type of observable"); observable.subscribe(m_on_next, m_on_error, m_on_completed); } @@ -183,17 +183,17 @@ namespace rpp::operators::details } template Strategy> - requires std::invocable rpp::composite_disposable_wrapper operator()(const rpp::observable& observable) && { + static_assert(std::invocable, "OnNext should be suitable for type of observable"); observable.subscribe(m_disposable, std::move(m_on_next), std::move(m_on_error), std::move(m_on_completed)); return std::move(m_disposable); } template Strategy> - requires std::invocable rpp::composite_disposable_wrapper operator()(const rpp::observable& observable) const & { + static_assert(std::invocable, "OnNext should be suitable for type of observable"); observable.subscribe(m_disposable, m_on_next, m_on_error, m_on_completed); return m_disposable; }