/** * * @file message_bus.hpp * @author zxw * Copyright 2024, yjrobotics. All rights reserved. * * robotics * */ #pragma once //stl #include #include #include #include //boost #include //robotics #include "function_traits.hpp" #include "message_bus_impl.h" namespace robotics { namespace v3 { class message_bus :boost::noncopyable { public: /** * @brief 构造 */ message_bus() { message_bus_impl_ = message_bus_impl::instance(); } /** * @brief 析构 */ ~message_bus() { } /** * @brief 注册消息 * @tparam _Fn * @param str_topic * @param observer 观察者 * @param f * @return */ template bool bind(const std::string& str_topic, bool observer, _Fn&& f) { auto func = v3::to_function(std::forward<_Fn>(f)); return add(str_topic, observer, std::move(func)); } /** * @brief 注册消息 * @tparam _Fn * @tparam _Obj * @param str_topic * @param observer 观察者 * @param f * @param obj * @return */ template bool bind(const std::string& str_topic, bool observer, _Fn&& f, _Obj&& obj) { auto func = v3::to_function((v3::function_traits<_Fn>::stl_function_type)(std::bind_front(std::forward<_Fn>(f), std::forward<_Obj>(obj)))); return add(str_topic, observer, std::move(func)); } /** * @brief 发送消息 * @param str_topic */ template _Ret invoke(const std::string& str_topic) { using function_type = std::function<_Ret()>; std::string str_msg_type = str_topic + typeid(function_type).name(); auto funcs = message_bus_impl_->find(str_msg_type); if constexpr (!_BCast) { if (std::find_if(funcs.begin(), funcs.end(), [](auto it) {return !it.first; }) == funcs.end()) { throw std::runtime_error("no function binded to topic " + str_topic); } } if constexpr (std::is_same<_Ret, void>::value) { for (auto& fn : funcs) { std::any_cast(fn.second)(); } } else { _Ret result = _Ret{}; for (auto& fn : funcs) { if (!fn.first) { result = std::any_cast(fn.second)(); } else { std::any_cast(fn.second)(); } } return result; } } /** * @brief 发送消息 * @tparam ..._Args * @param str_topic * @param ...args */ template _Ret invoke(const std::string& str_topic, _Args ...args) { using function_type = std::function<_Ret(_Args...)>; std::string str_msg_type = str_topic + typeid(function_type).name(); auto funcs = message_bus_impl_->find(str_msg_type); if constexpr (!_BCast) { if (std::find_if(funcs.begin(), funcs.end(), [](auto it) {return !it.first; }) == funcs.end()) { throw std::runtime_error("no function binded to topic " + str_topic); } } if constexpr(std::is_same<_Ret, void>::value) { for(auto &fn : funcs) { std::any_cast(fn.second)(args...); } } else { _Ret result = _Ret{}; for (auto& fn : funcs) { if (!fn.first) { result = std::any_cast(fn.second)(args...); } else { std::any_cast(fn.second)(args...); } } return result; } } /** * @brief 移除某个主题,需要主题和消息类型 * @tparam ...Args * @param strTopic */ template void remove(const std::string& str_topic) { using function_type = std::function; std::string str_msg_type = str_topic + typeid(function_type).name(); message_bus_impl_->remove(str_msg_type); } private: /** * @brief 单个添加 * @tparam _Fn * @param str_topic * @param f * @return */ template bool add(const std::string& str_topic, bool observer, _Fn&& f) { std::string str_msg_type = str_topic + typeid(f).name(); return message_bus_impl_->bind(str_msg_type, observer, std::forward<_Fn>(f)); } private: message_bus_impl* message_bus_impl_ = nullptr; }; } }