use strum_macros::{EnumMessage, EnumProperty};
#[derive(Debug, PartialEq, EnumMessage, EnumProperty)]
pub enum HKIDSymbol {
#[strum(
message = "The holder is aged 18 or over and eligible for a Hong Kong Re-entry Permit",
props(Symbol = "***")
)]
AdultEligibleReentryPermit,
#[strum(
message = "The holder is aged between 11 and 17 and eligible for a Hong Kong Re-entry Permit",
props(Symbol = "*")
)]
YouthEligibleReentryPermit,
#[strum(
message = "The holder has the right of abode in Hong Kong",
props(Symbol = "A")
)]
RightOfAbode,
#[strum(
message = "The holder's reported date/place of birth has changed since first registration",
props(Symbol = "B")
)]
BirthDateOrPlaceChanged,
#[strum(
message = "The holder's stay in Hong Kong is limited by the Director of Immigration at registration",
props(Symbol = "C")
)]
StayLimitedByImmigration,
#[strum(
message = "The holder's reported name has changed since first registration",
props(Symbol = "N")
)]
NameChanged,
#[strum(
message = "The holder was born outside Hong Kong, Mainland China, or Macau",
props(Symbol = "O")
)]
BornOutsideHKChinaMacau,
#[strum(
message = "The holder has the right to land in Hong Kong",
props(Symbol = "R")
)]
RightToLand,
#[strum(
message = "The holder's stay in Hong Kong is not limited by the Director of Immigration",
props(Symbol = "U")
)]
StayUnlimitedByImmigration,
#[strum(
message = "The holder's reported place of birth is Macau",
props(Symbol = "W")
)]
BornInMacau,
#[strum(
message = "The holder's reported place of birth is Mainland China",
props(Symbol = "X")
)]
BornInMainlandChina,
#[strum(
message = "The holder's date of birth has been confirmed by birth certificate or passport",
props(Symbol = "Y")
)]
BirthDateConfirmed,
#[strum(
message = "The holder's reported place of birth is Hong Kong",
props(Symbol = "Z")
)]
BornInHongKong,
#[strum(
message = "Issuing office code (e.g., H1, K2, S1, P1, V1, etc.)",
props(Symbol = "<Office Code>")
)]
IssuingOfficeCode(String),
#[strum(
message = "The holder has lost their ID card. 'L1' for once, 'L2' for twice, etc.",
props(Symbol = "<L#>")
)]
LostCard(u8),
#[strum(message = "Unknown or custom symbol", props(Symbol = "<Unknown>"))]
Unknown(String),
}
impl HKIDSymbol {
pub fn parse(symbol: &str) -> HKIDSymbol {
match symbol {
"***" => HKIDSymbol::AdultEligibleReentryPermit,
"*" => HKIDSymbol::YouthEligibleReentryPermit,
"A" => HKIDSymbol::RightOfAbode,
"B" => HKIDSymbol::BirthDateOrPlaceChanged,
"C" => HKIDSymbol::StayLimitedByImmigration,
"N" => HKIDSymbol::NameChanged,
"O" => HKIDSymbol::BornOutsideHKChinaMacau,
"R" => HKIDSymbol::RightToLand,
"U" => HKIDSymbol::StayUnlimitedByImmigration,
"W" => HKIDSymbol::BornInMacau,
"X" => HKIDSymbol::BornInMainlandChina,
"Y" => HKIDSymbol::BirthDateConfirmed,
"Z" => HKIDSymbol::BornInHongKong,
s if s.starts_with('L') && s.len() > 1 => {
if let Ok(times) = s[1..].parse::<u8>() {
HKIDSymbol::LostCard(times)
} else {
HKIDSymbol::Unknown(s.to_string())
}
}
s if s.len() == 2 && s.chars().nth(1).unwrap().is_digit(10) => {
HKIDSymbol::IssuingOfficeCode(s.to_string())
}
_ => HKIDSymbol::Unknown(symbol.to_string()),
}
}
}
#[cfg(test)]
mod tests {
use strum::EnumMessage;
use strum::EnumProperty;
use super::*;
#[test]
fn test_symbol_and_message_basic_variants() {
let symbol = HKIDSymbol::RightOfAbode;
assert_eq!(symbol.get_str("Symbol"), Some("A"));
assert_eq!(
symbol.get_message(),
Some("The holder has the right of abode in Hong Kong")
);
let symbol = HKIDSymbol::StayLimitedByImmigration;
assert_eq!(symbol.get_str("Symbol"), Some("C"));
assert_eq!(
symbol.get_message(),
Some("The holder's stay in Hong Kong is limited by the Director of Immigration at registration")
);
}
#[test]
fn test_symbol_and_message_lost_card() {
let symbol = HKIDSymbol::LostCard(2);
assert_eq!(symbol.get_str("Symbol"), Some("<L#>"));
assert_eq!(
symbol.get_message(),
Some("The holder has lost their ID card. 'L1' for once, 'L2' for twice, etc.")
);
}
#[test]
fn test_symbol_and_message_issuing_office_code() {
let symbol = HKIDSymbol::IssuingOfficeCode("K2".to_string());
assert_eq!(symbol.get_str("Symbol"), Some("<Office Code>"));
assert_eq!(
symbol.get_message(),
Some("Issuing office code (e.g., H1, K2, S1, P1, V1, etc.)")
);
}
#[test]
fn test_symbol_and_message_unknown() {
let symbol = HKIDSymbol::Unknown("XYZ".to_string());
assert_eq!(symbol.get_str("Symbol"), Some("<Unknown>"));
assert_eq!(symbol.get_message(), Some("Unknown or custom symbol"));
}
#[test]
fn test_parse_standard_symbols() {
assert_eq!(
HKIDSymbol::parse("***"),
HKIDSymbol::AdultEligibleReentryPermit
);
assert_eq!(
HKIDSymbol::parse("*"),
HKIDSymbol::YouthEligibleReentryPermit
);
assert_eq!(HKIDSymbol::parse("A"), HKIDSymbol::RightOfAbode);
assert_eq!(HKIDSymbol::parse("B"), HKIDSymbol::BirthDateOrPlaceChanged);
assert_eq!(HKIDSymbol::parse("C"), HKIDSymbol::StayLimitedByImmigration);
assert_eq!(HKIDSymbol::parse("N"), HKIDSymbol::NameChanged);
assert_eq!(HKIDSymbol::parse("O"), HKIDSymbol::BornOutsideHKChinaMacau);
assert_eq!(HKIDSymbol::parse("R"), HKIDSymbol::RightToLand);
assert_eq!(
HKIDSymbol::parse("U"),
HKIDSymbol::StayUnlimitedByImmigration
);
assert_eq!(HKIDSymbol::parse("W"), HKIDSymbol::BornInMacau);
assert_eq!(HKIDSymbol::parse("X"), HKIDSymbol::BornInMainlandChina);
assert_eq!(HKIDSymbol::parse("Y"), HKIDSymbol::BirthDateConfirmed);
assert_eq!(HKIDSymbol::parse("Z"), HKIDSymbol::BornInHongKong);
}
#[test]
fn test_parse_lost_card() {
assert_eq!(HKIDSymbol::parse("L1"), HKIDSymbol::LostCard(1));
assert_eq!(HKIDSymbol::parse("L2"), HKIDSymbol::LostCard(2));
assert_eq!(HKIDSymbol::parse("L10"), HKIDSymbol::LostCard(10));
assert_eq!(
HKIDSymbol::parse("Lab"),
HKIDSymbol::Unknown("Lab".to_string())
);
}
#[test]
fn test_parse_issuing_office_code() {
assert_eq!(
HKIDSymbol::parse("H1"),
HKIDSymbol::IssuingOfficeCode("H1".to_string())
);
assert_eq!(
HKIDSymbol::parse("K2"),
HKIDSymbol::IssuingOfficeCode("K2".to_string())
);
assert_eq!(
HKIDSymbol::parse("S9"),
HKIDSymbol::IssuingOfficeCode("S9".to_string())
);
assert_eq!(
HKIDSymbol::parse("HF"),
HKIDSymbol::Unknown("HF".to_string())
);
}
#[test]
fn test_parse_unknown() {
assert_eq!(
HKIDSymbol::parse("XYZ"),
HKIDSymbol::Unknown("XYZ".to_string())
);
assert_eq!(HKIDSymbol::parse(""), HKIDSymbol::Unknown("".to_string()));
assert_eq!(HKIDSymbol::parse("Q"), HKIDSymbol::Unknown("Q".to_string()));
assert_eq!(HKIDSymbol::parse("1"), HKIDSymbol::Unknown("1".to_string()));
}
}