eml_nl/utils/
election_domain_id.rs1use std::sync::LazyLock;
2
3use regex::Regex;
4use thiserror::Error;
5
6use crate::{EMLError, EMLValueResultExt, utils::StringValueData};
7
8static ELECTION_DOMAIN_ID_RE: LazyLock<Regex> = LazyLock::new(|| {
10 Regex::new(r"^(\d{4}|([12]?[0-9]))$").expect("Failed to compile Election Domain ID regex")
11});
12
13#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15#[repr(transparent)]
16pub struct ElectionDomainId(String);
17
18impl ElectionDomainId {
19 pub fn new(s: impl AsRef<str>) -> Result<Self, EMLError> {
21 StringValueData::parse_from_str(s.as_ref()).wrap_value_error()
22 }
23
24 pub fn value(&self) -> &str {
26 &self.0
27 }
28}
29
30#[derive(Debug, Clone, Error)]
32#[error("Invalid election domain id: {0}")]
33pub struct InvalidElectionDomainIdError(String);
34
35impl StringValueData for ElectionDomainId {
36 type Error = InvalidElectionDomainIdError;
37
38 fn parse_from_str(s: &str) -> Result<Self, Self::Error>
39 where
40 Self: Sized,
41 {
42 if ELECTION_DOMAIN_ID_RE.is_match(s) {
43 Ok(ElectionDomainId(s.to_string()))
44 } else {
45 Err(InvalidElectionDomainIdError(s.to_string()))
46 }
47 }
48
49 fn to_raw_value(&self) -> String {
50 self.0.clone()
51 }
52}
53
54#[cfg(test)]
55mod tests {
56 use super::*;
57
58 #[test]
59 fn test_election_domain_id_regex_compiles() {
60 LazyLock::force(&ELECTION_DOMAIN_ID_RE);
61 }
62
63 #[test]
64 fn test_valid_election_domain_ids() {
65 let valid_ids = ["1", "12", "1234"];
66 for id in valid_ids {
67 assert!(
68 ElectionDomainId::new(id).is_ok(),
69 "ElectionDomainId should accept valid id: {}",
70 id
71 );
72 }
73 }
74
75 #[test]
76 fn test_invalid_election_domain_ids() {
77 let invalid_ids = ["", "34", "123", "12345", "abc"];
78 for id in invalid_ids {
79 assert!(
80 ElectionDomainId::new(id).is_err(),
81 "ElectionDomainId should reject invalid id: {}",
82 id
83 );
84 }
85 }
86}