// Copyright Sebastian Jeckel 2014. // Distributed under the Boost Software License, Version 1.0. // (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #pragma once #include "react/detail/Defs.h" #include #include #include #include #include "Observer.h" #include "react/detail/ReactiveBase.h" #include "react/detail/ReactiveDomain.h" #include "react/detail/graph/EventStreamNodes.h" /*****************************************/ REACT_BEGIN /*****************************************/ enum class EventToken { token }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// Events /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename E = EventToken > class Events : public Reactive> { protected: using NodeT = REACT_IMPL::EventStreamNode; public: using ValueT = E; Events() : Reactive() { } explicit Events(const std::shared_ptr& ptr) : Reactive(ptr) { } template Events Filter(F&& f) { return react::Filter(*this, std::forward(f)); } template Events Transform(F&& f) { return react::Transform(*this, std::forward(f)); } template Observer Observe(F&& f) { return react::Observe(*this, std::forward(f)); } }; /******************************************/ REACT_END /******************************************/ /***************************************/ REACT_IMPL_BEGIN /**************************************/ template bool Equals(const Events& lhs, const Events& rhs) { return lhs.Equals(rhs); } /****************************************/ REACT_IMPL_END /***************************************/ /*****************************************/ REACT_BEGIN /*****************************************/ /////////////////////////////////////////////////////////////////////////////////////////////////// /// Eventsource /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename E = EventToken > class EventSource : public Events { private: using NodeT = REACT_IMPL::EventSourceNode; public: EventSource() : Events() { } explicit EventSource(const std::shared_ptr& ptr) : Events(ptr) { } template void Emit(V&& v) const { D::AddInput(*std::static_pointer_cast(ptr_), std::forward(v)); } template ::value>::type> void Emit() const { Emit(EventToken::token); } const EventSource& operator<<(const E& e) const { Emit(e); return *this; } }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// TempEvents /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename E, typename TOp > class TempEvents : public Events { protected: using NodeT = REACT_IMPL::EventOpNode; public: TempEvents() : Events() {} explicit TempEvents(const std::shared_ptr& ptr) : Events(ptr) {} explicit TempEvents(std::shared_ptr&& ptr) : Events(std::move(ptr)) {} TOp StealOp() { return std::move(std::static_pointer_cast(ptr_)->StealOp()); } }; /////////////////////////////////////////////////////////////////////////////////////////////////// /// MakeEventSource /////////////////////////////////////////////////////////////////////////////////////////////////// template auto MakeEventSource() -> EventSource { return EventSource( std::make_shared>()); } template auto MakeEventSource() -> EventSource { return EventSource( std::make_shared>()); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Merge /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename TArg1, typename ... TArgs, typename E = TArg1, typename TOp = REACT_IMPL::EventMergeOp, REACT_IMPL::EventStreamNodePtr ...> > auto Merge(const Events& arg1, const Events& ... args) -> TempEvents { static_assert(sizeof...(TArgs) > 0, "react::Merge requires at least 2 arguments."); return TempEvents( std::make_shared>( arg1.GetPtr(), args.GetPtr() ...)); } template < typename TLeftEvents, typename TRightEvents, typename D = TLeftEvents::DomainT, typename TLeftVal = TLeftEvents::ValueT, typename TRightVal = TRightEvents::ValueT, typename E = TLeftVal, typename TOp = REACT_IMPL::EventMergeOp, REACT_IMPL::EventStreamNodePtr>, class = std::enable_if< IsEvent::value>::type, class = std::enable_if< IsEvent::value>::type > auto operator|(const TLeftEvents& lhs, const TRightEvents& rhs) -> TempEvents { return TempEvents( std::make_shared>( lhs.GetPtr(), rhs.GetPtr())); } template < typename D, typename TLeftVal, typename TLeftOp, typename TRightVal, typename TRightOp, typename E = TLeftVal, typename TOp = REACT_IMPL::EventMergeOp > auto operator|(TempEvents&& lhs, TempEvents&& rhs) -> TempEvents { return TempEvents( std::make_shared>( lhs.StealOp(), rhs.StealOp())); } template < typename D, typename TLeftVal, typename TLeftOp, typename TRightEvents, typename TRightVal = TRightEvents::ValueT, typename E = TLeftVal, typename TOp = REACT_IMPL::EventMergeOp>, class = std::enable_if< IsEvent::value>::type > auto operator|(TempEvents&& lhs, const TRightEvents& rhs) -> TempEvents { return TempEvents( std::make_shared>( lhs.StealOp(), rhs.GetPtr())); } template < typename TLeftEvents, typename D, typename TRightVal, typename TRightOp, typename TLeftVal = TLeftEvents::ValueT, typename E = TLeftVal, typename TOp = REACT_IMPL::EventMergeOp, TRightOp>, class = std::enable_if< IsEvent::value>::type > auto operator|(const TLeftEvents& lhs, TempEvents&& rhs) -> TempEvents { return TempEvents( std::make_shared>( lhs.GetPtr(), rhs.StealOp())); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Filter /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename E, typename FIn, typename F = std::decay::type, typename TOp = REACT_IMPL::EventFilterOp> > auto Filter(const Events& src, FIn&& filter) -> TempEvents { return TempEvents( std::make_shared>( std::forward(filter), src.GetPtr())); } template < typename D, typename E, typename TOpIn, typename FIn, typename F = std::decay::type, typename TOpOut = REACT_IMPL::EventFilterOp > auto Filter(TempEvents&& src, FIn&& filter) -> TempEvents { return TempEvents( std::make_shared>( std::forward(filter), src.StealOp())); } template < typename TEvents, typename F, class = std::enable_if< IsEvent::value>::type > auto operator&(TEvents&& src, F&& filter) -> decltype(Filter(std::forward(src), std::forward(filter))) { return Filter(std::forward(src), std::forward(filter)); } /////////////////////////////////////////////////////////////////////////////////////////////////// /// Transform /////////////////////////////////////////////////////////////////////////////////////////////////// template < typename D, typename E, typename FIn, typename F = std::decay::type, typename TOp = REACT_IMPL::EventTransformOp> > auto Transform(const Events& src, FIn&& func) -> TempEvents { return TempEvents( std::make_shared>( std::forward(func), src.GetPtr())); } template < typename D, typename E, typename TOpIn, typename FIn, typename F = std::decay::type, typename TOpOut = REACT_IMPL::EventTransformOp > auto Transform(TempEvents&& src, FIn&& func) -> TempEvents { return TempEvents( std::make_shared>( std::forward(func), src.StealOp())); } template < typename TEvents, typename F, class = std::enable_if< IsEvent::value>::type > auto operator->*(TEvents&& src, F&& func) -> decltype(Transform(std::forward(src), std::forward(func))) { return Transform(std::forward(src), std::forward(func)); } /******************************************/ REACT_END /******************************************/