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