ROS 2 rclcpp + rcl - rolling  rolling-20536064
ROS 2 C++ Client Library with ROS Client Library
any_service_callback.hpp
1 // Copyright 2015 Open Source Robotics Foundation, Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 #ifndef RCLCPP__ANY_SERVICE_CALLBACK_HPP_
16 #define RCLCPP__ANY_SERVICE_CALLBACK_HPP_
17 
18 #include <variant>
19 #include <functional>
20 #include <memory>
21 #include <stdexcept>
22 #include <type_traits>
23 #include <utility>
24 
25 #include "rclcpp/function_traits.hpp"
26 #include "rmw/types.h"
27 #include "tracetools/tracetools.h"
28 #include "tracetools/utils.hpp"
29 
30 namespace rclcpp
31 {
32 
33 namespace detail
34 {
35 template<typename T, typename = void>
36 struct can_be_nullptr : std::false_type {};
37 
38 // Some lambdas define a comparison with nullptr,
39 // but we see a warning that they can never be null when using it.
40 // We also test if `T &` can be assigned to `nullptr` to avoid the issue.
41 template<typename T>
42 #ifdef __QNXNTO__
43 struct can_be_nullptr<T, std::void_t<
44  decltype(std::declval<T>() == nullptr)>>: std::true_type {};
45 #else
46 struct can_be_nullptr<T, std::void_t<
47  decltype(std::declval<T>() == nullptr), decltype(std::declval<T &>() = nullptr)>>
48  : std::true_type {};
49 #endif
50 } // namespace detail
51 
52 // Forward declare
53 template<typename ServiceT>
54 class Service;
55 
56 template<typename ServiceT>
58 {
59 public:
61  : callback_(std::monostate{})
62  {}
63 
64  template<
65  typename CallbackT,
66  typename std::enable_if_t<!detail::can_be_nullptr<CallbackT>::value, int> = 0>
67  void
68  set(CallbackT && callback)
69  {
70  // Workaround Windows issue with std::bind
71  if constexpr (
73  CallbackT,
74  SharedPtrCallback
75  >::value)
76  {
77  callback_.template emplace<SharedPtrCallback>(callback);
78  } else if constexpr ( // NOLINT, can't satisfy both cpplint and uncrustify
80  CallbackT,
81  SharedPtrWithRequestHeaderCallback
82  >::value)
83  {
84  callback_.template emplace<SharedPtrWithRequestHeaderCallback>(callback);
85  } else if constexpr ( // NOLINT
87  CallbackT,
88  SharedPtrDeferResponseCallback
89  >::value)
90  {
91  callback_.template emplace<SharedPtrDeferResponseCallback>(callback);
92  } else if constexpr ( // NOLINT
94  CallbackT,
95  SharedPtrDeferResponseCallbackWithServiceHandle
96  >::value)
97  {
98  callback_.template emplace<SharedPtrDeferResponseCallbackWithServiceHandle>(callback);
99  } else {
100  // the else clause is not needed, but anyways we should only be doing this instead
101  // of all the above workaround ...
102  callback_ = std::forward<CallbackT>(callback);
103  }
104  }
105 
106  template<
107  typename CallbackT,
108  typename std::enable_if_t<detail::can_be_nullptr<CallbackT>::value, int> = 0>
109  void
110  set(CallbackT && callback)
111  {
112  if (!callback) {
113  throw std::invalid_argument("AnyServiceCallback::set(): callback cannot be nullptr");
114  }
115  // Workaround Windows issue with std::bind
116  if constexpr (
118  CallbackT,
119  SharedPtrCallback
120  >::value)
121  {
122  callback_.template emplace<SharedPtrCallback>(callback);
123  } else if constexpr ( // NOLINT
125  CallbackT,
126  SharedPtrWithRequestHeaderCallback
127  >::value)
128  {
129  callback_.template emplace<SharedPtrWithRequestHeaderCallback>(callback);
130  } else if constexpr ( // NOLINT
132  CallbackT,
133  SharedPtrDeferResponseCallback
134  >::value)
135  {
136  callback_.template emplace<SharedPtrDeferResponseCallback>(callback);
137  } else if constexpr ( // NOLINT
139  CallbackT,
140  SharedPtrDeferResponseCallbackWithServiceHandle
141  >::value)
142  {
143  callback_.template emplace<SharedPtrDeferResponseCallbackWithServiceHandle>(callback);
144  } else {
145  // the else clause is not needed, but anyways we should only be doing this instead
146  // of all the above workaround ...
147  callback_ = std::forward<CallbackT>(callback);
148  }
149  }
150 
151  // template<typename Allocator = std::allocator<typename ServiceT::Response>>
152  std::shared_ptr<typename ServiceT::Response>
153  dispatch(
154  const std::shared_ptr<rclcpp::Service<ServiceT>> & service_handle,
155  const std::shared_ptr<rmw_request_id_t> & request_header,
156  std::shared_ptr<typename ServiceT::Request> request)
157  {
158  TRACETOOLS_TRACEPOINT(callback_start, static_cast<const void *>(this), false);
159  if (std::holds_alternative<std::monostate>(callback_)) {
160  // TODO(ivanpauno): Remove the set method, and force the users of this class
161  // to pass a callback at construnciton.
162  throw std::runtime_error{"unexpected request without any callback set"};
163  }
164  if (std::holds_alternative<SharedPtrDeferResponseCallback>(callback_)) {
165  const auto & cb = std::get<SharedPtrDeferResponseCallback>(callback_);
166  cb(request_header, std::move(request));
167  TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
168  return nullptr;
169  }
170  if (std::holds_alternative<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_)) {
171  const auto & cb = std::get<SharedPtrDeferResponseCallbackWithServiceHandle>(callback_);
172  cb(service_handle, request_header, std::move(request));
173  TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
174  return nullptr;
175  }
176  // auto response = allocate_shared<typename ServiceT::Response, Allocator>();
177  auto response = std::make_shared<typename ServiceT::Response>();
178  if (std::holds_alternative<SharedPtrCallback>(callback_)) {
179  (void)request_header;
180  const auto & cb = std::get<SharedPtrCallback>(callback_);
181  cb(std::move(request), response);
182  } else if (std::holds_alternative<SharedPtrWithRequestHeaderCallback>(callback_)) {
183  const auto & cb = std::get<SharedPtrWithRequestHeaderCallback>(callback_);
184  cb(request_header, std::move(request), response);
185  }
186  TRACETOOLS_TRACEPOINT(callback_end, static_cast<const void *>(this));
187  return response;
188  }
189 
190  void register_callback_for_tracing()
191  {
192 #ifndef TRACETOOLS_DISABLED
193  std::visit(
194  [this](auto && arg) {
195  if (TRACETOOLS_TRACEPOINT_ENABLED(rclcpp_callback_register)) {
196  char * symbol = tracetools::get_symbol(arg);
197  TRACETOOLS_DO_TRACEPOINT(
198  rclcpp_callback_register,
199  static_cast<const void *>(this),
200  symbol);
201  std::free(symbol);
202  }
203  }, callback_);
204 #endif // TRACETOOLS_DISABLED
205  }
206 
207 private:
208  using SharedPtrCallback = std::function<
209  void (
210  std::shared_ptr<typename ServiceT::Request>,
211  std::shared_ptr<typename ServiceT::Response>
212  )>;
213  using SharedPtrWithRequestHeaderCallback = std::function<
214  void (
215  std::shared_ptr<rmw_request_id_t>,
216  std::shared_ptr<typename ServiceT::Request>,
217  std::shared_ptr<typename ServiceT::Response>
218  )>;
219  using SharedPtrDeferResponseCallback = std::function<
220  void (
221  std::shared_ptr<rmw_request_id_t>,
222  std::shared_ptr<typename ServiceT::Request>
223  )>;
224  using SharedPtrDeferResponseCallbackWithServiceHandle = std::function<
225  void (
226  std::shared_ptr<rclcpp::Service<ServiceT>>,
227  std::shared_ptr<rmw_request_id_t>,
228  std::shared_ptr<typename ServiceT::Request>
229  )>;
230 
231  std::variant<
232  std::monostate,
233  SharedPtrCallback,
234  SharedPtrWithRequestHeaderCallback,
235  SharedPtrDeferResponseCallback,
236  SharedPtrDeferResponseCallbackWithServiceHandle> callback_;
237 };
238 
239 } // namespace rclcpp
240 
241 #endif // RCLCPP__ANY_SERVICE_CALLBACK_HPP_
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.