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 {
91 reason: &'static str,
93 },
94 NotEnabled,
99}
100
101impl core::fmt::Display for DdsError {
102 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
103 match self {
104 Self::BadParameter { what } => write!(f, "bad parameter: {what}"),
105 Self::PreconditionNotMet { reason } => write!(f, "precondition not met: {reason}"),
106 Self::WireError { message } => write!(f, "wire/cdr error: {message}"),
107 Self::InconsistentPolicy { what } => write!(f, "inconsistent qos policy: {what}"),
108 Self::TransportError { label } => write!(f, "transport error: {label}"),
109 Self::OutOfResources { what } => write!(f, "out of resources: {what}"),
110 Self::Timeout => f.write_str("dds timeout"),
111 Self::Unsupported { feature } => write!(f, "not supported in v1.2: {feature}"),
112 Self::NotAllowedBySecurity { what } => {
113 write!(f, "not allowed by security policy: {what}")
114 }
115 Self::IllegalOperation { what } => write!(f, "illegal operation: {what}"),
116 Self::ImmutablePolicy { policy } => {
117 write!(f, "qos policy is immutable post-enable: {policy}")
118 }
119 Self::AlreadyDeleted => f.write_str("entity already deleted"),
120 Self::NoData => f.write_str("no data available"),
121 Self::Other { reason } => write!(f, "dds error: {reason}"),
122 Self::NotEnabled => f.write_str("entity not enabled"),
123 }
124 }
125}
126
127pub mod return_code {
131 pub const OK: i32 = 0;
133 pub const ERROR: i32 = 1;
135 pub const UNSUPPORTED: i32 = 2;
137 pub const BAD_PARAMETER: i32 = 3;
139 pub const PRECONDITION_NOT_MET: i32 = 4;
141 pub const OUT_OF_RESOURCES: i32 = 5;
143 pub const NOT_ENABLED: i32 = 6;
145 pub const IMMUTABLE_POLICY: i32 = 7;
147 pub const INCONSISTENT_POLICY: i32 = 8;
149 pub const ALREADY_DELETED: i32 = 9;
151 pub const TIMEOUT: i32 = 10;
153 pub const NO_DATA: i32 = 11;
155 pub const ILLEGAL_OPERATION: i32 = 12;
157 pub const NOT_ALLOWED_BY_SECURITY: i32 = 13;
159}
160
161impl DdsError {
162 #[must_use]
167 pub fn as_return_code(&self) -> i32 {
168 match self {
169 Self::BadParameter { .. } => return_code::BAD_PARAMETER,
170 Self::PreconditionNotMet { .. } => return_code::PRECONDITION_NOT_MET,
171 Self::WireError { .. } | Self::TransportError { .. } | Self::Other { .. } => {
172 return_code::ERROR
173 }
174 Self::InconsistentPolicy { .. } => return_code::INCONSISTENT_POLICY,
175 Self::OutOfResources { .. } => return_code::OUT_OF_RESOURCES,
176 Self::Timeout => return_code::TIMEOUT,
177 Self::Unsupported { .. } => return_code::UNSUPPORTED,
178 Self::NotAllowedBySecurity { .. } => return_code::NOT_ALLOWED_BY_SECURITY,
179 Self::IllegalOperation { .. } => return_code::ILLEGAL_OPERATION,
180 Self::ImmutablePolicy { .. } => return_code::IMMUTABLE_POLICY,
181 Self::AlreadyDeleted => return_code::ALREADY_DELETED,
182 Self::NoData => return_code::NO_DATA,
183 Self::NotEnabled => return_code::NOT_ENABLED,
184 }
185 }
186}
187
188#[cfg(feature = "std")]
189impl std::error::Error for DdsError {}
190
191pub type Result<T> = core::result::Result<T, DdsError>;
193
194#[cfg(test)]
195#[allow(clippy::expect_used)]
196mod tests {
197 use super::*;
198
199 #[test]
202 fn rc_error_maps_for_wire_and_transport_and_other() {
203 assert_eq!(
205 DdsError::WireError {
206 message: "x".into()
207 }
208 .as_return_code(),
209 return_code::ERROR
210 );
211 assert_eq!(
212 DdsError::TransportError { label: "y" }.as_return_code(),
213 return_code::ERROR
214 );
215 assert_eq!(
216 DdsError::Other { reason: "z" }.as_return_code(),
217 return_code::ERROR
218 );
219 }
220
221 #[test]
222 fn rc_unsupported_maps() {
223 assert_eq!(
224 DdsError::Unsupported { feature: "f" }.as_return_code(),
225 return_code::UNSUPPORTED
226 );
227 }
228
229 #[test]
230 fn rc_bad_parameter_maps() {
231 assert_eq!(
232 DdsError::BadParameter { what: "p" }.as_return_code(),
233 return_code::BAD_PARAMETER
234 );
235 }
236
237 #[test]
238 fn rc_precondition_not_met_maps() {
239 assert_eq!(
240 DdsError::PreconditionNotMet { reason: "r" }.as_return_code(),
241 return_code::PRECONDITION_NOT_MET
242 );
243 }
244
245 #[test]
246 fn rc_out_of_resources_maps() {
247 assert_eq!(
248 DdsError::OutOfResources { what: "samples" }.as_return_code(),
249 return_code::OUT_OF_RESOURCES
250 );
251 }
252
253 #[test]
254 fn rc_not_enabled_maps() {
255 assert_eq!(
256 DdsError::NotEnabled.as_return_code(),
257 return_code::NOT_ENABLED
258 );
259 }
260
261 #[test]
262 fn rc_immutable_policy_maps() {
263 assert_eq!(
264 DdsError::ImmutablePolicy {
265 policy: "Reliability"
266 }
267 .as_return_code(),
268 return_code::IMMUTABLE_POLICY
269 );
270 }
271
272 #[test]
273 fn rc_inconsistent_policy_maps() {
274 assert_eq!(
275 DdsError::InconsistentPolicy { what: "x" }.as_return_code(),
276 return_code::INCONSISTENT_POLICY
277 );
278 }
279
280 #[test]
281 fn rc_already_deleted_maps() {
282 assert_eq!(
283 DdsError::AlreadyDeleted.as_return_code(),
284 return_code::ALREADY_DELETED
285 );
286 }
287
288 #[test]
289 fn rc_timeout_maps() {
290 assert_eq!(DdsError::Timeout.as_return_code(), return_code::TIMEOUT);
291 }
292
293 #[test]
294 fn rc_no_data_maps() {
295 assert_eq!(DdsError::NoData.as_return_code(), return_code::NO_DATA);
296 }
297
298 #[test]
299 fn rc_illegal_operation_maps() {
300 assert_eq!(
301 DdsError::IllegalOperation {
302 what: "write_on_reader"
303 }
304 .as_return_code(),
305 return_code::ILLEGAL_OPERATION
306 );
307 }
308
309 #[test]
310 fn rc_not_allowed_by_security_maps() {
311 assert_eq!(
312 DdsError::NotAllowedBySecurity { what: "topic" }.as_return_code(),
313 return_code::NOT_ALLOWED_BY_SECURITY
314 );
315 }
316
317 #[test]
318 fn rc_constants_have_spec_values() {
319 assert_eq!(return_code::OK, 0);
322 assert_eq!(return_code::ERROR, 1);
323 assert_eq!(return_code::UNSUPPORTED, 2);
324 assert_eq!(return_code::BAD_PARAMETER, 3);
325 assert_eq!(return_code::PRECONDITION_NOT_MET, 4);
326 assert_eq!(return_code::OUT_OF_RESOURCES, 5);
327 assert_eq!(return_code::NOT_ENABLED, 6);
328 assert_eq!(return_code::IMMUTABLE_POLICY, 7);
329 assert_eq!(return_code::INCONSISTENT_POLICY, 8);
330 assert_eq!(return_code::ALREADY_DELETED, 9);
331 assert_eq!(return_code::TIMEOUT, 10);
332 assert_eq!(return_code::NO_DATA, 11);
333 assert_eq!(return_code::ILLEGAL_OPERATION, 12);
334 assert_eq!(return_code::NOT_ALLOWED_BY_SECURITY, 13);
335 }
336
337 #[test]
338 fn rc_display_does_not_leak_security_details() {
339 let e = DdsError::NotAllowedBySecurity { what: "Topic A" };
342 let s = format!("{e}");
343 assert!(s.contains("not allowed by security"));
344 assert!(s.contains("Topic A"));
345 assert!(!s.to_lowercase().contains("permission file"));
347 assert!(!s.to_lowercase().contains("ca cert"));
348 }
349}