use std::num::NonZeroU64;
use crate::{
EMLError, NS_EML,
io::{EMLElement, EMLElementReader, EMLElementWriter, QualifiedName, collect_struct},
utils::{CandidateId, NameShortCode, StringValue},
};
#[derive(Debug, Clone)]
pub struct CandidateIdentifier {
pub id: StringValue<CandidateId>,
pub display_order: Option<StringValue<NonZeroU64>>,
pub short_code: Option<StringValue<NameShortCode>>,
pub short_code_ref: Option<StringValue<NameShortCode>>,
pub expected_confirmation_reference: Option<Box<str>>,
}
impl CandidateIdentifier {
pub fn new(id: CandidateId) -> Self {
CandidateIdentifier {
id: StringValue::Parsed(id),
display_order: None,
short_code: None,
short_code_ref: None,
expected_confirmation_reference: None,
}
}
pub fn with_display_order(mut self, display_order: NonZeroU64) -> Self {
self.display_order = Some(StringValue::Parsed(display_order));
self
}
pub fn with_short_code(mut self, short_code: NameShortCode) -> Self {
self.short_code = Some(StringValue::Parsed(short_code));
self
}
pub fn with_short_code_ref(mut self, short_code: NameShortCode) -> Self {
self.short_code_ref = Some(StringValue::Parsed(short_code));
self
}
pub fn with_expected_confirmation_reference(mut self, reference: impl Into<Box<str>>) -> Self {
self.expected_confirmation_reference = Some(reference.into());
self
}
pub fn has_reference(&self) -> bool {
self.short_code_ref.is_some()
}
}
impl From<CandidateId> for CandidateIdentifier {
fn from(value: CandidateId) -> Self {
CandidateIdentifier::new(value)
}
}
impl EMLElement for CandidateIdentifier {
const EML_NAME: QualifiedName<'_, '_> =
QualifiedName::from_static("CandidateIdentifier", Some(NS_EML));
fn read_eml(elem: &mut EMLElementReader<'_, '_>) -> Result<Self, EMLError> {
Ok(collect_struct!(elem, CandidateIdentifier {
id: elem.string_value_attr("Id", None)?,
display_order: elem.string_value_attr_opt("DisplayOrder")?,
short_code: elem.string_value_attr_opt("ShortCode")?,
short_code_ref as Option: ("ShortCode", NS_EML) => |elem| elem.string_value()?,
expected_confirmation_reference: elem
.attribute_value("ExpectedConfirmationReference")?
.map(|s| s.into()),
}))
}
fn write_eml(&self, writer: EMLElementWriter) -> Result<(), EMLError> {
let writer = writer
.attr("Id", &self.id.raw())?
.attr_opt("DisplayOrder", self.display_order.as_ref().map(|v| v.raw()))?
.attr_opt("ShortCode", self.short_code.as_ref().map(|v| v.raw()))?
.attr_opt(
"ExpectedConfirmationReference",
self.expected_confirmation_reference.as_ref(),
)?;
if let Some(short_code_ref) = &self.short_code_ref {
writer
.child(("ShortCode", NS_EML), |elem| {
elem.text(short_code_ref.raw().as_ref())?.finish()
})?
.finish()
} else {
writer.empty()
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{
EMLVersion,
io::{EMLParsingMode, EMLRead as _, test_write_eml_element, test_xml_fragment},
};
#[test]
fn test_simple_candidate_identifier() {
let xml = test_xml_fragment(
r#"
<CandidateIdentifier xmlns="urn:oasis:names:tc:evs:schema:eml" Id="1"/>
"#,
);
let can_id = CandidateIdentifier::parse_eml_fragment(
&xml,
EMLParsingMode::Strict,
EMLVersion::default(),
)
.unwrap();
assert_eq!(
can_id.id,
StringValue::Parsed(CandidateId::new(NonZeroU64::new(1).unwrap()))
);
assert_eq!(can_id.display_order, None);
assert_eq!(can_id.short_code, None);
assert_eq!(can_id.short_code_ref, None);
assert_eq!(can_id.expected_confirmation_reference, None);
let xml_output = test_write_eml_element(&can_id, &[NS_EML], EMLVersion::default()).unwrap();
assert_eq!(xml_output, xml);
}
#[test]
fn test_all_attributes_candidate_identifier() {
let xml = test_xml_fragment(
r#"
<CandidateIdentifier xmlns="urn:oasis:names:tc:evs:schema:eml" Id="2254" DisplayOrder="2" ShortCode="1234" ExpectedConfirmationReference="Ref123"/>
"#,
);
let can_id = CandidateIdentifier::parse_eml_fragment(
&xml,
EMLParsingMode::Strict,
EMLVersion::default(),
)
.unwrap();
assert_eq!(
can_id.id,
StringValue::Parsed(CandidateId::new(NonZeroU64::new(2254).unwrap()))
);
assert_eq!(
can_id.display_order,
Some(StringValue::Parsed(NonZeroU64::new(2).unwrap()))
);
assert_eq!(
can_id.short_code,
Some(StringValue::Parsed(NameShortCode::new("1234").unwrap()))
);
assert_eq!(can_id.short_code_ref, None);
assert_eq!(
can_id.expected_confirmation_reference,
Some("Ref123".into())
);
let xml_output = test_write_eml_element(&can_id, &[NS_EML], EMLVersion::default()).unwrap();
assert_eq!(xml_output, xml);
}
#[test]
fn test_short_code_element_candidate_identifier() {
let xml = test_xml_fragment(
r#"
<CandidateIdentifier xmlns="urn:oasis:names:tc:evs:schema:eml" Id="3">
<ShortCode>VlagW</ShortCode>
</CandidateIdentifier>
"#,
);
let can_id = CandidateIdentifier::parse_eml_fragment(
&xml,
EMLParsingMode::Strict,
EMLVersion::default(),
)
.unwrap();
assert_eq!(can_id.short_code, None);
assert_eq!(
can_id.short_code_ref,
Some(StringValue::Parsed(NameShortCode::new("VlagW").unwrap()))
);
let xml_output = test_write_eml_element(&can_id, &[NS_EML], EMLVersion::default()).unwrap();
assert_eq!(xml_output, xml);
}
#[test]
fn test_candidate_identifier_construction() {
let can_id = CandidateIdentifier::new(CandidateId::new(NonZeroU64::new(5678).unwrap()))
.with_display_order(NonZeroU64::new(3).unwrap())
.with_short_code(NameShortCode::new("9876").unwrap())
.with_expected_confirmation_reference("reference");
assert_eq!(
can_id.id,
StringValue::Parsed(CandidateId::new(NonZeroU64::new(5678).unwrap()))
);
assert_eq!(
can_id.display_order,
Some(StringValue::Parsed(NonZeroU64::new(3).unwrap()))
);
assert_eq!(
can_id.short_code,
Some(StringValue::Parsed(NameShortCode::new("9876").unwrap()))
);
assert_eq!(
can_id.expected_confirmation_reference,
Some("reference".into())
);
}
}