Skip to main content

dynamic_config_embedded/
error.rs

1//! What can go wrong on a device, which is less than on a host.
2
3use core::fmt;
4
5/// Why a document could not become a configuration.
6#[derive(Debug, Clone, Copy, PartialEq, Eq)]
7#[non_exhaustive]
8pub enum ErrorKind {
9    /// The bytes are not valid in their format.
10    Parse,
11    /// They parsed, but do not fit the struct.
12    Type,
13    /// Every field is valid and the whole was rejected.
14    Invalid,
15    /// The format's feature is not enabled in this build.
16    Unsupported,
17}
18
19impl ErrorKind {
20    /// A short, stable label. Useful for a log line or a status register.
21    #[must_use]
22    pub const fn as_str(self) -> &'static str {
23        match self {
24            Self::Parse => "parse",
25            Self::Type => "type",
26            Self::Invalid => "invalid",
27            Self::Unsupported => "unsupported",
28        }
29    }
30}
31
32/// A configuration failure.
33///
34/// Carries a kind and a `&'static str`, and nothing else. There is no allocator
35/// to build a message with, and a device's log is a line on a UART — the key
36/// facts are *what kind* and *which rule*, both of which fit.
37#[derive(Debug, Clone, Copy, PartialEq, Eq)]
38pub struct Error {
39    kind: ErrorKind,
40    message: &'static str,
41}
42
43impl Error {
44    /// An error of `kind`, described by `message`.
45    #[must_use]
46    pub const fn new(kind: ErrorKind, message: &'static str) -> Self {
47        Self { kind, message }
48    }
49
50    /// What went wrong, as a category.
51    #[must_use]
52    pub const fn kind(&self) -> ErrorKind {
53        self.kind
54    }
55
56    /// What went wrong, in words.
57    #[must_use]
58    pub const fn message(&self) -> &'static str {
59        self.message
60    }
61}
62
63impl fmt::Display for Error {
64    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65        write!(f, "{}: {}", self.kind.as_str(), self.message)
66    }
67}
68
69// `core::error::Error` rather than `std::error::Error`: stable since 1.81, and
70// it means a device's error type composes with everything else the same way.
71impl core::error::Error for Error {}
72
73#[cfg(test)]
74mod tests {
75    use super::*;
76
77    #[test]
78    fn an_error_says_the_kind_and_the_rule() {
79        let error = Error::new(ErrorKind::Invalid, "low_ms must be below high_ms");
80
81        assert_eq!(error.kind(), ErrorKind::Invalid);
82        assert_eq!(error.message(), "low_ms must be below high_ms");
83    }
84
85    #[test]
86    fn it_is_copy_so_it_can_go_in_a_status_register() {
87        let error = Error::new(ErrorKind::Parse, "bad");
88        let copied = error;
89
90        assert_eq!(error, copied);
91    }
92}