Skip to main content

eml_nl/utils/
reporting_unit_identifier_id.rs

1use std::sync::LazyLock;
2
3use regex::Regex;
4use thiserror::Error;
5
6use crate::{EMLError, EMLValueResultExt, utils::StringValueData};
7
8/// Regular expression for validating ReportingUnitIdentifier id values.
9static REPORTING_UNIT_IDENTIFIER_ID_RE: LazyLock<Regex> = LazyLock::new(|| {
10    Regex::new(r"^((HSB\d+)|((HSB\d+::)?\d{4})|(((HSB\d+::)?\d{4}::)?SB\d+)|(HSB\d+::SB\d+))$")
11        .expect("Failed to compile ReportingUnitIdentifier id regex")
12});
13
14/// A string of type ReportingUnitIdentifier id as defined in the EML_NL specification
15#[derive(Debug, Clone, PartialEq, Eq, Hash)]
16#[repr(transparent)]
17pub struct ReportingUnitIdentifierId(String);
18
19impl ReportingUnitIdentifierId {
20    /// Create a new ReportingUnitIdentifierId from a string, validating its format
21    pub fn new(s: impl AsRef<str>) -> Result<Self, EMLError> {
22        StringValueData::parse_from_str(s.as_ref()).wrap_value_error()
23    }
24
25    /// Get the raw string value of the ReportingUnitIdentifierId.
26    pub fn value(&self) -> &str {
27        &self.0
28    }
29}
30
31/// Error returned when a string could not be parsed as a [`ReportingUnitIdentifierId`]
32#[derive(Debug, Clone, Error)]
33#[error("Invalid reporting unit identifier id: {0}")]
34pub struct InvalidReportingUnitIdentifierIdError(String);
35
36impl StringValueData for ReportingUnitIdentifierId {
37    type Error = InvalidReportingUnitIdentifierIdError;
38    fn parse_from_str(s: &str) -> Result<Self, Self::Error>
39    where
40        Self: Sized,
41    {
42        if REPORTING_UNIT_IDENTIFIER_ID_RE.is_match(s) {
43            Ok(ReportingUnitIdentifierId(s.to_string()))
44        } else {
45            Err(InvalidReportingUnitIdentifierIdError(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_reporting_unit_identifier_id_regex_compiles() {
60        LazyLock::force(&REPORTING_UNIT_IDENTIFIER_ID_RE);
61    }
62
63    #[test]
64    fn test_valid_reporting_unit_identifier_ids() {
65        let valid_ids = [
66            "HSB123",
67            "HSB123::5678",
68            "5678",
69            "SB456",
70            "HSB123::SB456",
71            "HSB123::5678::SB456",
72        ];
73        for id in valid_ids {
74            assert!(
75                ReportingUnitIdentifierId::new(id).is_ok(),
76                "ReportingUnitIdentifierId should accept valid id: {}",
77                id
78            );
79        }
80    }
81
82    #[test]
83    fn test_invalid_reporting_unit_identifier_ids() {
84        let invalid_ids = [
85            "",
86            "HSB",
87            "HSB::123",
88            "HSB123::",
89            "::5678",
90            "HSB123::5678::",
91            "HSB123::5678::SB",
92        ];
93        for id in invalid_ids {
94            assert!(
95                ReportingUnitIdentifierId::new(id).is_err(),
96                "ReportingUnitIdentifierId should reject invalid id: {}",
97                id
98            );
99        }
100    }
101}