181 lines
8.7 KiB
C++
181 lines
8.7 KiB
C++
#pragma once
|
|
|
|
#include <boost/callable_traits.hpp>
|
|
#include <boost/callable_traits/args.hpp>
|
|
#include <boost/callable_traits/return_type.hpp>
|
|
#include <cstddef>
|
|
#include <stdexcept>
|
|
#include <tuple>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#include "port_base.hpp"
|
|
#include "ports.hpp"
|
|
#include "src/port_types.hpp"
|
|
#include "tuple.hpp"
|
|
|
|
using namespace boost::callable_traits;
|
|
|
|
template <typename...> class Port;
|
|
template <typename... Adapters, typename... Args>
|
|
requires(
|
|
(std::is_same_v<typename Adapters::base_t::callback_type_t::result_type, typename std::tuple_element_t<0, std::tuple<Adapters...>>::base_t::callback_type_t::result_type> &&
|
|
...) &&
|
|
((std::tuple_size_v<args_t<typename Adapters::base_t::callback_type_t::signature_type>> ==
|
|
std::tuple_size_v<args_t<typename std::tuple_element_t<0, std::tuple<Adapters...>>::callback_type_t::signature_type>>) &&
|
|
...))
|
|
|
|
class Port<std::tuple<Adapters...>, std::tuple<Args...>> : public PortBase<std::tuple_element_t<0, std::tuple<return_type_t<typename Adapters::encoder_type_t>...>>> {
|
|
public:
|
|
static constexpr auto callback_args_num = std::tuple_size_v<args_t<typename std::tuple_element_t<0, std::tuple<Adapters...>>::callback_type_t::signature_type>>;
|
|
using this_t = Port<std::tuple<Adapters...>, std::tuple<Args...>>;
|
|
using port_data_type_t = std::tuple_element_t<0, std::tuple<return_type_t<typename Adapters::encoder_type_t>...>>;
|
|
using callback_aargs_t = tp::tuple_tail<args_t<typename std::tuple_element_t<0, std::tuple<Adapters...>>::callback_type_t::signature_type>>::type;
|
|
|
|
Port(enum port_types_e pt, const std::string &name, const std::string &endpoint, zmq::context_t &zmq_ctx, std::tuple<std::unique_ptr<Adapters>...> &&adapters,
|
|
std::tuple<Args...> &&args)
|
|
: PortBase<port_data_type_t>(pt, name, endpoint, zmq_ctx),
|
|
|
|
// Init adapters
|
|
mc_adapters_([&]<size_t... Ids>(std::index_sequence<Ids...>) {
|
|
return std::make_tuple([&]<size_t Idx>() {
|
|
using adapter_type_t = std::remove_cvref_t<decltype(*std::get<Idx>(adapters))>;
|
|
using adapter_input_type_t = std::remove_cvref_t<return_type_t<typename adapter_type_t::decoder_type_t>>;
|
|
using adapter_callback_type_t = std::remove_cvref_t<typename adapter_type_t::base_t::callback_type_t>;
|
|
|
|
// fmt::print("Adding callback: name: {}, namehash: {}, typehash: {}, cbk_typehash: {}, cbk_type: {}\r\n", std::get<Idx>(adapters)->name(),
|
|
// std::hash<std::string>()(std::get<Idx>(adapters)->name()), typeid(adapter_input_type_t).hash_code(), typeid(adapter_callback_type_t).hash_code(),
|
|
// type_name<adapter_callback_type_t>());
|
|
return std::make_tuple(std::get<Idx>(adapters)->name(), std::hash<std::string>()(std::get<Idx>(adapters)->name()), typeid(adapter_input_type_t).hash_code(),
|
|
typeid(adapter_callback_type_t).hash_code(), std::forward<std::unique_ptr<adapter_type_t>>(std::get<Idx>(adapters)));
|
|
}.template operator()<Ids>()...);
|
|
}(std::make_index_sequence<sizeof...(Adapters)>{})) {
|
|
std::apply([&, this](auto &&...args) { init_impl_(pt, zmq_ctx, std::move(endpoint), std::forward<Args>(args)...); }, std::forward<decltype(args)>(args));
|
|
}
|
|
|
|
~Port() override { stop(); }
|
|
|
|
void stop() const override {
|
|
stop__();
|
|
m_impl__->close();
|
|
}
|
|
|
|
inline const auto &adapters() const { return mc_adapters_; }
|
|
|
|
protected:
|
|
void stop__() const override { m_impl__->stop_source().request_stop(); }
|
|
void send__(const std::string &addr, const void *data, size_t size, size_t hash) const override {
|
|
const void *adapter_ptr = nullptr;
|
|
|
|
tp::for_each(mc_adapters_, [&](const auto &e) {
|
|
const auto &[adapter_name, adapter_namehash, adapter_typehash, adapter_cbk_typehash, adapter] = e;
|
|
|
|
if (adapter_typehash == hash) {
|
|
using adapter_in_type_t = std::remove_cvref_t<return_type_t<decltype(adapter->decoder())>>;
|
|
adapter_ptr = &adapter;
|
|
|
|
typename PortImplBase<this_t, PortImplCallback_<callback_aargs_t>>::port_payload_s payload = {
|
|
.typehash = hash,
|
|
.data = {adapter->encoder()(*reinterpret_cast<const adapter_in_type_t *>(data))},
|
|
};
|
|
|
|
msgpack::sbuffer buf;
|
|
msgpack::pack(buf, payload);
|
|
m_impl__->send(addr, buf);
|
|
}
|
|
});
|
|
|
|
if (!adapter_ptr) {
|
|
throw std::runtime_error(fmt::format("No suitable adapter found for type #{}\r\n", hash));
|
|
}
|
|
}
|
|
|
|
void *get_adapter__(const std::string &name, size_t namehash, size_t typehash, size_t cbk_typehash) const override final {
|
|
void *ret = nullptr;
|
|
|
|
tp::for_each(mc_adapters_, [&](auto &a) {
|
|
if (!ret) {
|
|
auto &[adapter_name, adapter_namehash, adapter_typehash, adapter_cbk_typehash, adapter] = a;
|
|
if (adapter_typehash == typehash && adapter_namehash == namehash && adapter_cbk_typehash == cbk_typehash) {
|
|
ret = reinterpret_cast<void *>(adapter.get());
|
|
}
|
|
}
|
|
});
|
|
|
|
if (!ret) {
|
|
throw std::runtime_error(
|
|
fmt::format("No such callback in adapter '{}' in port '{}' (namehash: #{}, typehash: #{}, cbk_typehash: #{})\r\n", name, this->name(), namehash, typehash, cbk_typehash));
|
|
}
|
|
|
|
return ret;
|
|
};
|
|
|
|
private:
|
|
using base_t_ = PortBase<port_data_type_t>;
|
|
using cbk_return_type_t_ = typename std::tuple_element_t<0, std::tuple<Adapters...>>::base_t::callback_type_t::result_type;
|
|
|
|
template <typename...> class PortImplCallback_;
|
|
template <typename... Aargs> class PortImplCallback_<std::tuple<Aargs...>> {
|
|
public:
|
|
PortImplCallback_(const Port *port) : mc_port_(port) {}
|
|
using type_t = std::function<cbk_return_type_t_(const port_data_type_t &, size_t, Aargs &&...)>;
|
|
|
|
cbk_return_type_t_ operator()(const port_data_type_t &data, size_t hash, Aargs &&...callback_args) const {
|
|
std::conditional_t<!std::is_void_v<cbk_return_type_t_>, cbk_return_type_t_, std::false_type> ret;
|
|
|
|
tp::for_each(mc_port_->mc_adapters_, [&](const auto &e) {
|
|
const auto &[adapter_name, adapter_namehash, adapter_typehash, adapter_cbk_typehash, adapter] = e;
|
|
if (adapter_typehash == hash) {
|
|
if constexpr (std::is_void_v<std::invoke_result_t<std::remove_cvref_t<decltype(adapter->callback())>, decltype(adapter->decoder()(data)), Aargs &&...>>) {
|
|
adapter->callback()(adapter->decoder()(data), std::forward<Aargs>(callback_args)...);
|
|
} else {
|
|
ret = adapter->callback()(adapter->decoder()(data), std::forward<Aargs>(callback_args)...);
|
|
}
|
|
}
|
|
});
|
|
|
|
if constexpr (!std::is_void_v<cbk_return_type_t_>) {
|
|
return ret;
|
|
}
|
|
}
|
|
|
|
private:
|
|
const Port *mc_port_;
|
|
};
|
|
|
|
mutable std::unique_ptr<PortImplBase<this_t, PortImplCallback_<callback_aargs_t>>> m_impl__;
|
|
mutable std::tuple<std::tuple<std::string, size_t, size_t, size_t, std::unique_ptr<Adapters>>...> mc_adapters_;
|
|
|
|
template <typename... ImplArgs> void init_impl_(enum port_types_e pt, ImplArgs &&...args) const {
|
|
using enum port_types_e;
|
|
static constexpr auto make_null_impl_pair = []<enum port_types_e port_type>() consteval {
|
|
if constexpr (port_type == UNKNOWN) {
|
|
return std::make_pair(port_type, static_cast<PortImplBase<this_t, PortImplCallback_<callback_aargs_t>> *>(nullptr));
|
|
} else {
|
|
return std::make_pair(port_type, static_cast<PortImpl<port_type, this_t, PortImplCallback_<callback_aargs_t>> *>(nullptr));
|
|
}
|
|
};
|
|
|
|
static constexpr auto impl_map =
|
|
std::make_tuple(make_null_impl_pair.template operator()<UNKNOWN>(), make_null_impl_pair.template operator()<PUB>(), make_null_impl_pair.template operator()<SUB>(),
|
|
make_null_impl_pair.template operator()<REQ>(), make_null_impl_pair.template operator()<REP>(), make_null_impl_pair.template operator()<ROUTER>(),
|
|
make_null_impl_pair.template operator()<DEALER>(), make_null_impl_pair.template operator()<PUSH>(), make_null_impl_pair.template operator()<PULL>(),
|
|
make_null_impl_pair.template operator()<PAIR>());
|
|
|
|
tp::for_each(impl_map, [&](const auto &p) {
|
|
const auto &[type, null_pimpl] = p;
|
|
if (type == pt) {
|
|
using impl_type_t = std::remove_pointer_t<decltype(null_pimpl)>;
|
|
|
|
if constexpr (std::is_constructible_v<impl_type_t, const this_t *, const ImplArgs &..., PortImplCallback_<callback_aargs_t> &&>) {
|
|
m_impl__ = std::make_unique<impl_type_t>(this, std::forward<ImplArgs>(args)..., PortImplCallback_<callback_aargs_t>(this));
|
|
}
|
|
}
|
|
});
|
|
}
|
|
};
|
|
|
|
template <typename... Adapters, typename... Args>
|
|
Port(enum port_types_e, const std::string &, const std::string &, zmq::context_t &, std::tuple<std::unique_ptr<Adapters>...> &&, std::tuple<Args...> &&)
|
|
-> Port<std::tuple<Adapters...>, std::tuple<Args...>>;
|