/* @file Sink.hpp */ #pragma once #include "AbstractSink.hpp" #include "AbstractSource.hpp" #include "PolyAdapterSink.hpp" #include "xo/reflect/Reflect.hpp" #include "xo/indentlog/print/time.hpp" #include "xo/indentlog/print/tag.hpp" #include "xo/cxxutil/demangle.hpp" #include namespace xo { namespace reactor { /* Sink for events of type T * * inheritance: * ref::Refcount * ^ * isa * | * reactor::AbstractEventProcessor * ^ * isa * | * reactor::AbstractSink * ^ * isa * | * reactor::Sink1 */ template class Sink1 : public AbstractSink { public: using Reflect = reflect::Reflect; using TypeDescr = reflect::TypeDescr; public: /* convenience: convert abstract sink to Sink1*, * or throw */ static ref::rp> require_native(std::string_view caller, ref::rp const & sink) { using xo::scope; using xo::xtag; /* 1. if sink expects events of type T, * make direct connection */ Sink1 * native_sink = nullptr; native_sink = dynamic_cast *>(sink.get()); if (native_sink) return native_sink; /* 2. if sink is polymorphic, * make type-erasing adapter */ if (sink->allow_polymorphic_source()) { #ifdef DEBUG_NOT_USING scope lscope("Sink1::require_native: create PolyAdapterSink"); lscope.log(xtag("caller", caller)); #endif return PolyAdapterSink::make(sink); } if (!native_sink) { #ifdef DEBUG_EVENT_TYPEINFO std::type_info const * sink_parent_typeinfo = sink->parent_typeinfo(); #endif std::size_t src_hashcode = typeid(T).hash_code(); throw std::runtime_error(tostr("Sink1::require_native" ": wanted to sink S, but sink expects T", xtag("caller", caller), xtag("T", sink->sink_ev_type()->canonical_name()), xtag("S", reflect::type_name()), xtag("required_hashcode", typeid(Sink1).hash_code()), xtag("required_name", typeid(Sink1).name()), xtag("src_hashcode", src_hashcode), xtag("sink_hashcode", sink->sink_ev_type()->typeinfo()->hash_code()) #ifdef DEBUG_EVENT_TYPEINFO , xtag("sink_hashcode", sink->item_typeinfo()->hash_code()) , xtag("sink_parent_hashcode", sink_parent_typeinfo->hash_code()) , xtag("sink_parent_name", sink_parent_typeinfo->name()) , xtag("sink.type", sink->self_typename()) , xtag("sink.parent_type", sink->parent_typename()) #endif )); } return native_sink; } /*require_native*/ virtual TypeDescr sink_ev_type() const override { return reflect::Reflect::require(); } /* accept incoming event */ virtual void notify_ev(T const & ev) = 0; /* invoke these when this sink added to, or removed from, a source */ virtual void notify_add_callback() {} virtual void notify_remove_callback() {} // ----- inherited from AbstractSink ----- /* Sink1 only allows source providing T */ virtual bool allow_polymorphic_source() const override { return false; } virtual void attach_source(ref::rp const & src) override { src->attach_sink(this); } /*attach_source*/ virtual void notify_ev_tp(TaggedPtr const & ev_tp) override { using xo::xtag; T * p_ev = ev_tp.recover_native(); if (p_ev) { this->notify_ev(*p_ev); } else { throw std::runtime_error(tostr("Sink1::notify_ev_tp" ": unable to convert ev_tp to T", xtag("ev_tp.type", ev_tp.td()->canonical_name()), xtag("T", reflect::type_name()))); } } /*notify_ev_tp*/ }; /*Sink1*/ /* a sink with no further downstream processors */ template class SinkEndpoint : public Sink1 { public: // ----- Inherited from AbstractEventProcessor ----- virtual std::string const & name() const override { return name_; } virtual void set_name(std::string const & x) override { name_ = x; } virtual void visit_direct_consumers(std::function)> const &) override { /* *this is not an event source */ } /*visit_direct_consumers*/ private: /* reporting name for this sink */ std::string name_; }; /*SinkEndpoint*/ template class SinkToFunction : public SinkEndpoint { public: SinkToFunction(Fn fn) : fn_{std::move(fn)} {} /* NOTE: conservative choice here, could templatize on this */ virtual bool allow_volatile_source() const override { return false; } virtual uint32_t n_in_ev() const override { return n_in_ev_; } virtual void notify_ev(T const & ev) override { ++(this->n_in_ev_); fn_(ev); } /*notify_ev*/ virtual void display(std::ostream & os) const override { using xo::xtag; os << "name()) << xtag("n_in_ev", this->n_in_ev()) << ">"; } /*display*/ private: Fn fn_; /* counts lifetime #of incoming events (see .notify_ev()) */ uint32_t n_in_ev_ = 0; }; /*SinkToFunction*/ /* sink that prints to console */ template class SinkToConsole : public SinkEndpoint { public: SinkToConsole() {} virtual bool allow_volatile_source() const override { return true; } virtual uint32_t n_in_ev() const override { return n_in_ev_; } virtual void notify_ev(T const & ev) override { //using logutil::operator<<; ++(this->n_in_ev_); std::cout << ev << std::endl; } /*notify_ev*/ virtual void display(std::ostream & os) const override { using xo::xtag; os << "name()) << xtag("n_in_ev", this->n_in_ev()) << ">"; } /*display*/ private: /* reporting name for this sink */ std::string name_; /* counts lifetime #of incoming events (see .notify_ev()) */ uint32_t n_in_ev_ = 0; }; /*SinkToConsole*/ #ifdef NOT_USING class TemporaryTest { public: static ref::rp>> realization_printer(); }; /*TemporaryTest*/ #endif } /*namespace reactor*/ } /*namespace xo*/ /* end Sink.hpp */