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
11
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
90#ifndef NROS_CPP_DEPRECATED_MSG
91#if defined(__has_cpp_attribute)
92#if __has_cpp_attribute(deprecated)
93#define NROS_CPP_DEPRECATED_MSG(msg) [[deprecated(msg)]]
94#endif
95#endif
96#endif
97#ifndef NROS_CPP_DEPRECATED_MSG
98#if defined(__GNUC__) || defined(__clang__)
99#define NROS_CPP_DEPRECATED_MSG(msg) __attribute__((deprecated(msg)))
100#else
101#define NROS_CPP_DEPRECATED_MSG(msg)
102#endif
103#endif
104
105namespace rclcpp {
106
156
157// Issue #229 pin (self-consistency half): the values above ARE the shared
158// numbering. The cross-space asserts against the real C constants live in
159// parameter.hpp (vs NROS_RET_*) and node.hpp (vs NROS_CPP_RET_*), where
160// those headers are visible.
161static_assert(static_cast<int32_t>(ErrorCode::NotFound) == -4 &&
162 static_cast<int32_t>(ErrorCode::AlreadyExists) == -5 &&
163 static_cast<int32_t>(ErrorCode::Full) == -6 &&
164 static_cast<int32_t>(ErrorCode::NotInitialized) == -7 &&
165 static_cast<int32_t>(ErrorCode::TryAgain) == -14 &&
166 static_cast<int32_t>(ErrorCode::Reentrant) == -15 &&
167 static_cast<int32_t>(ErrorCode::Unsupported) == -16,
168 "ErrorCode numbering must match rcl_ret_t (issue #229)");
169
205template <typename T> class ResultOf;
206
217template <> class NROS_NODISCARD ResultOf<void> {
218 public:
220 constexpr ResultOf() : code_(ErrorCode::Ok) {}
222 constexpr ResultOf(ErrorCode code) : code_(code) {}
224 constexpr ResultOf(int32_t raw) : code_(static_cast<ErrorCode>(raw)) {}
225
227 bool ok() const { return code_ == ErrorCode::Ok; }
228
230 explicit operator bool() const { return ok(); }
231
233 ErrorCode code() const { return code_; }
234
236 int32_t raw() const { return static_cast<int32_t>(code_); }
237
239 static constexpr ResultOf success() { return ResultOf(ErrorCode::Ok); }
240
241 private:
242 ErrorCode code_;
243};
244
248
259#define RCLCPP_TRY(expr) \
260 do { \
261 ::rclcpp::Result _nros_r = (expr); \
262 if (!_nros_r.ok()) return _nros_r; \
263 } while (0)
264
278#ifndef RCLCPP_TRY_LOG
279#if defined(NROS_CPP_STD) || (__STDC_HOSTED__ + 0) // hosted-family: hosted-console
280#define RCLCPP_TRY_LOG(file, line, expr, ret) \
281 ::fprintf(stderr, "[nros] %s:%d %s -> %d\n", (file), (line), (expr), (int)(ret))
282#else
283#define RCLCPP_TRY_LOG(file, line, expr, ret) \
284 ((void)(file), (void)(line), (void)(expr), (void)(ret))
285#endif
286#endif
287
288#define RCLCPP_TRY_RET(expr, retval) \
289 do { \
290 ::rclcpp::Result _nros_r = (expr); \
291 if (!_nros_r.ok()) { \
292 RCLCPP_TRY_LOG(__FILE__, __LINE__, #expr, _nros_r.raw()); \
293 return (retval); \
294 } \
295 } while (0)
296
300#define RCLCPP_CHECK(expr) \
301 do { \
302 ::rclcpp::Result _nros_r = (expr); \
303 if (!_nros_r.ok()) { \
304 RCLCPP_TRY_LOG(__FILE__, __LINE__, #expr, _nros_r.raw()); \
305 return; \
306 } \
307 } while (0)
308
332template <typename T> class NROS_NODISCARD ResultOf {
333 public:
334 static ResultOf ok(T value) {
335 ResultOf e;
336 e.ok_ = true;
337 e.value_ = ::rclcpp::tr::forward_rvalue(value);
338 return e;
339 }
340 static ResultOf error(ErrorCode code) {
341 ResultOf e;
342 e.ok_ = false;
343 e.error_ = code;
344 return e;
345 }
346 static ResultOf error(const Result& r) { return error(r.code()); }
347
348 bool ok() const { return ok_; }
349 explicit operator bool() const { return ok_; }
350
351 T& value() & { return value_; }
352 const T& value() const& { return value_; }
353 T&& value() && { return ::rclcpp::tr::forward_rvalue(value_); }
354
355 ErrorCode error() const { return error_; }
356 Result error_as_result() const { return Result(error_); }
357
358 private:
359 ResultOf() : ok_(false), error_(ErrorCode::Error), value_() {}
360
361 bool ok_;
362 ErrorCode error_;
363 T value_;
364};
365
366} // namespace rclcpp
367
368// ============================================================================
369// rclcpp:: — the ROS 2 spelling (RFC-0089 stage 6, step A)
370// ============================================================================
371//
372// Moved here from `nros/rclcpp_compat.hpp`, which no longer carries a surface
373// of its own: RFC-0089 §"Naming: replace, with alias as the migration step"
374// makes the ROS 2 spelling a first-class name declared by the API header that
375// owns the concept, at which point a shim has nothing left to bridge.
376
377// `rclcpp::Result` is NOT an upstream rclcpp name — it is a convenience the
378// compat header carried, kept here because step A must not lose anything. It
379// re-exported `nros::Result` until phase-483 W1 made it the type itself (the
380// using-declaration below is now a no-op); RFC-0018 forbids exceptions, so
381// there is no upstream error type to adopt in its place.
382namespace rclcpp {
383using ::rclcpp::Result;
384} // namespace rclcpp
385
386#if defined(NROS_CPP_STD) // hosted-family: ported-publish
387namespace rclcpp {
388namespace detail {
396class StatementResult : public ::rclcpp::ResultOf<void> {
397 public:
398 constexpr StatementResult(::rclcpp::ResultOf<void> r) : ::rclcpp::ResultOf<void>(r) {}
399};
400} // namespace detail
401} // namespace rclcpp
402#endif
403
404#endif // NROS_RCLCPP_RESULT_HPP
int32_t raw() const
Get the raw integer code (for FFI interop).
Definition result.hpp:236
bool ok() const
Returns true if the operation succeeded.
Definition result.hpp:227
constexpr ResultOf()
Default-construct a success.
Definition result.hpp:220
ErrorCode code() const
Get the underlying error code.
Definition result.hpp:233
static constexpr ResultOf success()
Named constructors.
Definition result.hpp:239
constexpr ResultOf(int32_t raw)
Construct from a raw FFI return value (int32_t).
Definition result.hpp:224
constexpr ResultOf(ErrorCode code)
Construct from a typed code.
Definition result.hpp:222
Definition result.hpp:332
T && value() &&
Definition result.hpp:353
bool ok() const
Definition result.hpp:348
T & value() &
Definition result.hpp:351
static ResultOf error(const Result &r)
Definition result.hpp:346
ErrorCode error() const
Definition result.hpp:355
static ResultOf ok(T value)
Definition result.hpp:334
Result error_as_result() const
Definition result.hpp:356
const T & value() const &
Definition result.hpp:352
static ResultOf error(ErrorCode code)
Definition result.hpp:340
Definition rclcpp.hpp:418
Definition rclcpp.hpp:75
ErrorCode
Definition result.hpp:114
@ InvalidArgument
Null pointer, empty topic name, or out-of-range value.
Definition result.hpp:122
@ NotFound
Entity not found (topic, parameter, service…).
Definition result.hpp:124
@ Reentrant
A blocking call was made from inside a callback.
Definition result.hpp:150
@ PublishFailed
Publish failed.
Definition result.hpp:137
@ BadSequence
Operation invalid in the current state (bad call sequence).
Definition result.hpp:133
@ ServiceFailed
Service request/reply failed.
Definition result.hpp:135
@ AlreadyExists
Already exists (duplicate declare/register).
Definition result.hpp:126
@ Error
Generic failure not covered by a more specific code.
Definition result.hpp:118
@ NotInitialized
Definition result.hpp:131
@ Ok
Success.
Definition result.hpp:116
@ TransportError
Underlying zenoh-pico / DDS transport rejected the operation.
Definition result.hpp:154
@ Unsupported
Operation not implemented by the active backend.
Definition result.hpp:152
@ Full
Static pool exhausted (executor slots, subscription buffers, …).
Definition result.hpp:128
@ Timeout
Operation deadline elapsed before completion.
Definition result.hpp:120
@ Rejected
Definition result.hpp:146
@ SubscriptionFailed
Subscription create/take failed.
Definition result.hpp:139
@ TryAgain
Transient — no data ready yet (non-blocking take). Retry later.
Definition result.hpp:148
@ NotAllowed
Operation not allowed for this entity/backend.
Definition result.hpp:141
ResultOf< void > Result
Definition result.hpp:247
#define NROS_NODISCARD
Definition result.hpp:75