|
15 | 15 | #ifndef RCLCPP__ANY_SERVICE_CALLBACK_HPP_ |
16 | 16 | #define RCLCPP__ANY_SERVICE_CALLBACK_HPP_ |
17 | 17 |
|
| 18 | +#include <variant> |
18 | 19 | #include <functional> |
19 | 20 | #include <memory> |
20 | 21 | #include <stdexcept> |
21 | 22 | #include <type_traits> |
| 23 | +#include <utility> |
22 | 24 |
|
23 | 25 | #include "rclcpp/function_traits.hpp" |
24 | 26 | #include "rclcpp/visibility_control.hpp" |
|
29 | 31 | namespace rclcpp |
30 | 32 | { |
31 | 33 |
|
32 | | -template<typename ServiceT> |
33 | | -class AnyServiceCallback |
| 34 | +namespace detail |
34 | 35 | { |
35 | | -private: |
36 | | - using SharedPtrCallback = std::function< |
37 | | - void ( |
38 | | - const std::shared_ptr<typename ServiceT::Request>, |
39 | | - std::shared_ptr<typename ServiceT::Response> |
40 | | - )>; |
41 | | - using SharedPtrWithRequestHeaderCallback = std::function< |
42 | | - void ( |
43 | | - const std::shared_ptr<rmw_request_id_t>, |
44 | | - const std::shared_ptr<typename ServiceT::Request>, |
45 | | - std::shared_ptr<typename ServiceT::Response> |
46 | | - )>; |
| 36 | +template<typename T, typename = void> |
| 37 | +struct can_be_nullptr : std::false_type {}; |
| 38 | + |
| 39 | +// Some lambdas define a comparison with nullptr, |
| 40 | +// but we see a warning that they can never be null when using it. |
| 41 | +// We also test if `T &` can be assigned to `nullptr` to avoid the issue. |
| 42 | +template<typename T> |
| 43 | +struct can_be_nullptr<T, std::void_t< |
| 44 | + decltype(std::declval<T>() == nullptr), decltype(std::declval<T &>() = nullptr)>> |
| 45 | + : std::true_type {}; |
| 46 | +} // namespace detail |
47 | 47 |
|
48 | | - SharedPtrCallback shared_ptr_callback_; |
49 | | - SharedPtrWithRequestHeaderCallback shared_ptr_with_request_header_callback_; |
| 48 | +// Forward declare |
| 49 | +template<typename ServiceT> |
| 50 | +class Service; |
50 | 51 |
|
| 52 | +template<typename ServiceT> |
| 53 | +class AnyServiceCallback |
| 54 | +{ |
51 | 55 | public: |
52 | 56 | AnyServiceCallback() |
53 | | - : shared_ptr_callback_(nullptr), shared_ptr_with_request_header_callback_(nullptr) |
| 57 | + : callback_(std::monostate{}) |
54 | 58 | {} |
55 | 59 |
|
56 | | - AnyServiceCallback(const AnyServiceCallback &) = default; |
57 | | - |
58 | 60 | template< |
59 | 61 | typename CallbackT, |
60 | | - typename std::enable_if< |
61 | | - rclcpp::function_traits::same_arguments< |
62 | | - CallbackT, |
63 | | - SharedPtrCallback |
64 | | - >::value |
65 | | - >::type * = nullptr |
66 | | - > |
67 | | - void set(CallbackT callback) |
| 62 | + typename std::enable_if_t<!detail::can_be_nullptr<CallbackT>::value, int> = 0> |
| 63 | + void |
| 64 | + set(CallbackT && callback) |
68 | 65 | { |
69 | | - shared_ptr_callback_ = callback; |
| 66 | + callback_ = std::forward<CallbackT>(callback); |
70 | 67 | } |
71 | 68 |
|
72 | 69 | template< |
73 | 70 | typename CallbackT, |
74 | | - typename std::enable_if< |
75 | | - rclcpp::function_traits::same_arguments< |
76 | | - CallbackT, |
77 | | - SharedPtrWithRequestHeaderCallback |
78 | | - >::value |
79 | | - >::type * = nullptr |
80 | | - > |
81 | | - void set(CallbackT callback) |
| 71 | + typename std::enable_if_t<detail::can_be_nullptr<CallbackT>::value, int> = 0> |
| 72 | + void |
| 73 | + set(CallbackT && callback) |
82 | 74 | { |
83 | | - shared_ptr_with_request_header_callback_ = callback; |
| 75 | + if (!callback) { |
| 76 | + throw std::invalid_argument("AnyServiceCallback::set(): callback cannot be nullptr"); |
| 77 | + } |
| 78 | + callback_ = std::forward<CallbackT>(callback); |
84 | 79 | } |
85 | 80 |
|
86 | | - void dispatch( |
87 | | - std::shared_ptr<rmw_request_id_t> request_header, |
88 | | - std::shared_ptr<typename ServiceT::Request> request, |
89 | | - std::shared_ptr<typename ServiceT::Response> response) |
| 81 | + // template<typename Allocator = std::allocator<typename ServiceT::Response>> |
| 82 | + std::shared_ptr<typename ServiceT::Response> |
| 83 | + dispatch( |
| 84 | + const std::shared_ptr<rclcpp::Service<ServiceT>> & service_handle, |
| 85 | + const std::shared_ptr<rmw_request_id_t> & request_header, |
| 86 | + std::shared_ptr<typename ServiceT::Request> request) |
90 | 87 | { |
91 | 88 | TRACEPOINT(callback_start, static_cast<const void *>(this), false); |
92 | | - if (shared_ptr_callback_ != nullptr) { |
| 89 | + if (std::holds_alternative<std::monostate>(callback_)) { |
| 90 | + // TODO(ivanpauno): Remove the set method, and force the users of this class |
| 91 | + // to pass a callback at construnciton. |
| 92 | + throw std::runtime_error{"unexpected request without any callback set"}; |
| 93 | + } |
| 94 | + if (std::holds_alternative<SharedPtrDeferResponseCallback>(callback_)) { |
| 95 | + const auto & cb = std::get<SharedPtrDeferResponseCallback>(callback_); |
| 96 | + cb(request_header, std::move(request)); |
| 97 | + return nullptr; |
| 98 | + } |
| 99 | + if (std::holds_alternative<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_)) { |
| 100 | + const auto & cb = std::get<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_); |
| 101 | + cb(service_handle, request_header, std::move(request)); |
| 102 | + return nullptr; |
| 103 | + } |
| 104 | + // auto response = allocate_shared<typename ServiceT::Response, Allocator>(); |
| 105 | + auto response = std::make_shared<typename ServiceT::Response>(); |
| 106 | + if (std::holds_alternative<SharedPtrCallback>(callback_)) { |
93 | 107 | (void)request_header; |
94 | | - shared_ptr_callback_(request, response); |
95 | | - } else if (shared_ptr_with_request_header_callback_ != nullptr) { |
96 | | - shared_ptr_with_request_header_callback_(request_header, request, response); |
97 | | - } else { |
98 | | - throw std::runtime_error("unexpected request without any callback set"); |
| 108 | + const auto & cb = std::get<SharedPtrCallback>(callback_); |
| 109 | + cb(std::move(request), response); |
| 110 | + } else if (std::holds_alternative<SharedPtrWithRequestHeaderCallback>(callback_)) { |
| 111 | + const auto & cb = std::get<SharedPtrWithRequestHeaderCallback>(callback_); |
| 112 | + cb(request_header, std::move(request), response); |
99 | 113 | } |
100 | 114 | TRACEPOINT(callback_end, static_cast<const void *>(this)); |
| 115 | + return response; |
101 | 116 | } |
102 | 117 |
|
103 | 118 | void register_callback_for_tracing() |
104 | 119 | { |
105 | 120 | #ifndef TRACETOOLS_DISABLED |
106 | | - if (shared_ptr_callback_) { |
107 | | - TRACEPOINT( |
108 | | - rclcpp_callback_register, |
109 | | - static_cast<const void *>(this), |
110 | | - tracetools::get_symbol(shared_ptr_callback_)); |
111 | | - } else if (shared_ptr_with_request_header_callback_) { |
112 | | - TRACEPOINT( |
113 | | - rclcpp_callback_register, |
114 | | - static_cast<const void *>(this), |
115 | | - tracetools::get_symbol(shared_ptr_with_request_header_callback_)); |
116 | | - } |
| 121 | + std::visit( |
| 122 | + [this](auto && arg) { |
| 123 | + TRACEPOINT( |
| 124 | + rclcpp_callback_register, |
| 125 | + static_cast<const void *>(this), |
| 126 | + tracetools::get_symbol(arg)); |
| 127 | + }, callback_); |
117 | 128 | #endif // TRACETOOLS_DISABLED |
118 | 129 | } |
| 130 | + |
| 131 | +private: |
| 132 | + using SharedPtrCallback = std::function< |
| 133 | + void ( |
| 134 | + std::shared_ptr<typename ServiceT::Request>, |
| 135 | + std::shared_ptr<typename ServiceT::Response> |
| 136 | + )>; |
| 137 | + using SharedPtrWithRequestHeaderCallback = std::function< |
| 138 | + void ( |
| 139 | + std::shared_ptr<rmw_request_id_t>, |
| 140 | + std::shared_ptr<typename ServiceT::Request>, |
| 141 | + std::shared_ptr<typename ServiceT::Response> |
| 142 | + )>; |
| 143 | + using SharedPtrDeferResponseCallback = std::function< |
| 144 | + void ( |
| 145 | + std::shared_ptr<rmw_request_id_t>, |
| 146 | + std::shared_ptr<typename ServiceT::Request> |
| 147 | + )>; |
| 148 | + using SharedPtrDeferResponseCallbackWithServiceHandle = std::function< |
| 149 | + void ( |
| 150 | + std::shared_ptr<rclcpp::Service<ServiceT>>, |
| 151 | + std::shared_ptr<rmw_request_id_t>, |
| 152 | + std::shared_ptr<typename ServiceT::Request> |
| 153 | + )>; |
| 154 | + |
| 155 | + std::variant< |
| 156 | + std::monostate, |
| 157 | + SharedPtrCallback, |
| 158 | + SharedPtrWithRequestHeaderCallback, |
| 159 | + SharedPtrDeferResponseCallback, |
| 160 | + SharedPtrDeferResponseCallbackWithServiceHandle> callback_; |
119 | 161 | }; |
120 | 162 |
|
121 | 163 | } // namespace rclcpp |
|
0 commit comments