ROS 2 rclcpp + rcl - rolling  rolling-29de98cf
ROS 2 C++ Client Library with ROS Client Library
client.hpp
1 // Copyright 2014 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__CLIENT_HPP_
16 #define RCLCPP__CLIENT_HPP_
17 
18 #include <atomic>
19 #include <functional>
20 #include <future>
21 #include <memory>
22 #include <mutex>
23 #include <optional>
24 #include <string>
25 #include <tuple>
26 #include <unordered_map>
27 #include <utility>
28 #include <variant>
29 #include <vector>
30 
31 #include "rcl/client.h"
32 #include "rcl/error_handling.h"
33 #include "rcl/event_callback.h"
34 #include "rcl/service_introspection.h"
35 #include "rcl/wait.h"
36 
37 #include "rclcpp/clock.hpp"
38 #include "rclcpp/exceptions.hpp"
39 #include "rclcpp/expand_topic_or_service_name.hpp"
40 #include "rclcpp/function_traits.hpp"
41 #include "rclcpp/logging.hpp"
42 #include "rclcpp/macros.hpp"
43 #include "rclcpp/node_interfaces/node_graph_interface.hpp"
44 #include "rclcpp/qos.hpp"
45 #include "rclcpp/type_support_decl.hpp"
46 #include "rclcpp/visibility_control.hpp"
47 
48 #include "rmw/error_handling.h"
49 #include "rmw/rmw.h"
50 
51 namespace rclcpp
52 {
53 
54 namespace detail
55 {
56 template<typename FutureT>
58 {
59  FutureT future;
60  int64_t request_id;
61 
62  FutureAndRequestId(FutureT impl, int64_t req_id)
63  : future(std::move(impl)), request_id(req_id)
64  {}
65 
67  operator FutureT &() {return this->future;}
68 
69  // delegate future like methods in the std::future impl_
70 
72  auto get() {return this->future.get();}
74  bool valid() const noexcept {return this->future.valid();}
76  void wait() const {return this->future.wait();}
78  template<class Rep, class Period>
79  std::future_status wait_for(
80  const std::chrono::duration<Rep, Period> & timeout_duration) const
81  {
82  return this->future.wait_for(timeout_duration);
83  }
85  template<class Clock, class Duration>
86  std::future_status wait_until(
87  const std::chrono::time_point<Clock, Duration> & timeout_time) const
88  {
89  return this->future.wait_until(timeout_time);
90  }
91 
92  // Rule of five, we could use the rule of zero here, but better be explicit as some of the
93  // methods are deleted.
94 
96  FutureAndRequestId(FutureAndRequestId && other) noexcept = default;
98  FutureAndRequestId(const FutureAndRequestId & other) = delete;
100  FutureAndRequestId & operator=(FutureAndRequestId && other) noexcept = default;
104  ~FutureAndRequestId() = default;
105 };
106 
107 template<typename PendingRequestsT, typename AllocatorT = std::allocator<int64_t>>
108 size_t
109 prune_requests_older_than_impl(
110  PendingRequestsT & pending_requests,
111  std::mutex & pending_requests_mutex,
112  std::chrono::time_point<std::chrono::system_clock> time_point,
113  std::vector<int64_t, AllocatorT> * pruned_requests = nullptr)
114 {
115  std::lock_guard guard(pending_requests_mutex);
116  auto old_size = pending_requests.size();
117  for (auto it = pending_requests.begin(), last = pending_requests.end(); it != last; ) {
118  if (it->second.first < time_point) {
119  if (pruned_requests) {
120  pruned_requests->push_back(it->first);
121  }
122  it = pending_requests.erase(it);
123  } else {
124  ++it;
125  }
126  }
127  return old_size - pending_requests.size();
128 }
129 } // namespace detail
130 
131 namespace node_interfaces
132 {
133 class NodeBaseInterface;
134 } // namespace node_interfaces
135 
137 {
138 public:
139  RCLCPP_SMART_PTR_DEFINITIONS_NOT_COPYABLE(ClientBase)
140 
141  RCLCPP_PUBLIC
142  ClientBase(
144  const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr & node_graph);
145 
146  RCLCPP_PUBLIC
147  virtual ~ClientBase() = default;
148 
150 
166  RCLCPP_PUBLIC
167  bool
168  take_type_erased_response(void * response_out, rmw_request_id_t & request_header_out);
169 
171 
172  RCLCPP_PUBLIC
173  const char *
174  get_service_name() const;
175 
177 
181  RCLCPP_PUBLIC
182  std::shared_ptr<rcl_client_t>
184 
186 
190  RCLCPP_PUBLIC
191  std::shared_ptr<const rcl_client_t>
192  get_client_handle() const;
193 
195 
198  RCLCPP_PUBLIC
199  bool
200  service_is_ready() const;
201 
203 
207  template<typename RepT = int64_t, typename RatioT = std::milli>
208  bool
210  std::chrono::duration<RepT, RatioT> timeout = std::chrono::duration<RepT, RatioT>(-1))
211  {
212  return wait_for_service_nanoseconds(
213  std::chrono::duration_cast<std::chrono::nanoseconds>(timeout)
214  );
215  }
216 
217  virtual std::shared_ptr<void> create_response() = 0;
218  virtual std::shared_ptr<rmw_request_id_t> create_request_header() = 0;
219  virtual void handle_response(
220  const std::shared_ptr<rmw_request_id_t> & request_header,
221  const std::shared_ptr<void> & response) = 0;
222 
224 
233  RCLCPP_PUBLIC
234  bool
235  exchange_in_use_by_wait_set_state(bool in_use_state);
236 
238 
249  RCLCPP_PUBLIC
252 
254 
265  RCLCPP_PUBLIC
268 
270 
295  RCLCPP_PUBLIC
296  void
297  set_on_new_response_callback(const std::function<void(size_t)> & callback);
298 
300  RCLCPP_PUBLIC
301  void
303 
304 protected:
305  RCLCPP_DISABLE_COPY(ClientBase)
306 
307  RCLCPP_PUBLIC
308  bool
309  wait_for_service_nanoseconds(std::chrono::nanoseconds timeout);
310 
311  RCLCPP_PUBLIC
312  rcl_node_t *
313  get_rcl_node_handle();
314 
315  RCLCPP_PUBLIC
316  const rcl_node_t *
317  get_rcl_node_handle() const;
318 
319  RCLCPP_PUBLIC
320  void
321  set_on_new_response_callback(rcl_event_callback_t callback, const void * user_data);
322 
323  rclcpp::node_interfaces::NodeGraphInterface::WeakPtr node_graph_;
324  std::shared_ptr<rcl_node_t> node_handle_;
325  std::shared_ptr<rclcpp::Context> context_;
326  rclcpp::Logger node_logger_;
327 
328  std::recursive_mutex callback_mutex_;
329  // It is important to declare on_new_response_callback_ before
330  // client_handle_, so on destruction the client is
331  // destroyed first. Otherwise, the rmw client callback
332  // would point briefly to a destroyed function.
333  std::function<void(size_t)> on_new_response_callback_{nullptr};
334  // Declare client_handle_ after callback
335  std::shared_ptr<rcl_client_t> client_handle_;
336 
337  std::atomic<bool> in_use_by_wait_set_{false};
338 };
339 
340 template<typename ServiceT>
341 class Client : public ClientBase
342 {
343 public:
344  using Request = typename ServiceT::Request;
345  using Response = typename ServiceT::Response;
346 
347  using SharedRequest = typename ServiceT::Request::SharedPtr;
348  using SharedResponse = typename ServiceT::Response::SharedPtr;
349 
350  using Promise = std::promise<SharedResponse>;
351  using PromiseWithRequest = std::promise<std::pair<SharedRequest, SharedResponse>>;
352 
353  using SharedPromise = std::shared_ptr<Promise>;
354  using SharedPromiseWithRequest = std::shared_ptr<PromiseWithRequest>;
355 
356  using Future = std::future<SharedResponse>;
357  using SharedFuture = std::shared_future<SharedResponse>;
358  using SharedFutureWithRequest = std::shared_future<std::pair<SharedRequest, SharedResponse>>;
359 
360  using CallbackType = std::function<void (SharedFuture)>;
361  using CallbackWithRequestType = std::function<void (SharedFutureWithRequest)>;
362 
363  RCLCPP_SMART_PTR_DEFINITIONS(Client)
364 
365 
374  : detail::FutureAndRequestId<std::future<SharedResponse>>
375  {
377 
378  // delegate future like methods in the std::future impl_
379 
381  SharedFuture share() noexcept {return this->future.share();}
382  };
383 
385 
393  : detail::FutureAndRequestId<std::shared_future<SharedResponse>>
394  {
396  };
397 
399 
407  : detail::FutureAndRequestId<std::shared_future<std::pair<SharedRequest, SharedResponse>>>
408  {
410  std::shared_future<std::pair<SharedRequest, SharedResponse>>
412  };
413 
415 
427  const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr & node_graph,
428  const std::string & service_name,
429  rcl_client_options_t & client_options)
430  : ClientBase(node_base, node_graph),
431  srv_type_support_handle_(rosidl_typesupport_cpp::get_service_type_support_handle<ServiceT>())
432  {
434  this->get_client_handle().get(),
435  this->get_rcl_node_handle(),
436  srv_type_support_handle_,
437  service_name.c_str(),
438  &client_options);
439  if (ret != RCL_RET_OK) {
440  if (ret == RCL_RET_SERVICE_NAME_INVALID) {
441  auto rcl_node_handle = this->get_rcl_node_handle();
442  // this will throw on any validation problem
443  rcl_reset_error();
445  service_name,
446  rcl_node_get_name(rcl_node_handle),
447  rcl_node_get_namespace(rcl_node_handle),
448  true);
449  }
450  rclcpp::exceptions::throw_from_rcl_error(ret, "could not create client");
451  }
452  }
453 
454  virtual ~Client()
455  {
456  }
457 
459 
471  bool
472  take_response(typename ServiceT::Response & response_out, rmw_request_id_t & request_header_out)
473  {
474  return this->take_type_erased_response(&response_out, request_header_out);
475  }
476 
478 
481  std::shared_ptr<void>
482  create_response() override
483  {
484  return std::shared_ptr<void>(new typename ServiceT::Response());
485  }
486 
488 
491  std::shared_ptr<rmw_request_id_t>
493  {
494  // TODO(wjwwood): This should probably use rmw_request_id's allocator.
495  // (since it is a C type)
496  return std::shared_ptr<rmw_request_id_t>(new rmw_request_id_t);
497  }
498 
500 
504  void
506  const std::shared_ptr<rmw_request_id_t> & request_header,
507  const std::shared_ptr<void> & response) override
508  {
509  std::optional<CallbackInfoVariant>
510  optional_pending_request = this->get_and_erase_pending_request(request_header->sequence_number);
511  if (!optional_pending_request) {
512  return;
513  }
514  auto & value = *optional_pending_request;
515  auto typed_response = std::static_pointer_cast<typename ServiceT::Response>(
516  response);
517  if (std::holds_alternative<Promise>(value)) {
518  auto & promise = std::get<Promise>(value);
519  promise.set_value(std::move(typed_response));
520  } else if (std::holds_alternative<CallbackTypeValueVariant>(value)) {
521  auto & inner = std::get<CallbackTypeValueVariant>(value);
522  const auto & callback = std::get<CallbackType>(inner);
523  auto & promise = std::get<Promise>(inner);
524  auto & future = std::get<SharedFuture>(inner);
525  promise.set_value(std::move(typed_response));
526  callback(std::move(future));
527  } else if (std::holds_alternative<CallbackWithRequestTypeValueVariant>(value)) {
528  auto & inner = std::get<CallbackWithRequestTypeValueVariant>(value);
529  const auto & callback = std::get<CallbackWithRequestType>(inner);
530  auto & promise = std::get<PromiseWithRequest>(inner);
531  auto & future = std::get<SharedFutureWithRequest>(inner);
532  auto & request = std::get<SharedRequest>(inner);
533  promise.set_value(std::make_pair(std::move(request), std::move(typed_response)));
534  callback(std::move(future));
535  }
536  }
537 
539 
566  FutureAndRequestId
567  async_send_request(const SharedRequest & request)
568  {
569  Promise promise;
570  auto future = promise.get_future();
571  auto req_id = async_send_request_impl(
572  *request,
573  std::move(promise));
574  return FutureAndRequestId(std::move(future), req_id);
575  }
576 
578 
592  template<
593  typename CallbackT,
594  typename std::enable_if<
596  CallbackT,
597  CallbackType
598  >::value
599  >::type * = nullptr
600  >
601  SharedFutureAndRequestId
602  async_send_request(const SharedRequest & request, CallbackT && cb)
603  {
604  Promise promise;
605  auto shared_future = promise.get_future().share();
606  auto req_id = async_send_request_impl(
607  *request,
608  std::make_tuple(
609  CallbackType{std::forward<CallbackT>(cb)},
610  shared_future,
611  std::move(promise)));
612  return SharedFutureAndRequestId{std::move(shared_future), req_id};
613  }
614 
616 
623  template<
624  typename CallbackT,
625  typename std::enable_if<
627  CallbackT,
628  CallbackWithRequestType
629  >::value
630  >::type * = nullptr
631  >
632  SharedFutureWithRequestAndRequestId
633  async_send_request(const SharedRequest & request, CallbackT && cb)
634  {
635  PromiseWithRequest promise;
636  auto shared_future = promise.get_future().share();
637  auto req_id = async_send_request_impl(
638  *request,
639  std::make_tuple(
640  CallbackWithRequestType{std::forward<CallbackT>(cb)},
641  request,
642  shared_future,
643  std::move(promise)));
644  return SharedFutureWithRequestAndRequestId{std::move(shared_future), req_id};
645  }
646 
648 
658  bool
659  remove_pending_request(int64_t request_id)
660  {
661  std::lock_guard guard(pending_requests_mutex_);
662  return pending_requests_.erase(request_id) != 0u;
663  }
664 
666 
671  bool
673  {
674  return this->remove_pending_request(future.request_id);
675  }
676 
678 
683  bool
685  {
686  return this->remove_pending_request(future.request_id);
687  }
688 
690 
695  bool
697  {
698  return this->remove_pending_request(future.request_id);
699  }
700 
702 
705  size_t
707  {
708  std::lock_guard guard(pending_requests_mutex_);
709  auto ret = pending_requests_.size();
710  pending_requests_.clear();
711  return ret;
712  }
713 
715 
721  template<typename AllocatorT = std::allocator<int64_t>>
722  size_t
724  std::chrono::time_point<std::chrono::system_clock> time_point,
725  std::vector<int64_t, AllocatorT> * pruned_requests = nullptr)
726  {
727  return detail::prune_requests_older_than_impl(
728  pending_requests_,
729  pending_requests_mutex_,
730  time_point,
731  pruned_requests);
732  }
733 
735 
743  void
745  const Clock::SharedPtr & clock, const QoS & qos_service_event_pub,
746  rcl_service_introspection_state_t introspection_state)
747  {
749  pub_opts.qos = qos_service_event_pub.get_rmw_qos_profile();
750 
752  client_handle_.get(),
753  node_handle_.get(),
754  clock->get_clock_handle(),
755  srv_type_support_handle_,
756  pub_opts,
757  introspection_state);
758 
759  if (RCL_RET_OK != ret) {
760  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to configure client introspection");
761  }
762  }
763 
764 protected:
765  using CallbackTypeValueVariant = std::tuple<CallbackType, SharedFuture, Promise>;
766  using CallbackWithRequestTypeValueVariant = std::tuple<
767  CallbackWithRequestType, SharedRequest, SharedFutureWithRequest, PromiseWithRequest>;
768 
769  using CallbackInfoVariant = std::variant<
770  std::promise<SharedResponse>,
771  CallbackTypeValueVariant,
772  CallbackWithRequestTypeValueVariant>;
773 
774  int64_t
775  async_send_request_impl(const Request & request, CallbackInfoVariant value)
776  {
777  int64_t sequence_number;
778  std::lock_guard<std::mutex> lock(pending_requests_mutex_);
779  rcl_ret_t ret = rcl_send_request(get_client_handle().get(), &request, &sequence_number);
780  if (RCL_RET_OK != ret) {
781  rclcpp::exceptions::throw_from_rcl_error(ret, "failed to send request");
782  }
783  pending_requests_.try_emplace(
784  sequence_number,
785  std::make_pair(std::chrono::system_clock::now(), std::move(value)));
786  return sequence_number;
787  }
788 
789  std::optional<CallbackInfoVariant>
790  get_and_erase_pending_request(int64_t request_number)
791  {
792  std::unique_lock<std::mutex> lock(pending_requests_mutex_);
793  auto it = this->pending_requests_.find(request_number);
794  if (it == this->pending_requests_.end()) {
795  RCUTILS_LOG_DEBUG_NAMED(
796  "rclcpp",
797  "Received invalid sequence number. Ignoring...");
798  return std::nullopt;
799  }
800  std::optional<CallbackInfoVariant> value = std::move(it->second.second);
801  this->pending_requests_.erase(request_number);
802  return value;
803  }
804 
805  RCLCPP_DISABLE_COPY(Client)
806 
807  std::unordered_map<
808  int64_t,
809  std::pair<
810  std::chrono::time_point<std::chrono::system_clock>,
811  CallbackInfoVariant>>
812  pending_requests_;
813  std::mutex pending_requests_mutex_;
814 
815 private:
816  const rosidl_service_type_support_t * srv_type_support_handle_;
817 };
818 
819 } // namespace rclcpp
820 
821 #endif // RCLCPP__CLIENT_HPP_
RCLCPP_PUBLIC bool exchange_in_use_by_wait_set_state(bool in_use_state)
Exchange the "in use by wait set" state for this client.
Definition: client.cpp:200
RCLCPP_PUBLIC rclcpp::QoS get_request_publisher_actual_qos() const
Get the actual request publsher QoS settings, after the defaults have been determined.
Definition: client.cpp:206
RCLCPP_PUBLIC std::shared_ptr< rcl_client_t > get_client_handle()
Return the rcl_client_t client handle in a std::shared_ptr.
Definition: client.cpp:98
RCLCPP_PUBLIC void set_on_new_response_callback(const std::function< void(size_t)> &callback)
Set a callback to be called when each new response is received.
Definition: client.cpp:257
RCLCPP_PUBLIC bool take_type_erased_response(void *response_out, rmw_request_id_t &request_header_out)
Take the next response for this client as a type erased pointer.
Definition: client.cpp:77
bool wait_for_service(std::chrono::duration< RepT, RatioT > timeout=std::chrono::duration< RepT, RatioT >(-1))
Wait for a service to be ready.
Definition: client.hpp:209
RCLCPP_PUBLIC void clear_on_new_response_callback()
Unset the callback registered for new responses, if any.
Definition: client.cpp:305
RCLCPP_PUBLIC const char * get_service_name() const
Return the name of the service.
Definition: client.cpp:92
RCLCPP_PUBLIC rclcpp::QoS get_response_subscription_actual_qos() const
Get the actual response subscription QoS settings, after the defaults have been determined.
Definition: client.cpp:225
RCLCPP_PUBLIC bool service_is_ready() const
Return if the service is ready.
Definition: client.cpp:110
bool take_response(typename ServiceT::Response &response_out, rmw_request_id_t &request_header_out)
Take the next response for this client.
Definition: client.hpp:472
std::shared_ptr< rmw_request_id_t > create_request_header() override
Create a shared pointer with a rmw_request_id_t.
Definition: client.hpp:492
bool remove_pending_request(int64_t request_id)
Cleanup a pending request.
Definition: client.hpp:659
std::shared_ptr< void > create_response() override
Create a shared pointer with the response type.
Definition: client.hpp:482
size_t prune_requests_older_than(std::chrono::time_point< std::chrono::system_clock > time_point, std::vector< int64_t, AllocatorT > *pruned_requests=nullptr)
Clean all pending requests older than a time_point.
Definition: client.hpp:723
void configure_introspection(const Clock::SharedPtr &clock, const QoS &qos_service_event_pub, rcl_service_introspection_state_t introspection_state)
Configure client introspection.
Definition: client.hpp:744
FutureAndRequestId async_send_request(const SharedRequest &request)
Send a request to the service server.
Definition: client.hpp:567
Client(rclcpp::node_interfaces::NodeBaseInterface *node_base, const rclcpp::node_interfaces::NodeGraphInterface::SharedPtr &node_graph, const std::string &service_name, rcl_client_options_t &client_options)
Default constructor.
Definition: client.hpp:425
size_t prune_pending_requests()
Clean all pending requests.
Definition: client.hpp:706
bool remove_pending_request(const SharedFutureAndRequestId &future)
Cleanup a pending request.
Definition: client.hpp:684
SharedFutureWithRequestAndRequestId async_send_request(const SharedRequest &request, CallbackT &&cb)
Send a request to the service server and schedule a callback in the executor.
Definition: client.hpp:633
bool remove_pending_request(const SharedFutureWithRequestAndRequestId &future)
Cleanup a pending request.
Definition: client.hpp:696
void handle_response(const std::shared_ptr< rmw_request_id_t > &request_header, const std::shared_ptr< void > &response) override
Handle a server response.
Definition: client.hpp:505
SharedFutureAndRequestId async_send_request(const SharedRequest &request, CallbackT &&cb)
Send a request to the service server and schedule a callback in the executor.
Definition: client.hpp:602
bool remove_pending_request(const FutureAndRequestId &future)
Cleanup a pending request.
Definition: client.hpp:672
Encapsulation of Quality of Service settings.
Definition: qos.hpp:114
rmw_qos_profile_t & get_rmw_qos_profile()
Return the rmw qos profile.
Definition: qos.cpp:109
Pure virtual interface class for the NodeBase part of the Node API.
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_client_configure_service_introspection(rcl_client_t *client, rcl_node_t *node, rcl_clock_t *clock, const rosidl_service_type_support_t *type_support, const rcl_publisher_options_t publisher_options, rcl_service_introspection_state_t introspection_state)
Configures service introspection features for the client.
Definition: client.c:456
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_client_init(rcl_client_t *client, const rcl_node_t *node, const rosidl_service_type_support_t *type_support, const char *service_name, const rcl_client_options_t *options)
Initialize a rcl client.
Definition: client.c:76
RCL_PUBLIC RCL_WARN_UNUSED rcl_ret_t rcl_send_request(const rcl_client_t *client, const void *ros_request, int64_t *sequence_number)
Send a ROS request using a client.
Definition: client.c:308
Versions of rosidl_typesupport_cpp::get_message_type_support_handle that handle adapted types.
RCLCPP_PUBLIC std::string expand_topic_or_service_name(const std::string &name, const std::string &node_name, const std::string &namespace_, bool is_service=false)
Expand a topic or service name and throw if it is not valid.
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_name(const rcl_node_t *node)
Return the name of the node.
Definition: node.c:416
RCL_PUBLIC RCL_WARN_UNUSED const char * rcl_node_get_namespace(const rcl_node_t *node)
Return the namespace of the node.
Definition: node.c:425
RCL_PUBLIC RCL_WARN_UNUSED rcl_publisher_options_t rcl_publisher_get_default_options(void)
Return the default publisher options in a rcl_publisher_options_t.
Definition: publisher.c:217
Options available for a rcl_client_t.
Definition: client.h:50
Structure which encapsulates a ROS Node.
Definition: node.h:45
Options available for a rcl publisher.
Definition: publisher.h:44
rmw_qos_profile_t qos
Middleware quality of service settings for the publisher.
Definition: publisher.h:46
A convenient Client::Future and request id pair.
Definition: client.hpp:375
SharedFuture share() noexcept
See std::future::share().
Definition: client.hpp:381
A convenient Client::SharedFuture and request id pair.
Definition: client.hpp:394
A convenient Client::SharedFutureWithRequest and request id pair.
Definition: client.hpp:408
std::future_status wait_for(const std::chrono::duration< Rep, Period > &timeout_duration) const
See std::future::wait_for().
Definition: client.hpp:79
std::future_status wait_until(const std::chrono::time_point< Clock, Duration > &timeout_time) const
See std::future::wait_until().
Definition: client.hpp:86
FutureAndRequestId & operator=(FutureAndRequestId &&other) noexcept=default
Move assignment.
FutureAndRequestId & operator=(const FutureAndRequestId &other)=delete
Deleted copy assignment, each instance is a unique owner of the future.
FutureAndRequestId(const FutureAndRequestId &other)=delete
Deleted copy constructor, each instance is a unique owner of the future.
void wait() const
See std::future::wait().
Definition: client.hpp:76
FutureAndRequestId(FutureAndRequestId &&other) noexcept=default
Move constructor.
~FutureAndRequestId()=default
Destructor.
auto get()
See std::future::get().
Definition: client.hpp:72
bool valid() const noexcept
See std::future::valid().
Definition: client.hpp:74
#define RCL_RET_SERVICE_NAME_INVALID
Service name (same as topic name) does not pass validation.
Definition: types.h:49
#define RCL_RET_OK
Success return code.
Definition: types.h:27
rmw_ret_t rcl_ret_t
The type that holds an rcl return code.
Definition: types.h:24