do_not_use_testing_rclrs/
error.rs1use std::error::Error;
2use std::ffi::{CStr, NulError};
3use std::fmt::{self, Display};
4
5use crate::rcl_bindings::*;
6
7#[derive(Debug, PartialEq, Eq)]
9pub enum RclrsError {
10 RclError {
12 code: RclReturnCode,
14 msg: Option<RclErrorMsg>,
16 },
17 UnknownRclError {
19 code: i32,
21 msg: Option<RclErrorMsg>,
23 },
24 StringContainsNul {
26 s: String,
28 err: NulError,
30 },
31 AlreadyAddedToWaitSet,
33}
34
35impl Display for RclrsError {
36 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
37 match self {
38 RclrsError::RclError { code, .. } => write!(f, "{}", code),
39 RclrsError::UnknownRclError { code, .. } => write!(f, "{}", code),
40 RclrsError::StringContainsNul { s, .. } => {
41 write!(f, "Could not convert string '{}' to CString", s)
42 }
43 RclrsError::AlreadyAddedToWaitSet => {
44 write!(
45 f,
46 "Could not add entity to wait set because it was already added to a wait set"
47 )
48 }
49 }
50 }
51}
52
53#[derive(Debug, PartialEq, Eq)]
64pub struct RclErrorMsg(String);
65
66impl Display for RclErrorMsg {
67 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68 write!(f, "{}", self.0)
69 }
70}
71
72impl Error for RclErrorMsg {}
73
74impl Error for RclrsError {
75 fn source(&self) -> Option<&(dyn Error + 'static)> {
76 match self {
77 RclrsError::RclError { msg, .. } => msg.as_ref().map(|e| e as &dyn Error),
78 RclrsError::UnknownRclError { msg, .. } => msg.as_ref().map(|e| e as &dyn Error),
79 RclrsError::StringContainsNul { err, .. } => Some(err).map(|e| e as &dyn Error),
80 RclrsError::AlreadyAddedToWaitSet => None,
81 }
82 }
83}
84
85#[repr(i32)]
91#[derive(Debug, PartialEq, Eq)]
92pub enum RclReturnCode {
93 Ok = 0,
95 Error = 1,
97 Timeout = 2,
99 Unsupported = 3,
101 BadAlloc = 10,
103 InvalidArgument = 11,
105 AlreadyInit = 100,
108 NotInit = 101,
110 MismatchedRmwId = 102,
112 TopicNameInvalid = 103,
114 ServiceNameInvalid = 104,
116 UnknownSubstitution = 105,
118 AlreadyShutdown = 106,
120 NodeInvalid = 200,
123 NodeInvalidName = 201,
125 NodeInvalidNamespace = 202,
127 NodeNameNonexistent = 203,
129 PublisherInvalid = 300,
132 SubscriptionInvalid = 400,
135 SubscriptionTakeFailed = 401,
137 ClientInvalid = 500,
140 ClientTakeFailed = 501,
142 ServiceInvalid = 600,
145 ServiceTakeFailed = 601,
147 TimerInvalid = 800,
150 TimerCanceled = 801,
152 WaitSetInvalid = 900,
155 WaitSetEmpty = 901,
157 WaitSetFull = 902,
159 InvalidRemapRule = 1001,
162 WrongLexeme = 1002,
164 InvalidRosArgs = 1003,
166 InvalidParamRule = 1010,
168 InvalidLogLevelRule = 1020,
170 EventInvalid = 2000,
173 EventTakeFailed = 2001,
175 LifecycleStateRegistered = 3000,
178 LifecycleStateNotRegistered = 3001,
180}
181
182impl TryFrom<i32> for RclReturnCode {
183 type Error = i32;
184
185 fn try_from(value: i32) -> Result<Self, i32> {
186 let code = match value {
187 x if x == Self::Ok as i32 => Self::Ok,
188 x if x == Self::Error as i32 => Self::Error,
189 x if x == Self::Timeout as i32 => Self::Timeout,
190 x if x == Self::Unsupported as i32 => Self::Unsupported,
191 x if x == Self::BadAlloc as i32 => Self::BadAlloc,
192 x if x == Self::InvalidArgument as i32 => Self::InvalidArgument,
193 x if x == Self::AlreadyInit as i32 => Self::AlreadyInit,
194 x if x == Self::NotInit as i32 => Self::NotInit,
195 x if x == Self::MismatchedRmwId as i32 => Self::MismatchedRmwId,
196 x if x == Self::TopicNameInvalid as i32 => Self::TopicNameInvalid,
197 x if x == Self::ServiceNameInvalid as i32 => Self::ServiceNameInvalid,
198 x if x == Self::UnknownSubstitution as i32 => Self::UnknownSubstitution,
199 x if x == Self::AlreadyShutdown as i32 => Self::AlreadyShutdown,
200 x if x == Self::NodeInvalid as i32 => Self::NodeInvalid,
201 x if x == Self::NodeInvalidName as i32 => Self::NodeInvalidName,
202 x if x == Self::NodeInvalidNamespace as i32 => Self::NodeInvalidNamespace,
203 x if x == Self::NodeNameNonexistent as i32 => Self::NodeNameNonexistent,
204 x if x == Self::PublisherInvalid as i32 => Self::PublisherInvalid,
205 x if x == Self::SubscriptionInvalid as i32 => Self::SubscriptionInvalid,
206 x if x == Self::SubscriptionTakeFailed as i32 => Self::SubscriptionTakeFailed,
207 x if x == Self::ClientInvalid as i32 => Self::ClientInvalid,
208 x if x == Self::ClientTakeFailed as i32 => Self::ClientTakeFailed,
209 x if x == Self::ServiceInvalid as i32 => Self::ServiceInvalid,
210 x if x == Self::ServiceTakeFailed as i32 => Self::ServiceTakeFailed,
211 x if x == Self::TimerInvalid as i32 => Self::TimerInvalid,
212 x if x == Self::TimerCanceled as i32 => Self::TimerCanceled,
213 x if x == Self::WaitSetInvalid as i32 => Self::WaitSetInvalid,
214 x if x == Self::WaitSetEmpty as i32 => Self::WaitSetEmpty,
215 x if x == Self::WaitSetFull as i32 => Self::WaitSetFull,
216 x if x == Self::InvalidRemapRule as i32 => Self::InvalidRemapRule,
217 x if x == Self::WrongLexeme as i32 => Self::WrongLexeme,
218 x if x == Self::InvalidRosArgs as i32 => Self::InvalidRosArgs,
219 x if x == Self::InvalidParamRule as i32 => Self::InvalidParamRule,
220 x if x == Self::InvalidLogLevelRule as i32 => Self::InvalidLogLevelRule,
221 x if x == Self::EventInvalid as i32 => Self::EventInvalid,
222 x if x == Self::EventTakeFailed as i32 => Self::EventTakeFailed,
223 x if x == Self::LifecycleStateRegistered as i32 => Self::LifecycleStateRegistered,
224 x if x == Self::LifecycleStateNotRegistered as i32 => Self::LifecycleStateNotRegistered,
225 other => {
226 return Err(other);
227 }
228 };
229 Ok(code)
230 }
231}
232
233impl Display for RclReturnCode {
234 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
235 let s = match self {
236 Self::Ok => "Operation successful (RCL_RET_OK).",
237 Self::Error => "Unspecified error (RCL_RET_ERROR).",
238 Self::Timeout => "Timeout occurred (RCL_RET_TIMEOUT).",
239 Self::Unsupported => "Unsupported return code (RCL_RET_UNSUPPORTED).",
240 Self::BadAlloc => "Failed to allocate memory (RCL_RET_BAD_ALLOC).",
241 Self::InvalidArgument => "Argument to function was invalid (RCL_RET_INVALID_ARGUMENT).",
242 Self::AlreadyInit => "`rcl_init()` already called (RCL_RET_ALREADY_INIT).",
243 Self::NotInit => "`rcl_init() not yet called (RCL_RET_NOT_INIT).",
244 Self::MismatchedRmwId => "Mismatched rmw identifier (RCL_RET_MISMATCHED_RMW_ID).",
245 Self::TopicNameInvalid => {
246 "Topic name does not pass validation (RCL_RET_TOPIC_NAME_INVALID)."
247 }
248 Self::ServiceNameInvalid => {
249 "Service name does not pass validation (RCL_RET_SERVICE_NAME_INVALID)."
250 }
251 Self::UnknownSubstitution => {
252 "Topic name substitution is unknown (RCL_RET_UNKNOWN_SUBSTITUTION)."
253 }
254 Self::AlreadyShutdown => "`rcl_shutdown()` already called (RCL_RET_ALREADY_SHUTDOWN).",
255 Self::NodeInvalid => "Invalid `rcl_node_t` given (RCL_RET_NODE_INVALID).",
256 Self::NodeInvalidName => "Invalid node name (RCL_RET_NODE_INVALID_NAME).",
257 Self::NodeInvalidNamespace => {
258 "Invalid node namespace (RCL_RET_NODE_INVALID_NAMESPACE)."
259 }
260 Self::NodeNameNonexistent => {
261 "Failed to find node name (RCL_RET_NODE_NAME_NON_EXISTENT)."
262 }
263 Self::PublisherInvalid => {
264 "Invalid `rcl_publisher_t` given (RCL_RET_PUBLISHER_INVALID)."
265 }
266 Self::SubscriptionInvalid => {
267 "Invalid `rcl_subscription_t` given (RCL_RET_SUBSCRIPTION_INVALID)."
268 }
269 Self::SubscriptionTakeFailed => {
270 "Failed to take a message from the subscription (RCL_RET_SUBSCRIPTION_TAKE_FAILED)."
271 }
272 Self::ClientInvalid => "Invalid `rcl_client_t` given (RCL_RET_CLIENT_INVALID).",
273 Self::ClientTakeFailed => {
274 "Failed to take a response from the client (RCL_RET_CLIENT_TAKE_FAILED)."
275 }
276 Self::ServiceInvalid => "Invalid `rcl_service_t` given (RCL_RET_SERVICE_INVALID).",
277 Self::ServiceTakeFailed => {
278 "Failed to take a request from the service (RCL_RET_SERVICE_TAKE_FAILED)."
279 }
280 Self::TimerInvalid => "Invalid `rcl_timer_t` given (RCL_RET_TIMER_INVALID).",
281 Self::TimerCanceled => "Given timer was canceled (RCL_RET_TIMER_CANCELED).",
282 Self::WaitSetInvalid => "Invalid `rcl_wait_set_t` given (RCL_RET_WAIT_SET_INVALID).",
283 Self::WaitSetEmpty => "Given `rcl_wait_set_t` was empty (RCL_RET_WAIT_SET_EMPTY).",
284 Self::WaitSetFull => "Given `rcl_wait_set_t` was full (RCL_RET_WAIT_SET_FULL).",
285 Self::InvalidRemapRule => {
286 "Argument is not a valid remap rule (RCL_RET_INVALID_REMAP_RULE)."
287 }
288 Self::WrongLexeme => {
289 "Expected one type of lexeme, but got another (RCL_RET_WRONG_LEXEME)"
290 }
291 Self::InvalidRosArgs => {
292 "Found invalid ROS argument while parsing (RCL_RET_INVALID_ROS_ARGS)."
293 }
294 Self::InvalidParamRule => {
295 "Argument is not a valid parameter rule (RCL_RET_INVALID_PARAM_RULE)."
296 }
297 Self::InvalidLogLevelRule => {
298 "Argument is not a valid log level rule (RCL_RET_INVALID_LOG_LEVEL_RULE)."
299 }
300 Self::EventInvalid => "Invalid `rcl_event_t` given (RCL_RET_EVENT_INVALID).",
301 Self::EventTakeFailed => {
302 "Failed to take an event from the event handle (RCL_RET_EVENT_TAKE_FAILED)."
303 }
304 Self::LifecycleStateRegistered => {
305 "`rcl_lifecycle` state registered (RCL_RET_LIFECYCLE_STATE_REGISTERED)."
306 }
307 Self::LifecycleStateNotRegistered => {
308 "`rcl_lifecycle` state not registered (RCL_RET_LIFECYCLE_STATE_NOT_REGISTERED)."
309 }
310 };
311 write!(f, "{}", s)
312 }
313}
314
315impl Error for RclReturnCode {}
316
317pub(crate) fn to_rclrs_result(ret: i32) -> Result<(), RclrsError> {
318 if ret == 0 {
319 return Ok(());
320 }
321 let mut msg = None;
322 let error_state_ptr = unsafe { rcutils_get_error_state() };
324 if !error_state_ptr.is_null() {
326 let msg_ptr = unsafe { (*error_state_ptr).message.as_ptr() };
328 let s = unsafe { CStr::from_ptr(msg_ptr) }
331 .to_string_lossy()
332 .into_owned();
333 msg = Some(RclErrorMsg(s));
334 }
335 unsafe { rcutils_reset_error() };
337 Err(match RclReturnCode::try_from(ret) {
339 Ok(code) => RclrsError::RclError { code, msg },
340 Err(code) => RclrsError::UnknownRclError { code, msg },
341 })
342}
343
344pub(crate) trait ToResult {
345 fn ok(&self) -> Result<(), RclrsError>;
346}
347
348impl ToResult for rcl_ret_t {
349 fn ok(&self) -> Result<(), RclrsError> {
350 to_rclrs_result(*self)
351 }
352}