Skip to main content

icydb_model/base/validator/intl/
phone.rs

1//! Module: base::validator::intl::phone
2//!
3//! Responsibility: base validator definitions.
4//! Does not own: normalization policy, persistence, or schema mutation semantics.
5//! Boundary: reports typed visitor issues for facade schema values.
6
7use crate::{prelude::*, visitor::Validator};
8
9///
10/// E164PhoneNumber
11/// Ensures phone number has the canonical E.164 envelope:
12/// `+` followed by 7 to 15 ASCII digits, with a non-zero first digit.
13///
14
15#[validator]
16pub struct E164PhoneNumber;
17
18impl Validator<str> for E164PhoneNumber {
19    fn validate(&self, s: &str, ctx: &mut dyn VisitorContext) {
20        let Some(digits) = s.strip_prefix('+') else {
21            ctx.issue("phone number must start with +");
22            return;
23        };
24
25        if digits.is_empty() || !digits.chars().all(|ch| ch.is_ascii_digit()) {
26            ctx.issue("phone number must contain only digits after +");
27            return;
28        }
29
30        if digits.starts_with('0') {
31            ctx.issue("phone number country code must not start with 0");
32            return;
33        }
34
35        let digit_count = digits.len();
36
37        if !(7..=15).contains(&digit_count) {
38            ctx.issue(format!(
39                "phone number has {digit_count} digits; expected 7 to 15"
40            ));
41        }
42    }
43}
44
45///
46/// TESTS
47///
48
49#[cfg(test)]
50mod tests;