nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
Loading...
Searching...
No Matches
executor.hpp
Go to the documentation of this file.
1// nros-cpp: Executor class
2// Freestanding C++ — no exceptions, no STL required
3
10#ifndef NROS_CPP_EXECUTOR_HPP
11#define NROS_CPP_EXECUTOR_HPP
12
13#include <cstdint>
14#include <cstddef>
15
16#include "nros/result.hpp"
17#include "nros/nros_cpp_config_generated.h"
18
19#include "nros_cpp_ffi.h"
20
21namespace nros {
22
23// Forward declarations
24class Node;
25class NodeBuilder;
26
34using ShutdownCallback = void (*)(void* context);
35
44 public:
47 ShutdownCallbackHandle() : value_(NROS_CPP_SHUTDOWN_CALLBACK_HANDLE_INVALID) {}
48
51 explicit ShutdownCallbackHandle(nros_cpp_shutdown_callback_handle_t value) : value_(value) {}
52
54 bool valid() const { return value_ != NROS_CPP_SHUTDOWN_CALLBACK_HANDLE_INVALID; }
55
57 nros_cpp_shutdown_callback_handle_t value() const { return value_; }
58
59 private:
60 nros_cpp_shutdown_callback_handle_t value_;
61};
62
75
82
106class Executor {
107 public:
109 Executor() : storage_(), initialized_(false) {}
110
120 static Result create(Executor& out, const char* locator = nullptr, uint8_t domain_id = 0) {
121 return create(out, locator, domain_id, "nros_cpp");
122 }
123
130 static Result create(Executor& out, const char* locator, uint8_t domain_id,
131 const char* session_name) {
132 // -3 = NROS_CPP_RET_INVALID_ARGUMENT (generated header).
133 if (session_name == nullptr) {
134 return Result(-3);
135 }
136 // Issue 1050 defect (3) — the same baked RMW selector `nros::init()`
137 // reads. Both spellings of "open the one session" must apply it, or the
138 // bake means one thing on one path and nothing on the other — which is
139 // how `BACKENDS` came to read as a declaration that decided nothing.
140#ifdef NROS_ENTRY_RMW
141 const char* rmw = NROS_ENTRY_RMW;
142#else
143 const char* rmw = nullptr;
144#endif
145 nros_cpp_ret_t ret =
146 nros_cpp_init_rmw(rmw, locator, domain_id, session_name, nullptr, out.storage_);
147 if (ret == 0) {
148 out.initialized_ = true;
149 }
150 return Result(ret);
151 }
152
161 static Result create_with_rmw(Executor& out, const char* rmw, const char* locator = nullptr,
162 uint8_t domain_id = 0, const char* session_name = "nros_cpp") {
163 if (session_name == nullptr) {
164 return Result(-3);
165 }
166 nros_cpp_ret_t ret =
167 nros_cpp_init_rmw(rmw, locator, domain_id, session_name, nullptr, out.storage_);
168 if (ret == 0) {
169 out.initialized_ = true;
170 }
171 return Result(ret);
172 }
173
180 Result create_node(Node& out, const char* name, const char* ns = nullptr);
181
189 NodeBuilder node_builder(const char* name);
190
198 Result spin_once(int32_t timeout_ms = 10) {
199 if (!initialized_) return Result(ErrorCode::NotInitialized);
200 return Result(nros_cpp_spin_once(storage_, timeout_ms));
201 }
202
214 Result ping(int32_t timeout_ms) {
215 if (!initialized_) return Result(ErrorCode::NotInitialized);
216 return Result(nros_cpp_executor_ping(storage_, timeout_ms));
217 }
218
236 Result get_node_names(nros_cpp_node_visit_fn visit, void* ctx) {
237 if (!initialized_) return Result(ErrorCode::NotInitialized);
238 return Result(nros_cpp_executor_get_node_names(storage_, visit, ctx));
239 }
240
247 Result get_topic_names_and_types(nros_cpp_names_and_types_visit_fn visit, void* ctx) {
248 if (!initialized_) return Result(ErrorCode::NotInitialized);
249 return Result(nros_cpp_executor_get_topic_names_and_types(storage_, visit, ctx));
250 }
251
254 Result get_service_names_and_types(nros_cpp_names_and_types_visit_fn visit, void* ctx) {
255 if (!initialized_) return Result(ErrorCode::NotInitialized);
256 return Result(nros_cpp_executor_get_service_names_and_types(storage_, visit, ctx));
257 }
258
264 Result count_publishers(const char* topic_name, size_t* out_count) {
265 if (!initialized_) return Result(ErrorCode::NotInitialized);
266 return Result(nros_cpp_executor_count_publishers(storage_, topic_name, out_count));
267 }
268
271 Result count_subscribers(const char* topic_name, size_t* out_count) {
272 if (!initialized_) return Result(ErrorCode::NotInitialized);
273 return Result(nros_cpp_executor_count_subscribers(storage_, topic_name, out_count));
274 }
275
277 Result get_publisher_names_and_types_by_node(const char* node_name, const char* node_namespace,
278 nros_cpp_names_and_types_visit_fn visit,
279 void* ctx) {
280 if (!initialized_) return Result(ErrorCode::NotInitialized);
281 return Result(nros_cpp_executor_get_publisher_names_and_types_by_node(
282 storage_, node_name, node_namespace, visit, ctx));
283 }
284
294 const char* node_namespace,
295 nros_cpp_names_and_types_visit_fn visit,
296 void* ctx) {
297 if (!initialized_) return Result(ErrorCode::NotInitialized);
298 return Result(nros_cpp_executor_get_subscription_names_and_types_by_node(
299 storage_, node_name, node_namespace, visit, ctx));
300 }
301
303 Result get_service_names_and_types_by_node(const char* node_name, const char* node_namespace,
304 nros_cpp_names_and_types_visit_fn visit, void* ctx) {
305 if (!initialized_) return Result(ErrorCode::NotInitialized);
306 return Result(nros_cpp_executor_get_service_names_and_types_by_node(
307 storage_, node_name, node_namespace, visit, ctx));
308 }
309
311 Result get_client_names_and_types_by_node(const char* node_name, const char* node_namespace,
312 nros_cpp_names_and_types_visit_fn visit, void* ctx) {
313 if (!initialized_) return Result(ErrorCode::NotInitialized);
314 return Result(nros_cpp_executor_get_client_names_and_types_by_node(
315 storage_, node_name, node_namespace, visit, ctx));
316 }
317
324 Result get_publishers_info_by_topic(const char* topic_name,
325 nros_cpp_endpoint_info_visit_fn visit, void* ctx) {
326 if (!initialized_) return Result(ErrorCode::NotInitialized);
327 return Result(
328 nros_cpp_executor_get_publishers_info_by_topic(storage_, topic_name, visit, ctx));
329 }
330
333 nros_cpp_endpoint_info_visit_fn visit, void* ctx) {
334 if (!initialized_) return Result(ErrorCode::NotInitialized);
335 return Result(
336 nros_cpp_executor_get_subscriptions_info_by_topic(storage_, topic_name, visit, ctx));
337 }
338
354 Result spin(int32_t poll_ms = 10) {
355 if (!initialized_) return Result(ErrorCode::NotInitialized);
356 Result last = Result::success();
357 while (initialized_) {
358 last = Result(nros_cpp_spin_once(storage_, poll_ms));
359 if (!last.ok()) return last;
360 }
361 return last;
362 }
363
372 Result spin_for(uint32_t duration_ms, int32_t poll_ms = 10) {
373 if (!initialized_) return Result(ErrorCode::NotInitialized);
374 // Issue 0329 — the wall-clock budgeted loop (Phase 118.C: iteration-count
375 // budgeting collapses when `spin_once` returns early on a signaled
376 // condvar) now lives once, Rust-side, in `nros_cpp_spin_for`; forward to
377 // it so this and `nros::spin()` share one implementation.
378 return Result(nros_cpp_spin_for(storage_, duration_ms, poll_ms));
379 }
380
386 [[deprecated("bounded spin is now `spin_for(duration_ms, poll_ms)`; "
387 "`spin()` blocks until shutdown, matching rclcpp (issue 0338)")]] Result
388 spin(uint32_t duration_ms, int32_t poll_ms) {
389 return spin_for(duration_ms, poll_ms);
390 }
391
393 bool ok() const { return initialized_; }
394
401 void* handle() { return storage_; }
402
426 Result add_pre_shutdown_callback(ShutdownCallback callback, void* context = nullptr,
427 PreShutdownCallbackHandle* out = nullptr) {
428 if (!initialized_) return Result(ErrorCode::NotInitialized);
429 nros_cpp_shutdown_callback_handle_t raw = NROS_CPP_SHUTDOWN_CALLBACK_HANDLE_INVALID;
430 nros_cpp_ret_t ret = nros_cpp_add_pre_shutdown_callback(storage_, callback, context, &raw);
431 if (out != nullptr) *out = PreShutdownCallbackHandle(raw);
432 return Result(ret);
433 }
434
444 Result add_on_shutdown_callback(ShutdownCallback callback, void* context = nullptr,
445 OnShutdownCallbackHandle* out = nullptr) {
446 if (!initialized_) return Result(ErrorCode::NotInitialized);
447 nros_cpp_shutdown_callback_handle_t raw = NROS_CPP_SHUTDOWN_CALLBACK_HANDLE_INVALID;
448 nros_cpp_ret_t ret = nros_cpp_add_on_shutdown_callback(storage_, callback, context, &raw);
449 if (out != nullptr) *out = OnShutdownCallbackHandle(raw);
450 return Result(ret);
451 }
452
461 if (!initialized_) return false;
462 return nros_cpp_remove_pre_shutdown_callback(storage_, handle.value()) == 0;
463 }
464
469 if (!initialized_) return false;
470 return nros_cpp_remove_on_shutdown_callback(storage_, handle.value()) == 0;
471 }
472
475 if (!initialized_) return Result::success();
476 nros_cpp_ret_t ret = nros_cpp_fini(storage_);
477 initialized_ = false;
478 return Result(ret);
479 }
480
483 if (initialized_) {
484 nros_cpp_fini(storage_);
485 initialized_ = false;
486 }
487 }
488
489 // Move semantics (non-copyable)
490 Executor(Executor&& other) : initialized_(other.initialized_) {
491 for (unsigned i = 0; i < sizeof(storage_); ++i) {
492 storage_[i] = other.storage_[i];
493 other.storage_[i] = 0;
494 }
495 other.initialized_ = false;
496 }
497
499 if (this != &other) {
500 if (initialized_) {
501 nros_cpp_fini(storage_);
502 }
503 for (unsigned i = 0; i < sizeof(storage_); ++i) {
504 storage_[i] = other.storage_[i];
505 other.storage_[i] = 0;
506 }
507 initialized_ = other.initialized_;
508 other.initialized_ = false;
509 }
510 return *this;
511 }
512
513 private:
514 Executor(const Executor&) = delete;
515 Executor& operator=(const Executor&) = delete;
516
517 alignas(8) uint8_t storage_[NROS_CPP_EXECUTOR_STORAGE_SIZE];
518 bool initialized_;
519};
520
521} // namespace nros
522
523#endif // NROS_CPP_EXECUTOR_HPP
Definition executor.hpp:106
Result get_client_names_and_types_by_node(const char *node_name, const char *node_namespace, nros_cpp_names_and_types_visit_fn visit, void *ctx)
phase-381 W4 — what services one named node CALLS, with the types.
Definition executor.hpp:311
Executor()
Default constructor — creates an uninitialized executor.
Definition executor.hpp:109
Result ping(int32_t timeout_ms)
Definition executor.hpp:214
NodeBuilder node_builder(const char *name)
Definition node.hpp:1147
Executor & operator=(Executor &&other)
Definition executor.hpp:498
Result get_node_names(nros_cpp_node_visit_fn visit, void *ctx)
Definition executor.hpp:236
~Executor()
Destructor — shuts down if still active.
Definition executor.hpp:482
static Result create(Executor &out, const char *locator=nullptr, uint8_t domain_id=0)
Definition executor.hpp:120
Result get_publishers_info_by_topic(const char *topic_name, nros_cpp_endpoint_info_visit_fn visit, void *ctx)
Definition executor.hpp:324
bool ok() const
Check if the executor is initialized.
Definition executor.hpp:393
Result get_topic_names_and_types(nros_cpp_names_and_types_visit_fn visit, void *ctx)
Definition executor.hpp:247
Result get_subscriptions_info_by_topic(const char *topic_name, nros_cpp_endpoint_info_visit_fn visit, void *ctx)
phase-381 W4 — the subscriptions on topic_name, one visit each.
Definition executor.hpp:332
bool remove_on_shutdown_callback(OnShutdownCallbackHandle handle)
Definition executor.hpp:468
Result get_subscription_names_and_types_by_node(const char *node_name, const char *node_namespace, nros_cpp_names_and_types_visit_fn visit, void *ctx)
Definition executor.hpp:293
void * handle()
Definition executor.hpp:401
Result shutdown()
Shut down the executor and close the middleware connection.
Definition executor.hpp:474
Result spin_once(int32_t timeout_ms=10)
Definition executor.hpp:198
Result count_publishers(const char *topic_name, size_t *out_count)
Definition executor.hpp:264
static Result create(Executor &out, const char *locator, uint8_t domain_id, const char *session_name)
Definition executor.hpp:130
Result get_service_names_and_types(nros_cpp_names_and_types_visit_fn visit, void *ctx)
Definition executor.hpp:254
Result get_service_names_and_types_by_node(const char *node_name, const char *node_namespace, nros_cpp_names_and_types_visit_fn visit, void *ctx)
phase-381 W4 — what services one named node SERVES, with the types.
Definition executor.hpp:303
bool remove_pre_shutdown_callback(PreShutdownCallbackHandle handle)
Definition executor.hpp:460
Result spin(int32_t poll_ms=10)
Definition executor.hpp:354
Result count_subscribers(const char *topic_name, size_t *out_count)
Definition executor.hpp:271
Result add_pre_shutdown_callback(ShutdownCallback callback, void *context=nullptr, PreShutdownCallbackHandle *out=nullptr)
Definition executor.hpp:426
static Result create_with_rmw(Executor &out, const char *rmw, const char *locator=nullptr, uint8_t domain_id=0, const char *session_name="nros_cpp")
Definition executor.hpp:161
Result get_publisher_names_and_types_by_node(const char *node_name, const char *node_namespace, nros_cpp_names_and_types_visit_fn visit, void *ctx)
phase-381 W4 — what one named node PUBLISHES, with the types.
Definition executor.hpp:277
Result add_on_shutdown_callback(ShutdownCallback callback, void *context=nullptr, OnShutdownCallbackHandle *out=nullptr)
Definition executor.hpp:444
Result spin(uint32_t duration_ms, int32_t poll_ms)
Definition executor.hpp:388
Result spin_for(uint32_t duration_ms, int32_t poll_ms=10)
Definition executor.hpp:372
Executor(Executor &&other)
Definition executor.hpp:490
Result create_node(Node &out, const char *name, const char *ns=nullptr)
Definition node.hpp:1048
Definition node.hpp:1071
Definition node.hpp:211
Definition executor.hpp:78
Definition executor.hpp:71
Definition result.hpp:90
static constexpr Result success()
Named constructors.
Definition result.hpp:112
bool ok() const
Returns true if the operation succeeded.
Definition result.hpp:100
Definition executor.hpp:43
ShutdownCallbackHandle(nros_cpp_shutdown_callback_handle_t value)
Definition executor.hpp:51
bool valid() const
True when this handle came from a successful registration.
Definition executor.hpp:54
ShutdownCallbackHandle()
Definition executor.hpp:47
nros_cpp_shutdown_callback_handle_t value() const
The raw FFI value, for passing to the C entry points directly.
Definition executor.hpp:57
int nros_cpp_ret_t
Definition future.hpp:21
nros_cpp_ret_t nros_cpp_spin_once(void *handle, int32_t timeout_ms)
Definition nros.hpp:55
void(*)(void *context) ShutdownCallback
Definition executor.hpp:34
nros::Result, nros::ErrorCode, and the NROS_TRY macro.