Skip to main content

eml_nl/utils/
authority_id.rs

1use std::sync::LazyLock;
2
3use regex::Regex;
4use thiserror::Error;
5
6use crate::{EMLError, EMLValueResultExt, utils::StringValueData};
7
8/// EML_NL authority id (called XSBType in the schema) value.
9#[derive(Debug, Clone, PartialEq, Eq, Hash)]
10#[repr(transparent)]
11pub struct AuthorityId(String);
12
13impl AuthorityId {
14    /// Create a new AuthorityId from a string, validating its format
15    pub fn new(s: impl AsRef<str>) -> Result<Self, EMLError> {
16        StringValueData::parse_from_str(s.as_ref()).wrap_value_error()
17    }
18
19    /// Get the raw string value of the authority id.
20    pub fn value(&self) -> &str {
21        &self.0
22    }
23}
24
25/// Error type returned when an invalid authority id value is encountered.
26#[derive(Debug, Clone, PartialEq, Eq, Error)]
27#[repr(transparent)]
28#[error("Invalid authority id: {0}")]
29pub struct InvalidAuthorityIdError(String);
30
31/// Regular expression for validating AuthorityId values.
32static AUTHORITY_ID_RE: LazyLock<Regex> = LazyLock::new(|| {
33    Regex::new(r"^(CSB|((HSB|SB)\d+)|(\d{4}))$").expect("Failed to compile AuthorityId regex")
34});
35
36impl StringValueData for AuthorityId {
37    type Error = InvalidAuthorityIdError;
38
39    fn parse_from_str(s: &str) -> Result<Self, Self::Error>
40    where
41        Self: Sized,
42    {
43        if AUTHORITY_ID_RE.is_match(s) {
44            Ok(AuthorityId(s.to_string()))
45        } else {
46            Err(InvalidAuthorityIdError(s.to_string()))
47        }
48    }
49
50    fn to_raw_value(&self) -> String {
51        self.0.clone()
52    }
53}
54
55#[cfg(test)]
56mod tests {
57    use super::*;
58
59    #[test]
60    fn test_authority_id_regex_compiles() {
61        LazyLock::force(&AUTHORITY_ID_RE);
62    }
63
64    #[test]
65    fn test_authority_id_valid_values() {
66        let valid_values = [
67            "CSB", "HSB1", "HSB123", "SB10", "SB999", "0001", "1234", "9999",
68        ];
69
70        for value in valid_values {
71            let parsed = AuthorityId::parse_from_str(value);
72            assert!(
73                parsed.is_ok(),
74                "Expected '{}' to parse successfully, got error: {:?}",
75                value,
76                parsed.err()
77            );
78        }
79    }
80
81    #[test]
82    fn test_authority_id_invalid_values() {
83        let invalid_values = ["CS", "HSB", "SB", "123", "12345", "ABC", "SB-1"];
84        for value in invalid_values {
85            let parsed = AuthorityId::parse_from_str(value);
86            assert!(
87                parsed.is_err(),
88                "Expected '{}' to fail parsing, but got: {:?}",
89                value,
90                parsed.ok()
91            );
92        }
93    }
94}