iop_morpheus_proto/data/
validation.rs

1use serde::{Deserialize, Serialize};
2
3#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialOrd, PartialEq, Serialize)]
4pub enum ValidationStatus {
5    /// All possible checks are done and passed.
6    Valid,
7    /// Some checks could not be performed for lack of information, all others passed.
8    /// E.g. Signatures are valid, but no timestamps are present so
9    /// they could have been created outside the time period in which the signer key was valid.
10    MaybeValid,
11    /// Any step of validation failed.
12    Invalid,
13}
14
15impl std::fmt::Display for ValidationStatus {
16    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17        let msg = match self {
18            Self::Valid => "valid",
19            Self::MaybeValid => "maybe valid",
20            Self::Invalid => "invalid",
21        };
22        write!(f, "{}", msg)
23    }
24}
25
26#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialOrd, PartialEq, Serialize)]
27pub enum ValidationIssueSeverity {
28    Warning,
29    Error,
30}
31
32impl std::fmt::Display for ValidationIssueSeverity {
33    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
34        let msg = match self {
35            Self::Warning => "warning",
36            Self::Error => "error",
37        };
38        write!(f, "{}", msg)
39    }
40}
41
42const VALIDATION_CODE_DEFAULT: u32 = 0;
43
44#[derive(Clone, Debug, Deserialize, Eq, Hash, Ord, PartialOrd, PartialEq, Serialize)]
45pub struct ValidationIssue {
46    code: u32,
47    reason: String,
48    severity: ValidationIssueSeverity,
49}
50
51impl ValidationIssue {
52    pub fn code(&self) -> u32 {
53        self.code
54    }
55    pub fn reason(&self) -> &str {
56        &self.reason
57    }
58    pub fn severity(&self) -> ValidationIssueSeverity {
59        self.severity
60    }
61}
62
63#[derive(Clone, Debug, Default, Deserialize, Eq, Hash, Ord, PartialOrd, PartialEq, Serialize)]
64pub struct ValidationResult {
65    issues: Vec<ValidationIssue>,
66}
67
68impl ValidationResult {
69    pub fn status(&self) -> ValidationStatus {
70        let has_error = self.issues.iter().any(|it| it.severity == ValidationIssueSeverity::Error);
71        if has_error {
72            ValidationStatus::Invalid
73        } else if !self.issues.is_empty() {
74            ValidationStatus::MaybeValid
75        } else {
76            ValidationStatus::Valid
77        }
78    }
79
80    pub fn add_issue(&mut self, severity: ValidationIssueSeverity, reason: &str) {
81        self.issues.push(ValidationIssue {
82            severity,
83            code: VALIDATION_CODE_DEFAULT,
84            reason: reason.to_owned(),
85        })
86    }
87
88    pub fn issues(&self) -> &[ValidationIssue] {
89        self.issues.as_slice()
90    }
91}