kumo_dmarc/types/
report_failure.rs

1use instant_xml::ToXml;
2use std::fmt::Write;
3use std::str::FromStr;
4
5#[derive(Clone, Copy, Debug, Eq, PartialEq)]
6pub struct ReportFailure {
7    all_pass: bool,
8    any_pass: bool,
9    dkim: bool,
10    spf: bool,
11}
12
13impl ToXml for ReportFailure {
14    fn serialize<W: std::fmt::Write + ?Sized>(
15        &self,
16        _: Option<instant_xml::Id<'_>>,
17        serializer: &mut instant_xml::Serializer<W>,
18    ) -> Result<(), instant_xml::Error> {
19        serializer.write_str(self)
20    }
21}
22
23impl std::fmt::Display for ReportFailure {
24    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25        let values = [
26            (self.all_pass, '0'),
27            (self.any_pass, '1'),
28            (self.dkim, 'd'),
29            (self.spf, 's'),
30        ];
31
32        let mut first = true;
33        for (value, ch) in values.into_iter() {
34            if !value {
35                continue;
36            }
37
38            if !first {
39                f.write_char(':')?;
40            } else {
41                first = false;
42            }
43
44            f.write_char(ch)?;
45        }
46
47        Ok(())
48    }
49}
50
51impl FromStr for ReportFailure {
52    type Err = String;
53
54    fn from_str(value: &str) -> Result<Self, Self::Err> {
55        let mut new = Self::default();
56        for part in value.split(':') {
57            match part.trim() {
58                "0" => new.all_pass = true,
59                "1" => new.any_pass = true,
60                "d" => new.dkim = true,
61                "s" => new.spf = true,
62                _ => return Err(format!("invalid report failure {value:?}")),
63            }
64        }
65
66        Ok(new)
67    }
68}
69
70impl Default for ReportFailure {
71    fn default() -> Self {
72        Self {
73            all_pass: true,
74            any_pass: false,
75            dkim: false,
76            spf: false,
77        }
78    }
79}