eml_nl/common/
candidate_identifier.rs1use std::num::NonZeroU64;
2
3use crate::{
4 EMLError, NS_EML,
5 io::{EMLElement, EMLElementReader, EMLElementWriter, QualifiedName, collect_struct},
6 utils::{CandidateId, NameShortCode, StringValue},
7};
8
9#[derive(Debug, Clone)]
11pub struct CandidateIdentifier {
12 pub id: StringValue<CandidateId>,
14
15 pub display_order: Option<StringValue<NonZeroU64>>,
17
18 pub short_code: Option<StringValue<NameShortCode>>,
24
25 pub expected_confirmation_reference: Option<Box<str>>,
27}
28
29impl CandidateIdentifier {
30 pub fn new(id: CandidateId) -> Self {
32 CandidateIdentifier {
33 id: StringValue::Parsed(id),
34 display_order: None,
35 short_code: None,
36 expected_confirmation_reference: None,
37 }
38 }
39
40 pub fn with_display_order(mut self, display_order: NonZeroU64) -> Self {
42 self.display_order = Some(StringValue::Parsed(display_order));
43 self
44 }
45
46 pub fn with_short_code(mut self, short_code: NameShortCode) -> Self {
48 self.short_code = Some(StringValue::Parsed(short_code));
49 self
50 }
51
52 pub fn with_expected_confirmation_reference(mut self, reference: impl Into<Box<str>>) -> Self {
54 self.expected_confirmation_reference = Some(reference.into());
55 self
56 }
57}
58
59impl From<CandidateId> for CandidateIdentifier {
60 fn from(value: CandidateId) -> Self {
61 CandidateIdentifier::new(value)
62 }
63}
64
65impl EMLElement for CandidateIdentifier {
66 const EML_NAME: QualifiedName<'_, '_> =
67 QualifiedName::from_static("CandidateIdentifier", Some(NS_EML));
68
69 fn read_eml(elem: &mut EMLElementReader<'_, '_>) -> Result<Self, EMLError> {
70 let id = elem.string_value_attr("Id", None)?;
71 let display_order = elem.string_value_attr_opt("DisplayOrder")?;
72 let short_code = elem.string_value_attr_opt("ShortCode")?;
73 let expected_confirmation_reference = elem
74 .attribute_value("ExpectedConfirmationReference")?
75 .map(|s| s.into());
76
77 struct CandidateIdentifierTmp {
78 short_code: Option<StringValue<NameShortCode>>,
79 }
80
81 let elem = collect_struct!(
82 elem,
83 CandidateIdentifierTmp {
84 short_code as Option: ("ShortCode", NS_EML) => |elem| elem.string_value()?,
85 }
86 );
87
88 Ok(CandidateIdentifier {
89 id,
90 display_order,
91 short_code: short_code.or(elem.short_code), expected_confirmation_reference,
93 })
94 }
95
96 fn write_eml(&self, writer: EMLElementWriter) -> Result<(), EMLError> {
97 writer
98 .attr("Id", &self.id.raw())?
99 .attr_opt("DisplayOrder", self.display_order.as_ref().map(|v| v.raw()))?
100 .attr_opt("ShortCode", self.short_code.as_ref().map(|v| v.raw()))?
101 .attr_opt(
102 "ExpectedConfirmationReference",
103 self.expected_confirmation_reference.as_ref(),
104 )?
105 .empty()
106 }
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112 use crate::io::{EMLParsingMode, EMLRead as _, test_write_eml_element, test_xml_fragment};
113
114 #[test]
115 fn test_simple_candidate_identifier() {
116 let xml = test_xml_fragment(
117 r#"
118 <CandidateIdentifier xmlns="urn:oasis:names:tc:evs:schema:eml" Id="1"/>
119 "#,
120 );
121 let can_id = CandidateIdentifier::parse_eml(&xml, EMLParsingMode::Strict).unwrap();
122 assert_eq!(
123 can_id.id,
124 StringValue::Parsed(CandidateId::new(NonZeroU64::new(1).unwrap()))
125 );
126 assert_eq!(can_id.display_order, None);
127 assert_eq!(can_id.short_code, None);
128 assert_eq!(can_id.expected_confirmation_reference, None);
129
130 let xml_output = test_write_eml_element(&can_id, &[NS_EML]).unwrap();
131 assert_eq!(xml_output, xml);
132 }
133
134 #[test]
135 fn test_all_attributes_candidate_identifier() {
136 let xml = test_xml_fragment(
137 r#"
138 <CandidateIdentifier xmlns="urn:oasis:names:tc:evs:schema:eml" Id="2254" DisplayOrder="2" ShortCode="1234" ExpectedConfirmationReference="Ref123"/>
139 "#,
140 );
141 let can_id = CandidateIdentifier::parse_eml(&xml, EMLParsingMode::Strict).unwrap();
142 assert_eq!(
143 can_id.id,
144 StringValue::Parsed(CandidateId::new(NonZeroU64::new(2254).unwrap()))
145 );
146 assert_eq!(
147 can_id.display_order,
148 Some(StringValue::Parsed(NonZeroU64::new(2).unwrap()))
149 );
150 assert_eq!(
151 can_id.short_code,
152 Some(StringValue::Parsed(NameShortCode::new("1234").unwrap()))
153 );
154 assert_eq!(
155 can_id.expected_confirmation_reference,
156 Some("Ref123".into())
157 );
158
159 let xml_output = test_write_eml_element(&can_id, &[NS_EML]).unwrap();
160 assert_eq!(xml_output, xml);
161 }
162
163 #[test]
164 fn test_candidate_identifier_construction() {
165 let can_id = CandidateIdentifier::new(CandidateId::new(NonZeroU64::new(5678).unwrap()))
166 .with_display_order(NonZeroU64::new(3).unwrap())
167 .with_short_code(NameShortCode::new("9876").unwrap())
168 .with_expected_confirmation_reference("reference");
169 assert_eq!(
170 can_id.id,
171 StringValue::Parsed(CandidateId::new(NonZeroU64::new(5678).unwrap()))
172 );
173 assert_eq!(
174 can_id.display_order,
175 Some(StringValue::Parsed(NonZeroU64::new(3).unwrap()))
176 );
177 assert_eq!(
178 can_id.short_code,
179 Some(StringValue::Parsed(NameShortCode::new("9876").unwrap()))
180 );
181 assert_eq!(
182 can_id.expected_confirmation_reference,
183 Some("reference".into())
184 );
185 }
186}