1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
use std::borrow::Cow;

/// Result error type.
///
#[derive(Debug)]
pub enum OpenProtocolError<'a> {
    /// The value of a field is the empty string `""` or containing all white-spaces,
    /// which is not allowed as value of that field.
    EmptyField(Cow<'a, str>),
    //
    /// The value (second parameter) of a field (first parameter) is not valid for that field.
    InvalidField { field: Cow<'a, str>, value: Cow<'a, str>, description: Cow<'a, str> },
    //
    /// The value of a field is not consistent with the matching value in the state.
    InconsistentState(Cow<'a, str>),
    //
    /// The value of a field is not consistent with the matching value in the
    /// [`Controller`] structure.
    ///
    /// [`Controller`]: struct.Controller.html
    InconsistentField(Cow<'a, str>),
    //
    /// An enforced constraint is broken.
    ConstraintViolated(Cow<'a, str>),
    //
    /// Error when serializing/deserializing JSON.
    JsonError(serde_json::Error),
}

impl std::error::Error for OpenProtocolError<'_> {
    fn description(&self) -> &str {
        match self {
            // JSON error
            OpenProtocolError::JsonError(err) => err.description(),
            //
            // Invalid field value
            OpenProtocolError::InvalidField { description, .. } if description.is_empty() => {
                "invalid field value"
            }
            OpenProtocolError::InvalidField { description, .. } => description,
            //
            // Constraint violation
            OpenProtocolError::ConstraintViolated(err) => err,
            //
            // Inconsistent field
            OpenProtocolError::InconsistentField(_) => {
                "value of field is not the same as matching field in the Controller"
            }
            //
            // Inconsistent state
            OpenProtocolError::InconsistentState(_) => {
                "value of field is not the same as matching field in the state"
            }
            //
            // Field empty
            OpenProtocolError::EmptyField(_) => "field cannot be empty or all whitespace",
        }
    }

    fn cause(&self) -> Option<&dyn std::error::Error> {
        match self {
            OpenProtocolError::JsonError(err) => Some(err),
            _ => None,
        }
    }
}

impl std::fmt::Display for OpenProtocolError<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> {
        match self {
            // JSON error
            OpenProtocolError::JsonError(err) => err.fmt(f),
            //
            // Invalid field value
            OpenProtocolError::InvalidField { field, value, description }
                if description.is_empty() =>
            {
                write!(f, "value [{}] is invalid for the field {}", value, field)
            }
            OpenProtocolError::InvalidField { field, value, description } => {
                write!(f, "value [{}] is invalid for the field {}: {}", value, field, description)
            }
            //
            // Constraint violation
            OpenProtocolError::ConstraintViolated(err) => err.fmt(f),
            //
            // Inconsistent field value
            OpenProtocolError::InconsistentField(field) => write!(
                f,
                "value of field {} is not the same as the matching field in the Controller",
                field
            ),
            //
            // Inconsistent state value
            OpenProtocolError::InconsistentState(field) => write!(
                f,
                "value of field {} is not the same as the matching field in the state",
                field
            ),
            //
            // Field empty
            OpenProtocolError::EmptyField(field) => {
                write!(f, "field {} cannot be empty or all whitespace", field)
            }
        }
    }
}

impl PartialEq for OpenProtocolError<'_> {
    fn eq(&self, other: &Self) -> bool {
        match self {
            // JSON error - since serde::error::Error does not implement PartialEq,
            //              the only thing we can do is compare the debug representation.
            OpenProtocolError::JsonError(err1) => match other {
                OpenProtocolError::JsonError(err2) => {
                    format!("{:?}", err1) == format!("{:?}", err2)
                }
                _ => false,
            },
            //
            // All other variants that implement PartialEq
            _ => *self == *other,
        }
    }
}

impl Eq for OpenProtocolError<'_> {}