16#ifndef NROS_RCLCPP_SERVICE_HPP
17#define NROS_RCLCPP_SERVICE_HPP
22#include "rclcpp/detail/callback_context.hpp"
24#include "rclcpp/detail/entity_name.hpp"
26#include "rclcpp/service_handle.hpp"
27#include "rclcpp/size_bound.hpp"
29#include "rclcpp/detail/nros_cpp_ffi.h"
47 uint8_t* resp,
size_t resp_cap,
48 size_t* resp_len,
void* ctx);
51 const char* service_name,
const char* type_name,
54 void* context, uint8_t sched_context,
55 size_t* out_handle_id);
59 const nros_cpp_node_t* node,
const char* service_name,
const char* type_name,
61 const uint8_t* capture,
size_t capture_len,
void (*capture_drop)(
void*), uint8_t sched_context,
62 size_t* out_handle_id);
67#include "rclcpp/detail/rmw_request_id.hpp"
72 rmw_request_id_t* request_id, uint8_t* resp,
73 size_t resp_cap,
size_t* resp_len,
80 const nros_cpp_node_t* node,
const char* service_name,
const char* type_name,
82 void* context,
const uint8_t* capture,
size_t capture_len,
void (*capture_drop)(
void*),
83 uint8_t sched_context,
size_t* out_handle_id);
259 : initialized_(other.initialized_), handle_id_(other.handle_id_), service_name_{},
260 executor_(other.executor_) {
261 ::rclcpp::detail::assign_entity_name(service_name_, other.service_name_);
262 other.initialized_ =
false;
266 if (
this != &other) {
267 initialized_ = other.initialized_;
268 handle_id_ = other.handle_id_;
269 ::rclcpp::detail::assign_entity_name(service_name_, other.service_name_);
271 executor_ = other.executor_;
272 other.initialized_ =
false;
279 Service() : initialized_(false), service_name_{} {}
288 friend class ::rclcpp::Node;
299 static bool request_trampoline(
const uint8_t* req,
size_t req_len, uint8_t* resp,
300 size_t resp_cap,
size_t* resp_len,
void* ctx) {
301 const TypedServiceFn user_fn = ::rclcpp::detail::fn_from_context<TypedServiceFn>(ctx);
302 if (user_fn ==
nullptr)
return false;
304 if (RequestType::ffi_deserialize(req, req_len, &request) != 0)
return false;
306 user_fn(request, response);
308 if (ResponseType::ffi_serialize(&response, resp, resp_cap, &len) != 0)
return false;
324 if (!initialized_) return ::rclcpp::detail::qos_all_unknown();
325 if (nros_cpp_service_server_get_actual_qos(
nullptr, executor_, handle_id_, &req, &resp) !=
327 return ::rclcpp::detail::qos_all_unknown();
329 return ::rclcpp::detail::qos_from_ffi(request ? req : resp);
337 size_t handle_id_ =
static_cast<size_t>(-1);
341 char service_name_[::rclcpp::SERVICE_NAME_MAX];
346 void* executor_ =
nullptr;
363template <
typename S,
typename F,
typename>
365 const ::rclcpp::QoS& qos, const ::rclcpp::ServiceOptions& options) {
372 return this->
template register_service_<S>(out, service_name, &Service<S>::request_trampoline,
373 ::rclcpp::detail::fn_to_context(user_fn), qos,
379 bool (*trampoline)(
const uint8_t*,
size_t, uint8_t*,
size_t,
size_t*,
381 void* context, const ::rclcpp::QoS& qos,
382 const ::rclcpp::ServiceOptions& options,
const void* capture,
383 size_t capture_len,
void (*capture_drop)(
void*)) {
387 uint8_t sched = (options.sched_context == ::rclcpp::SCHED_CONTEXT_UNSET)
389 :
static_cast<uint8_t
>(options.sched_context);
390 size_t handle =
static_cast<size_t>(-1);
392 (capture !=
nullptr && capture_len != 0)
394 &handle_, service_name, S::TYPE_NAME, S::Request::TYPE_HASH, ffi_qos, trampoline,
395 static_cast<const uint8_t*
>(capture), capture_len, capture_drop, sched, &
handle)
397 S::Request::TYPE_HASH, ffi_qos, trampoline, context,
399 return this->
template finish_register_service_<S>(out, service_name, ret,
handle);
408 const ::rclcpp::QoS& qos, const ::rclcpp::ServiceOptions& options,
409 const void* capture,
size_t capture_len,
410 void (*capture_drop)(
void*)) {
413 uint8_t sched = (options.sched_context == ::rclcpp::SCHED_CONTEXT_UNSET)
415 :
static_cast<uint8_t
>(options.sched_context);
416 size_t handle =
static_cast<size_t>(-1);
417 const bool captured = capture !=
nullptr && capture_len != 0;
419 &handle_, service_name, S::TYPE_NAME, S::Request::TYPE_HASH, ffi_qos, trampoline,
420 captured ?
nullptr : context, captured ?
static_cast<const uint8_t*
>(capture) :
nullptr,
421 captured ? capture_len : 0, captured ? capture_drop :
nullptr, sched, &
handle);
422 return this->
template finish_register_service_<S>(out, service_name, ret,
handle);
432 ::rclcpp::detail::assign_entity_name(out.service_name_, service_name);
435 out.executor_ = executor_handle_;
436 out.initialized_ =
true;
442#include "rclcpp/logging.hpp"
443#include "rclcpp/inplace_fn.hpp"
445#if defined(NROS_CPP_HAS_SHARED_PTR)
470 static const size_t CAPACITY = 96;
471 alignas(
alignof(::std::max_align_t))
unsigned char bytes[CAPACITY];
475[[noreturn]]
inline void abort_frame_block() {
476 RCLC_LOG_ERROR(log_handle(
nullptr),
477 "rclcpp: a shared_ptr control block does not fit FrameBlock::CAPACITY");
481template <
typename T>
struct FrameBlockAllocator {
482 using value_type = T;
484 explicit FrameBlockAllocator(FrameBlock* b) : block(b) {}
485 template <
typename U> FrameBlockAllocator(
const FrameBlockAllocator<U>& o) : block(o.block) {}
486 T* allocate(
size_t n) {
487 if (block->used || n *
sizeof(T) > FrameBlock::CAPACITY ||
488 alignof(T) >
alignof(::std::max_align_t)) {
492 return reinterpret_cast<T*
>(block->bytes);
494 void deallocate(T*,
size_t) { block->used =
false; }
495 template <
typename U>
bool operator==(
const FrameBlockAllocator<U>& o)
const {
496 return block == o.block;
498 template <
typename U>
bool operator!=(
const FrameBlockAllocator<U>& o)
const {
499 return block != o.block;
504 template <
typename T>
void operator()(T*)
const {}
507template <
typename T> inline ::std::shared_ptr<T> lend_from_frame(T*
object, FrameBlock* block) {
508 return ::std::shared_ptr<T>(
object, LendDeleter(), FrameBlockAllocator<T>(block));
511template <
typename S>
struct shared_ptr_service_fn {
512 using Request =
typename S::Request;
513 using Response =
typename S::Response;
514 using two = void (*)(::std::shared_ptr<Request>, ::std::shared_ptr<Response>);
515 using three = void (*)(::std::shared_ptr<::rmw_request_id_t>, ::std::shared_ptr<Request>,
516 ::std::shared_ptr<Response>);
521template <
typename S,
typename F>
struct service_ptr_shape {
522 static const int value =
523 ::rclcpp::tr::is_convertible<F, typename shared_ptr_service_fn<S>::three>::value ? 3
524 : ::rclcpp::tr::is_convertible<F, typename shared_ptr_service_fn<S>::two>::value ? 2
533template <
typename S,
typename Invoke>
534inline bool serve_lent(
const uint8_t* req,
size_t req_len, const ::rmw_request_id_t*
id,
535 uint8_t* resp,
size_t resp_cap,
size_t* resp_len,
const Invoke& invoke) {
536 typename S::Request request;
537 if (S::Request::ffi_deserialize(req, req_len, &request) != 0)
return false;
538 typename S::Response response;
541 ::rmw_request_id_t header = {};
542 if (
id !=
nullptr) header = *id;
544 FrameBlock request_block;
545 FrameBlock response_block;
546 FrameBlock header_block;
547 ::std::shared_ptr<typename S::Request> request_ptr =
548 lend_from_frame(&request, &request_block);
549 ::std::shared_ptr<typename S::Response> response_ptr =
550 lend_from_frame(&response, &response_block);
551 ::std::shared_ptr<::rmw_request_id_t> header_ptr = lend_from_frame(&header, &header_block);
552 invoke(header_ptr, request_ptr, response_ptr);
553 if (request_ptr.use_count() != 1 || response_ptr.use_count() != 1 ||
554 header_ptr.use_count() != 1) {
555 NROS_RCLCPP_SAY_REFUSED(NROS_RCLCPP_REFUSE_RETAINED_SERVICE_PTR);
560 if (S::Response::ffi_serialize(&response, resp, resp_cap, &len) != 0)
return false;
565template <
typename S,
int Shape>
struct shared_ptr_service_trampoline {
566 static bool call(
const uint8_t* req,
size_t req_len, ::rmw_request_id_t*
id, uint8_t* resp,
567 size_t resp_cap,
size_t* resp_len,
void* ctx) {
568 using Fn = shared_ptr_service_fn<S>;
569 return serve_lent<S>(req, req_len,
id, resp, resp_cap, resp_len,
570 [ctx](::std::shared_ptr<::rmw_request_id_t>& h,
571 ::std::shared_ptr<typename S::Request>& rq,
572 ::std::shared_ptr<typename S::Response>& rs) {
574 fn_from_context<typename Fn::three>(ctx)(h, rq, rs);
577 fn_from_context<typename Fn::two>(ctx)(rq, rs);
591template <
typename S,
typename F>
class stateful_service_shape {
592 using Rq =
typename S::Request;
593 using Rs =
typename S::Response;
594 using H = ::std::shared_ptr<::rmw_request_id_t>;
595 template <
typename G>
596 static auto probe3(
int)
597 ->
decltype(::std::declval<G&>()(::std::declval<H&>(),
598 ::std::declval<::std::shared_ptr<Rq>&>(),
599 ::std::declval<::std::shared_ptr<Rs>&>()),
603 template <
typename G>
static long probe3(...) {
return 0; }
604 template <
typename G>
605 static auto probe2(
int)
606 ->
decltype(::std::declval<G&>()(::std::declval<::std::shared_ptr<Rq>&>(),
607 ::std::declval<::std::shared_ptr<Rs>&>()),
611 template <
typename G>
static long probe2(...) {
return 0; }
612 template <
typename G>
613 static auto probe1(
int)
614 ->
decltype(::std::declval<G&>()(::std::declval<const Rq&>(), ::std::declval<Rs&>()),
618 template <
typename G>
static long probe1(...) {
return 0; }
621 static const int value =
sizeof(probe3<F>(0)) ==
sizeof(
char) ? 3
622 :
sizeof(probe2<F>(0)) ==
sizeof(
char) ? 2
623 :
sizeof(probe1<F>(0)) ==
sizeof(
char) ? 1
633using StatefulServiceFn = ::rclcpp::InplaceFn<void(::std::shared_ptr<::rmw_request_id_t>&,
634 ::std::shared_ptr<typename S::Request>&,
635 ::std::shared_ptr<typename S::Response>&),
638template <
typename S,
int Shape>
struct stateful_service_adapter;
639template <
typename S>
struct stateful_service_adapter<S, 3> {
640 template <
typename F>
static StatefulServiceFn<S> wrap(F f) {
641 return StatefulServiceFn<S>(
642 [f](::std::shared_ptr<::rmw_request_id_t>& h,
643 ::std::shared_ptr<typename S::Request>& rq,
644 ::std::shared_ptr<typename S::Response>& rs)
mutable { (void)f(h, rq, rs); });
647template <
typename S>
struct stateful_service_adapter<S, 2> {
648 template <
typename F>
static StatefulServiceFn<S> wrap(F f) {
649 return StatefulServiceFn<S>(
650 [f](::std::shared_ptr<::rmw_request_id_t>&, ::std::shared_ptr<typename S::Request>& rq,
651 ::std::shared_ptr<typename S::Response>& rs)
mutable { (void)f(rq, rs); });
654template <
typename S>
struct stateful_service_adapter<S, 1> {
655 template <
typename F>
static StatefulServiceFn<S> wrap(F f) {
656 return StatefulServiceFn<S>([f](::std::shared_ptr<::rmw_request_id_t>&,
657 ::std::shared_ptr<typename S::Request>& rq,
658 ::std::shared_ptr<typename S::Response>& rs)
mutable {
659 (void)f(
static_cast<const typename S::Request&
>(*rq), *rs);
665template <
typename S>
struct stateful_service_trampoline {
666 static bool call(
const uint8_t* req,
size_t req_len, ::rmw_request_id_t*
id, uint8_t* resp,
667 size_t resp_cap,
size_t* resp_len,
void* ctx) {
668 const StatefulServiceFn<S>* fn =
static_cast<const StatefulServiceFn<S>*
>(ctx);
669 return serve_lent<S>(req, req_len,
id, resp, resp_cap, resp_len, *fn);
671 static void destroy(
void* ctx) {
static_cast<StatefulServiceFn<S>*
>(ctx)->clear(); }
676template <
typename S,
typename F>
677inline void* shared_ptr_service_context(F callback, ::rclcpp::tr::integral_constant<int, 3>) {
678 return fn_to_context(
typename shared_ptr_service_fn<S>::three(callback));
680template <
typename S,
typename F>
681inline void* shared_ptr_service_context(F callback, ::rclcpp::tr::integral_constant<int, 2>) {
682 return fn_to_context(
typename shared_ptr_service_fn<S>::two(callback));
::rclcpp::Owned<::rclcpp::PollService< S > > create_service(const char *name, const ::rclcpp::QoS &qos=::rclcpp::QoS::services())
Definition service.hpp:146
const char * get_service_name() const
Definition service.hpp:199
Service & operator=(Service &&other)
Definition service.hpp:265
Service(Service &&other)
Definition service.hpp:258
~Service()
Definition service.hpp:241
void(*)(const RequestType &request, ResponseType &response) TypedServiceFn
Definition service.hpp:180
size_t handle_id() const
Executor arena slot for the registration; SIZE_MAX until registered.
Definition service.hpp:282
::rclcpp::QoS get_response_publisher_actual_qos() const
Definition service.hpp:230
typename S::Request RequestType
Definition service.hpp:166
::rclcpp::QoS get_request_subscription_actual_qos() const
Definition service.hpp:225
::rclcpp::ServiceHandle< S > UniquePtr
rclcpp::Service<S>::UniquePtr — see SharedPtr.
Definition service.hpp:164
bool is_valid() const
Check if the service was registered.
Definition service.hpp:183
Service()
Definition service.hpp:279
typename S::Response ResponseType
Definition service.hpp:167
::rclcpp::ServiceHandle< S > SharedPtr
Definition service.hpp:158
::rclcpp::ServiceHandle< S > ConstSharedPtr
Definition service.hpp:162
Inline storage-size macros for opaque entity buffers.
int nros_cpp_ret_t
Definition future.hpp:25
constexpr nros_cpp_qos_t qos_to_ffi(const QoS &qos)
Definition qos.hpp:719
constexpr bool operator==(const QoS &left, const QoS &right)
Definition qos.hpp:518
constexpr bool operator!=(const QoS &left, const QoS &right)
Definition qos.hpp:532
@ NotInitialized
Definition result.hpp:131
ResultOf< void > Result
Definition result.hpp:247
rclcpp::Node and global session helpers.
rclcpp::QoS — full DDS-shaped QoS settings (Phase 108.B.7).
**auto handle
Definition client.hpp:127
rclcpp::Result, rclcpp::ErrorCode, and the RCLCPP_TRY macro.
bool(* nros_cpp_service_request_id_callback_t)(const uint8_t *req, size_t req_len, rmw_request_id_t *request_id, uint8_t *resp, size_t resp_cap, size_t *resp_len, void *ctx)
Issue 2081 — a service trampoline that also receives the request's id.
Definition service.hpp:71
nros_cpp_ret_t nros_cpp_service_server_register_with_request_id(const nros_cpp_node_t *node, const char *service_name, const char *type_name, const char *type_hash, nros_cpp_qos_t qos, nros_cpp_service_request_id_callback_t callback, void *context, const uint8_t *capture, size_t capture_len, void(*capture_drop)(void *), uint8_t sched_context, size_t *out_handle_id)
bool(* nros_cpp_service_request_callback_t)(const uint8_t *req, size_t req_len, uint8_t *resp, size_t resp_cap, size_t *resp_len, void *ctx)
Definition service.hpp:46
nros_cpp_ret_t nros_cpp_service_server_register(const nros_cpp_node_t *node, const char *service_name, const char *type_name, const char *type_hash, nros_cpp_qos_t qos, nros_cpp_service_request_callback_t callback, void *context, uint8_t sched_context, size_t *out_handle_id)
nros_cpp_ret_t nros_cpp_service_server_register_capturing(const nros_cpp_node_t *node, const char *service_name, const char *type_name, const char *type_hash, nros_cpp_qos_t qos, nros_cpp_service_request_callback_t callback, const uint8_t *capture, size_t capture_len, void(*capture_drop)(void *), uint8_t sched_context, size_t *out_handle_id)