Skip to main content

cyclonedds/
error.rs

1//! Module containing error types and utilities.
2
3/// Result type specialized for DDS Errors.
4pub type Result<T, E = Error> = std::result::Result<T, E>;
5
6/// Errors that can occur during DDS operations.
7#[non_exhaustive]
8#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
9pub enum Error {
10    /// Non specific error.
11    NonSpecific,
12    /// Feature unsupported.
13    Unsupported,
14    /// Bad parameter value.
15    BadParameter,
16    /// Precondition for operation not met.
17    PreconditionNotMet,
18    /// When an operation fails because of a lack of resources.
19    OutOfResources,
20    /// When a configurable feature is not enabled.
21    NotEnabled,
22    /// When an attempt is made to modify an immutable policy.
23    ImmutablePolicy,
24    /// When a policy is used with inconsistent values.
25    InconsistentPolicy,
26    /// When an attempt is made to delete something more than once.
27    AlreadyDeleted,
28    /// When a timeout has occurred.
29    Timeout,
30    /// When expected data is not provided.
31    NoData,
32    /// When a function is called when it should not be.
33    IllegalOperation,
34    /// When credentials are insufficient to use the function.
35    NotAllowedBySecurity,
36}
37
38impl std::fmt::Display for Error {
39    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
40        write!(
41            f,
42            "{}",
43            match self {
44                Error::NonSpecific => "non specific error occurred",
45                Error::Unsupported => "unsupported feature",
46                Error::BadParameter => "bad parameter provided",
47                Error::PreconditionNotMet => "precondition for operation not met",
48                Error::OutOfResources => "out of resources",
49                Error::NotEnabled => "feature not enabled",
50                Error::ImmutablePolicy => "attempted to modify immutable policy",
51                Error::InconsistentPolicy => "policy has inconsistent values",
52                Error::AlreadyDeleted => "entity already deleted",
53                Error::Timeout => "timeout reached",
54                Error::NoData => "data not provided",
55                Error::IllegalOperation => "operation is illegal",
56                Error::NotAllowedBySecurity => "insufficient credentials",
57            }
58        )
59    }
60}
61
62impl std::error::Error for Error {}
63
64/// Conversion trait for mapping status codes to the Result type.
65pub(crate) trait IntoError<T>: Sized {
66    type Error;
67
68    fn into_error(self) -> Result<Self, Self::Error>;
69}
70
71impl IntoError<Error> for cyclonedds_sys::dds_return_t {
72    type Error = Error;
73
74    #[inline]
75    fn into_error(self) -> Result<Self, Self::Error> {
76        match self {
77            result if result >= 0 => Ok(result),
78            cyclonedds_sys::DDS_RETCODE_ERROR => Err(Self::Error::NonSpecific),
79            cyclonedds_sys::DDS_RETCODE_UNSUPPORTED => Err(Self::Error::Unsupported),
80            cyclonedds_sys::DDS_RETCODE_BAD_PARAMETER => Err(Self::Error::BadParameter),
81            cyclonedds_sys::DDS_RETCODE_PRECONDITION_NOT_MET => {
82                Err(Self::Error::PreconditionNotMet)
83            }
84            cyclonedds_sys::DDS_RETCODE_OUT_OF_RESOURCES => Err(Self::Error::OutOfResources),
85            cyclonedds_sys::DDS_RETCODE_NOT_ENABLED => Err(Self::Error::NotEnabled),
86            cyclonedds_sys::DDS_RETCODE_IMMUTABLE_POLICY => Err(Self::Error::ImmutablePolicy),
87            cyclonedds_sys::DDS_RETCODE_INCONSISTENT_POLICY => Err(Self::Error::InconsistentPolicy),
88            cyclonedds_sys::DDS_RETCODE_ALREADY_DELETED => Err(Self::Error::AlreadyDeleted),
89            cyclonedds_sys::DDS_RETCODE_TIMEOUT => Err(Self::Error::Timeout),
90            cyclonedds_sys::DDS_RETCODE_NO_DATA => Err(Self::Error::NoData),
91            cyclonedds_sys::DDS_RETCODE_ILLEGAL_OPERATION => Err(Self::Error::IllegalOperation),
92            cyclonedds_sys::DDS_RETCODE_NOT_ALLOWED_BY_SECURITY => {
93                Err(Self::Error::NotAllowedBySecurity)
94            }
95            _ => unreachable!(),
96        }
97    }
98}
99
100#[cfg(test)]
101mod tests {
102    use super::*;
103
104    #[test]
105    fn test_zero_is_success() {
106        let actual = 0.into_error();
107        let expected = Ok(0);
108        assert_eq!(actual, expected);
109    }
110
111    #[test]
112    fn test_positive_is_success() {
113        let actual = cyclonedds_sys::dds_return_t::MAX.into_error();
114        let expected = Ok(i32::MAX);
115        assert_eq!(actual, expected);
116    }
117
118    #[test]
119    fn test_error_mapping() {
120        let actual = cyclonedds_sys::DDS_RETCODE_ERROR.into_error();
121        let expected = Err(Error::NonSpecific);
122        assert_eq!(actual, expected);
123        assert_eq!(
124            format!("{}", actual.unwrap_err()),
125            "non specific error occurred"
126        );
127        let actual = cyclonedds_sys::DDS_RETCODE_UNSUPPORTED.into_error();
128        let expected = Err(Error::Unsupported);
129        assert_eq!(actual, expected);
130        assert_eq!(format!("{}", actual.unwrap_err()), "unsupported feature");
131        let actual = cyclonedds_sys::DDS_RETCODE_BAD_PARAMETER.into_error();
132        let expected = Err(Error::BadParameter);
133        assert_eq!(actual, expected);
134        assert_eq!(format!("{}", actual.unwrap_err()), "bad parameter provided");
135        let actual = cyclonedds_sys::DDS_RETCODE_PRECONDITION_NOT_MET.into_error();
136        let expected = Err(Error::PreconditionNotMet);
137        assert_eq!(actual, expected);
138        assert_eq!(
139            format!("{}", actual.unwrap_err()),
140            "precondition for operation not met"
141        );
142        let actual = cyclonedds_sys::DDS_RETCODE_OUT_OF_RESOURCES.into_error();
143        let expected = Err(Error::OutOfResources);
144        assert_eq!(actual, expected);
145        assert_eq!(format!("{}", actual.unwrap_err()), "out of resources");
146        let actual = cyclonedds_sys::DDS_RETCODE_NOT_ENABLED.into_error();
147        let expected = Err(Error::NotEnabled);
148        assert_eq!(actual, expected);
149        assert_eq!(format!("{}", actual.unwrap_err()), "feature not enabled");
150        let actual = cyclonedds_sys::DDS_RETCODE_IMMUTABLE_POLICY.into_error();
151        let expected = Err(Error::ImmutablePolicy);
152        assert_eq!(actual, expected);
153        assert_eq!(
154            format!("{}", actual.unwrap_err()),
155            "attempted to modify immutable policy"
156        );
157        let actual = cyclonedds_sys::DDS_RETCODE_INCONSISTENT_POLICY.into_error();
158        let expected = Err(Error::InconsistentPolicy);
159        assert_eq!(actual, expected);
160        assert_eq!(
161            format!("{}", actual.unwrap_err()),
162            "policy has inconsistent values"
163        );
164        let actual = cyclonedds_sys::DDS_RETCODE_ALREADY_DELETED.into_error();
165        let expected = Err(Error::AlreadyDeleted);
166        assert_eq!(actual, expected);
167        assert_eq!(format!("{}", actual.unwrap_err()), "entity already deleted");
168        let actual = cyclonedds_sys::DDS_RETCODE_TIMEOUT.into_error();
169        let expected = Err(Error::Timeout);
170        assert_eq!(actual, expected);
171        assert_eq!(format!("{}", actual.unwrap_err()), "timeout reached");
172        let actual = cyclonedds_sys::DDS_RETCODE_NO_DATA.into_error();
173        let expected = Err(Error::NoData);
174        assert_eq!(actual, expected);
175        assert_eq!(format!("{}", actual.unwrap_err()), "data not provided");
176        let actual = cyclonedds_sys::DDS_RETCODE_ILLEGAL_OPERATION.into_error();
177        let expected = Err(Error::IllegalOperation);
178        assert_eq!(actual, expected);
179        assert_eq!(format!("{}", actual.unwrap_err()), "operation is illegal");
180        let actual = cyclonedds_sys::DDS_RETCODE_NOT_ALLOWED_BY_SECURITY.into_error();
181        let expected = Err(Error::NotAllowedBySecurity);
182        assert_eq!(actual, expected);
183        assert_eq!(
184            format!("{}", actual.unwrap_err()),
185            "insufficient credentials"
186        );
187    }
188
189    #[test]
190    #[should_panic = "internal error: entered unreachable code"]
191    fn test_out_of_bounds_error_panics() {
192        let _ = cyclonedds_sys::dds_return_t::MIN.into_error();
193    }
194}