nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
Loading...
Searching...
No Matches
std_compat.hpp
Go to the documentation of this file.
1// nros-cpp: Optional std mode conveniences
2// Requires hosted C++ with STL — guarded by NROS_CPP_STD
3//
4// Provides:
5// A) std::function<void()> callback wrappers for Timer and GuardCondition
6// B) std::string forwarding overloads for name parameters
7// C) std::chrono::milliseconds overloads for spin/timer durations
8
16#ifndef NROS_CPP_STD_COMPAT_HPP
17#define NROS_CPP_STD_COMPAT_HPP
18
19// This header is a no-op without NROS_CPP_STD (allows freestanding syntax checks to pass).
20#ifdef NROS_CPP_STD
21
22#include <chrono>
23#include <functional>
24#include <memory>
25#include <string>
26
27namespace nros {
28
29// ============================================================================
30// A) std::function callback wrappers for Timer and GuardCondition
31// ============================================================================
32//
33// Lifetime: the heap-allocated std::function is owned by the Timer /
34// GuardCondition instance via `attach_std_closure(unique_ptr)`. The
35// runtime receives a raw pointer into the same std::function; the
36// Timer's destructor cancels the runtime callback before the
37// unique_ptr is dropped, so the raw pointer is never dereferenced
38// after free.
39
40namespace detail {
41
43inline void std_function_trampoline(void* context) {
44 auto* fn = static_cast<std::function<void()>*>(context);
45 (*fn)();
46}
47
48} // namespace detail
49
61inline Result create_wall_timer(Node& node, Timer& out, std::chrono::milliseconds period,
62 std::function<void()> callback) {
63 auto fn =
64 std::unique_ptr<std::function<void()>>(new std::function<void()>(std::move(callback)));
65 auto* raw = fn.get();
66 Result r = node.create_wall_timer(out, static_cast<uint64_t>(period.count()),
67 detail::std_function_trampoline, raw);
68 if (r.ok()) {
69 out.attach_std_closure(std::move(fn));
70 }
71 return r;
72}
73
90inline Result create_timer(Node& node, Timer& out, const Clock& clock,
91 std::chrono::milliseconds period, std::function<void()> callback) {
92 auto fn =
93 std::unique_ptr<std::function<void()>>(new std::function<void()>(std::move(callback)));
94 auto* raw = fn.get();
95 Result r = node.create_timer(out, clock, static_cast<uint64_t>(period.count()),
96 detail::std_function_trampoline, raw);
97 if (r.ok()) {
98 out.attach_std_closure(std::move(fn));
99 }
100 return r;
101}
102
107inline Result create_timer_oneshot(Node& node, Timer& out, std::chrono::milliseconds delay,
108 std::function<void()> callback) {
109 auto fn =
110 std::unique_ptr<std::function<void()>>(new std::function<void()>(std::move(callback)));
111 auto* raw = fn.get();
112 Result r = node.create_timer_oneshot(out, static_cast<uint64_t>(delay.count()),
113 detail::std_function_trampoline, raw);
114 if (r.ok()) {
115 out.attach_std_closure(std::move(fn));
116 }
117 return r;
118}
119
123inline Result create_guard_condition(Node& node, GuardCondition& out,
124 std::function<void()> callback) {
125 auto fn =
126 std::unique_ptr<std::function<void()>>(new std::function<void()>(std::move(callback)));
127 auto* raw = fn.get();
128 Result r = node.create_guard_condition(out, detail::std_function_trampoline, raw);
129 if (r.ok()) {
130 out.attach_std_closure(std::move(fn));
131 }
132 return r;
133}
134
135// ============================================================================
136// B) std::string forwarding overloads
137// ============================================================================
138
140inline Result init(const std::string& locator, uint8_t domain_id = 0) {
141 return init(locator.c_str(), domain_id);
142}
143
145inline Result create_node(Node& out, const std::string& name,
146 const std::string& ns = std::string()) {
147 return create_node(out, name.c_str(), ns.empty() ? nullptr : ns.c_str());
148}
149
150// -- Node member std::string overloads (free functions that forward) --
151
153template <typename M>
154Result create_publisher(Node& node, Publisher<M>& out, const std::string& topic,
155 const QoS& qos = QoS::default_profile()) {
156 return node.create_publisher(out, topic.c_str(), qos);
157}
158
160template <typename M>
161Result create_subscription(Node& node, Subscription<M>& out, const std::string& topic,
162 const QoS& qos = QoS::default_profile()) {
163 return node.create_subscription(out, topic.c_str(), qos);
164}
165
167template <typename S>
168Result create_service(Node& node, Service<S>& out, const std::string& service_name,
169 const QoS& qos = QoS::services()) {
170 return node.create_service(out, service_name.c_str(), qos);
171}
172
174template <typename S>
175Result create_client(Node& node, Client<S>& out, const std::string& service_name,
176 const QoS& qos = QoS::services()) {
177 return node.create_client(out, service_name.c_str(), qos);
178}
179
181template <typename A>
182Result create_action_server(Node& node, ActionServer<A>& out, const std::string& action_name,
183 const QoS& qos = QoS::services()) {
184 return node.create_action_server(out, action_name.c_str(), qos);
185}
186
188template <typename A>
189Result create_action_client(Node& node, ActionClient<A>& out, const std::string& action_name,
190 const QoS& qos = QoS::services()) {
191 return node.create_action_client(out, action_name.c_str(), qos);
192}
193
194// -- Executor std::string overloads --
195
197inline Result create_executor(Executor& out, const std::string& locator, uint8_t domain_id = 0) {
198 return Executor::create(out, locator.c_str(), domain_id);
199}
200
202inline Result create_node(Executor& exec, Node& out, const std::string& name,
203 const std::string& ns = std::string()) {
204 return exec.create_node(out, name.c_str(), ns.empty() ? nullptr : ns.c_str());
205}
206
207// ============================================================================
208// C) std::chrono duration overloads
209// ============================================================================
210
212inline Result spin_once(std::chrono::milliseconds timeout) {
213 return spin_once(static_cast<int32_t>(timeout.count()));
214}
215
217inline Result spin(std::chrono::milliseconds duration,
218 std::chrono::milliseconds poll = std::chrono::milliseconds(10)) {
219 return spin(static_cast<uint32_t>(duration.count()), static_cast<int32_t>(poll.count()));
220}
221
222} // namespace nros
223
224// -- Executor std::chrono member-like free functions --
225
226namespace nros {
227
229inline Result executor_spin_once(Executor& exec, std::chrono::milliseconds timeout) {
230 return exec.spin_once(static_cast<int32_t>(timeout.count()));
231}
232
237inline Result executor_spin_for(Executor& exec, std::chrono::milliseconds duration,
238 std::chrono::milliseconds poll = std::chrono::milliseconds(10)) {
239 return exec.spin_for(static_cast<uint32_t>(duration.count()),
240 static_cast<int32_t>(poll.count()));
241}
242
244[[deprecated("bounded spin is now `executor_spin_for(...)` (issue 0338)")]] inline Result
245executor_spin(Executor& exec, std::chrono::milliseconds duration,
246 std::chrono::milliseconds poll = std::chrono::milliseconds(10)) {
247 return executor_spin_for(exec, duration, poll);
248}
249
250} // namespace nros
251
252#endif // NROS_CPP_STD
253
254#endif // NROS_CPP_STD_COMPAT_HPP
static Result create(Executor &out, const char *locator=nullptr, uint8_t domain_id=0)
Definition executor.hpp:120
static constexpr QoS default_profile()
Default profile: RELIABLE + VOLATILE + KEEP_LAST(10).
Definition qos.hpp:328
static constexpr QoS services()
Services profile: RELIABLE + VOLATILE + KEEP_LAST(10).
Definition qos.hpp:334
Definition nros.hpp:55
Result spin()
Definition nros.hpp:157
Result spin_once(int32_t timeout_ms=10)
Definition nros.hpp:75
Result init(const char *locator=nullptr, uint8_t domain_id=0)
Definition node.hpp:824
Result create_node(Node &out, const char *name, const char *ns=nullptr)
Definition node.hpp:1008