icydb_model/base/normalizer/intl/
phone.rs1use crate::{prelude::*, visitor::Normalizer};
8
9#[normalizer]
15pub struct E164PhoneNumber;
16
17impl Normalizer<String> for E164PhoneNumber {
18 fn normalize(&self, value: &mut String) -> Result<(), String> {
19 let trimmed = value.trim();
20
21 if trimmed.is_empty() || trimmed.starts_with('+') {
22 *value = trimmed.to_owned();
23 return Ok(());
24 }
25
26 if trimmed.chars().all(|c| c.is_ascii_digit()) {
27 *value = format!("+{trimmed}");
28 return Ok(());
29 }
30
31 *value = trimmed.to_owned();
32
33 Ok(())
34 }
35}
36
37#[cfg(test)]
42mod tests {
43 use super::*;
44
45 #[test]
46 fn phone_normalizer_preserves_canonical_e164() {
47 let normalizer = E164PhoneNumber;
48 let mut value = " +15551234567 ".to_string();
49
50 normalizer.normalize(&mut value).unwrap();
51
52 assert_eq!(value, "+15551234567");
53 }
54
55 #[test]
56 fn phone_normalizer_adds_plus_to_plain_digits() {
57 let normalizer = E164PhoneNumber;
58 let mut value = "15551234567".to_string();
59
60 normalizer.normalize(&mut value).unwrap();
61
62 assert_eq!(value, "+15551234567");
63 }
64
65 #[test]
66 fn phone_normalizer_preserves_non_digit_input_for_validator_rejection() {
67 let normalizer = E164PhoneNumber;
68 let mut value = "+1 (555) 123-4567".to_string();
69
70 normalizer.normalize(&mut value).unwrap();
71
72 assert_eq!(value, "+1 (555) 123-4567");
73 }
74}