nros C++ API
Lightweight ROS 2 client for embedded real-time systems (C++ headers)
Loading...
Searching...
No Matches
result.hpp
Go to the documentation of this file.
1// nros-cpp: Result type for error handling
2// Freestanding C++ — no exceptions, no STL required
3
12#ifndef NROS_RCLCPP_RESULT_HPP
13#define NROS_RCLCPP_RESULT_HPP
14
15#include <cstdint>
16
17#include "rclcpp/detail/traits.hpp"
18#if defined(NROS_CPP_STD) || (__STDC_HOSTED__ + 0) // hosted-family: hosted-console
19#include <cstdio>
20// <stdio.h> + unqualified `::fprintf` (issue 0942 / phase-472 W5): `<cstdio>` need not put
21// the C names in `std` on a freestanding libstdc++, and `std::fprintf` then fails.
22#include <stdio.h>
23#endif
24
63#ifndef NROS_NODISCARD
64#if defined(__has_cpp_attribute)
65#if __has_cpp_attribute(nodiscard) >= 201603L
66#if defined(__clang__) && __cplusplus < 201703L
67#define NROS_NODISCARD __attribute__((warn_unused_result))
68#else
69#define NROS_NODISCARD [[nodiscard]]
70#endif
71#endif
72#endif
73#endif
74#ifndef NROS_NODISCARD
75#define NROS_NODISCARD
76#endif
77
89#ifndef NROS_CPP_DEPRECATED_MSG
90#if defined(__has_cpp_attribute)
91#if __has_cpp_attribute(deprecated)
92#define NROS_CPP_DEPRECATED_MSG(msg) [[deprecated(msg)]]
93#endif
94#endif
95#endif
96#ifndef NROS_CPP_DEPRECATED_MSG
97#if defined(__GNUC__) || defined(__clang__)
98#define NROS_CPP_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))
99#else
100#define NROS_CPP_DEPRECATED_MSG(msg)
101#endif
102#endif
103
104namespace rclcpp {
105
113enum class ErrorCode : int32_t {
115 Ok = 0,
117 Error = -1,
119 Timeout = -2,
121 InvalidArgument = -3,
123 NotFound = -4,
125 AlreadyExists = -5,
127 Full = -6,
130 NotInitialized = -7,
132 BadSequence = -8,
134 ServiceFailed = -9,
136 PublishFailed = -10,
138 SubscriptionFailed = -11,
140 NotAllowed = -12,
145 Rejected = -13,
147 TryAgain = -14,
149 Reentrant = -15,
151 Unsupported = -16,
153 TransportError = -100,
154};
155
156// Issue #229 pin (self-consistency half): the values above ARE the shared
157// numbering. The cross-space asserts against the real C constants live in
158// parameter.hpp (vs NROS_RET_*) and node.hpp (vs NROS_CPP_RET_*), where
159// those headers are visible.
160static_assert(static_cast<int32_t>(ErrorCode::NotFound) == -4 &&
161 static_cast<int32_t>(ErrorCode::AlreadyExists) == -5 &&
162 static_cast<int32_t>(ErrorCode::Full) == -6 &&
163 static_cast<int32_t>(ErrorCode::NotInitialized) == -7 &&
164 static_cast<int32_t>(ErrorCode::TryAgain) == -14 &&
165 static_cast<int32_t>(ErrorCode::Reentrant) == -15 &&
166 static_cast<int32_t>(ErrorCode::Unsupported) == -16,
167 "ErrorCode numbering must match rcl_ret_t (issue #229)");
168
204template <typename T> class ResultOf;
205
216template <> class NROS_NODISCARD ResultOf<void> {
217 public:
219 constexpr ResultOf() : code_(ErrorCode::Ok) {}
221 constexpr ResultOf(ErrorCode code) : code_(code) {}
223 constexpr ResultOf(int32_t raw) : code_(static_cast<ErrorCode>(raw)) {}
224
226 bool ok() const { return code_ == ErrorCode::Ok; }
227
229 explicit operator bool() const { return ok(); }
230
232 ErrorCode code() const { return code_; }
233
235 int32_t raw() const { return static_cast<int32_t>(code_); }
236
238 static constexpr ResultOf success() { return ResultOf(ErrorCode::Ok); }
239
240 private:
241 ErrorCode code_;
242};
243
247
258#define RCLCPP_TRY(expr) \
259 do { \
260 ::rclcpp::Result _nros_r = (expr); \
261 if (!_nros_r.ok()) return _nros_r; \
262 } while (0)
263
277#ifndef RCLCPP_TRY_LOG
278#if defined(NROS_CPP_STD) || (__STDC_HOSTED__ + 0) // hosted-family: hosted-console
279#define RCLCPP_TRY_LOG(file, line, expr, ret) \
280 ::fprintf(stderr, "[nros] %s:%d %s -> %d\n", (file), (line), (expr), (int)(ret))
281#else
282#define RCLCPP_TRY_LOG(file, line, expr, ret) \
283 ((void)(file), (void)(line), (void)(expr), (void)(ret))
284#endif
285#endif
286
287#define RCLCPP_TRY_RET(expr, retval) \
288 do { \
289 ::rclcpp::Result _nros_r = (expr); \
290 if (!_nros_r.ok()) { \
291 RCLCPP_TRY_LOG(__FILE__, __LINE__, #expr, _nros_r.raw()); \
292 return (retval); \
293 } \
294 } while (0)
295
299#define RCLCPP_CHECK(expr) \
300 do { \
301 ::rclcpp::Result _nros_r = (expr); \
302 if (!_nros_r.ok()) { \
303 RCLCPP_TRY_LOG(__FILE__, __LINE__, #expr, _nros_r.raw()); \
304 return; \
305 } \
306 } while (0)
307
331template <typename T> class NROS_NODISCARD ResultOf {
332 public:
333 static ResultOf ok(T value) {
334 ResultOf e;
335 e.ok_ = true;
336 e.value_ = ::rclcpp::tr::forward_rvalue(value);
337 return e;
338 }
339 static ResultOf error(ErrorCode code) {
340 ResultOf e;
341 e.ok_ = false;
342 e.error_ = code;
343 return e;
344 }
345 static ResultOf error(const Result& r) { return error(r.code()); }
346
347 bool ok() const { return ok_; }
348 explicit operator bool() const { return ok_; }
349
350 T& value() & { return value_; }
351 const T& value() const& { return value_; }
352 T&& value() && { return ::rclcpp::tr::forward_rvalue(value_); }
353
354 ErrorCode error() const { return error_; }
355 Result error_as_result() const { return Result(error_); }
356
357 private:
358 ResultOf() : ok_(false), error_(ErrorCode::Error), value_() {}
359
360 bool ok_;
361 ErrorCode error_;
362 T value_;
363};
364
365} // namespace rclcpp
366
367// ============================================================================
368// rclcpp:: — the ROS 2 spelling (RFC-0089 stage 6, step A)
369// ============================================================================
370//
371// Moved here from `nros/rclcpp_compat.hpp`, which no longer carries a surface
372// of its own: RFC-0089 §"Naming: replace, with alias as the migration step"
373// makes the ROS 2 spelling a first-class name declared by the API header that
374// owns the concept, at which point a shim has nothing left to bridge.
375
376// `rclcpp::Result` is NOT an upstream rclcpp name — it is a convenience the
377// compat header carried, kept here because step A must not lose anything. It
378// re-exported `nros::Result` until phase-483 W1 made it the type itself (the
379// using-declaration below is now a no-op); RFC-0018 forbids exceptions, so
380// there is no upstream error type to adopt in its place.
381namespace rclcpp {
382using ::rclcpp::Result;
383} // namespace rclcpp
384
385#endif // NROS_RCLCPP_RESULT_HPP
Definition client.hpp:129
Definition result.hpp:216
int32_t raw() const
Get the raw integer code (for FFI interop).
Definition result.hpp:235
bool ok() const
Returns true if the operation succeeded.
Definition result.hpp:226
constexpr ResultOf()
Default-construct a success.
Definition result.hpp:219
ErrorCode code() const
Get the underlying error code.
Definition result.hpp:232
static constexpr ResultOf success()
Named constructors.
Definition result.hpp:238
constexpr ResultOf(int32_t raw)
Construct from a raw FFI return value (int32_t).
Definition result.hpp:223
constexpr ResultOf(ErrorCode code)
Construct from a typed code.
Definition result.hpp:221
Definition result.hpp:331
T && value() &&
Definition result.hpp:352
bool ok() const
Definition result.hpp:347
T & value() &
Definition result.hpp:350
static ResultOf error(const Result &r)
Definition result.hpp:345
ErrorCode error() const
Definition result.hpp:354
static ResultOf ok(T value)
Definition result.hpp:333
Result error_as_result() const
Definition result.hpp:355
const T & value() const &
Definition result.hpp:351
static ResultOf error(ErrorCode code)
Definition result.hpp:339
Definition rclcpp.hpp:75
bool ok()
Definition node.hpp:3031
ErrorCode
Definition result.hpp:113
@ InvalidArgument
Null pointer, empty topic name, or out-of-range value.
@ NotFound
Entity not found (topic, parameter, service…).
@ Reentrant
A blocking call was made from inside a callback.
@ PublishFailed
Publish failed.
@ BadSequence
Operation invalid in the current state (bad call sequence).
@ ServiceFailed
Service request/reply failed.
@ AlreadyExists
Already exists (duplicate declare/register).
@ Error
Generic failure not covered by a more specific code.
@ TransportError
Underlying zenoh-pico / DDS transport rejected the operation.
@ Unsupported
Operation not implemented by the active backend.
@ Full
Static pool exhausted (executor slots, subscription buffers, …).
@ Timeout
Operation deadline elapsed before completion.
@ SubscriptionFailed
Subscription create/take failed.
@ TryAgain
Transient — no data ready yet (non-blocking take). Retry later.
@ NotAllowed
Operation not allowed for this entity/backend.
#define NROS_NODISCARD
Definition result.hpp:75