1extern crate alloc;
8use alloc::string::String;
9
10#[derive(Debug, Clone, PartialEq, Eq)]
15#[non_exhaustive]
16pub enum DdsError {
17 BadParameter {
19 what: &'static str,
21 },
22 PreconditionNotMet {
25 reason: &'static str,
27 },
28 WireError {
30 message: String,
32 },
33 InconsistentPolicy {
37 what: &'static str,
39 },
40 TransportError {
42 label: &'static str,
44 },
45 OutOfResources {
47 what: &'static str,
49 },
50 Timeout,
52 Unsupported {
54 feature: &'static str,
56 },
57 NotAllowedBySecurity {
63 what: &'static str,
65 },
66 IllegalOperation {
70 what: &'static str,
72 },
73 ImmutablePolicy {
76 policy: &'static str,
78 },
79 AlreadyDeleted,
82 NoData,
86 Other {
90 reason: &'static str,
92 },
93 NotEnabled,
98}
99
100impl core::fmt::Display for DdsError {
101 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
102 match self {
103 Self::BadParameter { what } => write!(f, "bad parameter: {what}"),
104 Self::PreconditionNotMet { reason } => write!(f, "precondition not met: {reason}"),
105 Self::WireError { message } => write!(f, "wire/cdr error: {message}"),
106 Self::InconsistentPolicy { what } => write!(f, "inconsistent qos policy: {what}"),
107 Self::TransportError { label } => write!(f, "transport error: {label}"),
108 Self::OutOfResources { what } => write!(f, "out of resources: {what}"),
109 Self::Timeout => f.write_str("dds timeout"),
110 Self::Unsupported { feature } => write!(f, "not supported in v1.2: {feature}"),
111 Self::NotAllowedBySecurity { what } => {
112 write!(f, "not allowed by security policy: {what}")
113 }
114 Self::IllegalOperation { what } => write!(f, "illegal operation: {what}"),
115 Self::ImmutablePolicy { policy } => {
116 write!(f, "qos policy is immutable post-enable: {policy}")
117 }
118 Self::AlreadyDeleted => f.write_str("entity already deleted"),
119 Self::NoData => f.write_str("no data available"),
120 Self::Other { reason } => write!(f, "dds error: {reason}"),
121 Self::NotEnabled => f.write_str("entity not enabled"),
122 }
123 }
124}
125
126pub mod return_code {
130 pub const OK: i32 = 0;
132 pub const ERROR: i32 = 1;
134 pub const UNSUPPORTED: i32 = 2;
136 pub const BAD_PARAMETER: i32 = 3;
138 pub const PRECONDITION_NOT_MET: i32 = 4;
140 pub const OUT_OF_RESOURCES: i32 = 5;
142 pub const NOT_ENABLED: i32 = 6;
144 pub const IMMUTABLE_POLICY: i32 = 7;
146 pub const INCONSISTENT_POLICY: i32 = 8;
148 pub const ALREADY_DELETED: i32 = 9;
150 pub const TIMEOUT: i32 = 10;
152 pub const NO_DATA: i32 = 11;
154 pub const ILLEGAL_OPERATION: i32 = 12;
156 pub const NOT_ALLOWED_BY_SECURITY: i32 = 13;
158}
159
160impl DdsError {
161 #[must_use]
166 pub fn as_return_code(&self) -> i32 {
167 match self {
168 Self::BadParameter { .. } => return_code::BAD_PARAMETER,
169 Self::PreconditionNotMet { .. } => return_code::PRECONDITION_NOT_MET,
170 Self::WireError { .. } | Self::TransportError { .. } | Self::Other { .. } => {
171 return_code::ERROR
172 }
173 Self::InconsistentPolicy { .. } => return_code::INCONSISTENT_POLICY,
174 Self::OutOfResources { .. } => return_code::OUT_OF_RESOURCES,
175 Self::Timeout => return_code::TIMEOUT,
176 Self::Unsupported { .. } => return_code::UNSUPPORTED,
177 Self::NotAllowedBySecurity { .. } => return_code::NOT_ALLOWED_BY_SECURITY,
178 Self::IllegalOperation { .. } => return_code::ILLEGAL_OPERATION,
179 Self::ImmutablePolicy { .. } => return_code::IMMUTABLE_POLICY,
180 Self::AlreadyDeleted => return_code::ALREADY_DELETED,
181 Self::NoData => return_code::NO_DATA,
182 Self::NotEnabled => return_code::NOT_ENABLED,
183 }
184 }
185}
186
187#[cfg(feature = "std")]
188impl std::error::Error for DdsError {}
189
190pub type Result<T> = core::result::Result<T, DdsError>;
192
193#[cfg(test)]
194#[allow(clippy::expect_used)]
195mod tests {
196 use super::*;
197
198 #[test]
201 fn rc_error_maps_for_wire_and_transport_and_other() {
202 assert_eq!(
204 DdsError::WireError {
205 message: "x".into()
206 }
207 .as_return_code(),
208 return_code::ERROR
209 );
210 assert_eq!(
211 DdsError::TransportError { label: "y" }.as_return_code(),
212 return_code::ERROR
213 );
214 assert_eq!(
215 DdsError::Other { reason: "z" }.as_return_code(),
216 return_code::ERROR
217 );
218 }
219
220 #[test]
221 fn rc_unsupported_maps() {
222 assert_eq!(
223 DdsError::Unsupported { feature: "f" }.as_return_code(),
224 return_code::UNSUPPORTED
225 );
226 }
227
228 #[test]
229 fn rc_bad_parameter_maps() {
230 assert_eq!(
231 DdsError::BadParameter { what: "p" }.as_return_code(),
232 return_code::BAD_PARAMETER
233 );
234 }
235
236 #[test]
237 fn rc_precondition_not_met_maps() {
238 assert_eq!(
239 DdsError::PreconditionNotMet { reason: "r" }.as_return_code(),
240 return_code::PRECONDITION_NOT_MET
241 );
242 }
243
244 #[test]
245 fn rc_out_of_resources_maps() {
246 assert_eq!(
247 DdsError::OutOfResources { what: "samples" }.as_return_code(),
248 return_code::OUT_OF_RESOURCES
249 );
250 }
251
252 #[test]
253 fn rc_not_enabled_maps() {
254 assert_eq!(
255 DdsError::NotEnabled.as_return_code(),
256 return_code::NOT_ENABLED
257 );
258 }
259
260 #[test]
261 fn rc_immutable_policy_maps() {
262 assert_eq!(
263 DdsError::ImmutablePolicy {
264 policy: "Reliability"
265 }
266 .as_return_code(),
267 return_code::IMMUTABLE_POLICY
268 );
269 }
270
271 #[test]
272 fn rc_inconsistent_policy_maps() {
273 assert_eq!(
274 DdsError::InconsistentPolicy { what: "x" }.as_return_code(),
275 return_code::INCONSISTENT_POLICY
276 );
277 }
278
279 #[test]
280 fn rc_already_deleted_maps() {
281 assert_eq!(
282 DdsError::AlreadyDeleted.as_return_code(),
283 return_code::ALREADY_DELETED
284 );
285 }
286
287 #[test]
288 fn rc_timeout_maps() {
289 assert_eq!(DdsError::Timeout.as_return_code(), return_code::TIMEOUT);
290 }
291
292 #[test]
293 fn rc_no_data_maps() {
294 assert_eq!(DdsError::NoData.as_return_code(), return_code::NO_DATA);
295 }
296
297 #[test]
298 fn rc_illegal_operation_maps() {
299 assert_eq!(
300 DdsError::IllegalOperation {
301 what: "write_on_reader"
302 }
303 .as_return_code(),
304 return_code::ILLEGAL_OPERATION
305 );
306 }
307
308 #[test]
309 fn rc_not_allowed_by_security_maps() {
310 assert_eq!(
311 DdsError::NotAllowedBySecurity { what: "topic" }.as_return_code(),
312 return_code::NOT_ALLOWED_BY_SECURITY
313 );
314 }
315
316 #[test]
317 fn rc_constants_have_spec_values() {
318 assert_eq!(return_code::OK, 0);
321 assert_eq!(return_code::ERROR, 1);
322 assert_eq!(return_code::UNSUPPORTED, 2);
323 assert_eq!(return_code::BAD_PARAMETER, 3);
324 assert_eq!(return_code::PRECONDITION_NOT_MET, 4);
325 assert_eq!(return_code::OUT_OF_RESOURCES, 5);
326 assert_eq!(return_code::NOT_ENABLED, 6);
327 assert_eq!(return_code::IMMUTABLE_POLICY, 7);
328 assert_eq!(return_code::INCONSISTENT_POLICY, 8);
329 assert_eq!(return_code::ALREADY_DELETED, 9);
330 assert_eq!(return_code::TIMEOUT, 10);
331 assert_eq!(return_code::NO_DATA, 11);
332 assert_eq!(return_code::ILLEGAL_OPERATION, 12);
333 assert_eq!(return_code::NOT_ALLOWED_BY_SECURITY, 13);
334 }
335
336 #[test]
337 fn rc_display_does_not_leak_security_details() {
338 let e = DdsError::NotAllowedBySecurity { what: "Topic A" };
341 let s = format!("{e}");
342 assert!(s.contains("not allowed by security"));
343 assert!(s.contains("Topic A"));
344 assert!(!s.to_lowercase().contains("permission file"));
346 assert!(!s.to_lowercase().contains("ca cert"));
347 }
348}