rust_br/check/
phone.rs

1use std::collections::HashMap;
2use std::sync::OnceLock;
3
4fn ddd_map() -> &'static HashMap<&'static str, (&'static str, &'static str)> {
5    static DDD_MAP: OnceLock<HashMap<&str, (&str, &str)>> = OnceLock::new();
6    DDD_MAP.get_or_init(|| {
7        let mut map = HashMap::new();
8
9        // Centro-Oeste
10        map.insert("61", ("Distrito Federal", "Centro-Oeste"));
11        map.insert("62", ("Goiás", "Centro-Oeste"));
12        map.insert("64", ("Goiás", "Centro-Oeste"));
13        map.insert("65", ("Mato Grosso", "Centro-Oeste"));
14        map.insert("66", ("Mato Grosso", "Centro-Oeste"));
15        map.insert("67", ("Mato Grosso do Sul", "Centro-Oeste"));
16
17        // Nordeste
18        map.insert("82", ("Alagoas", "Nordeste"));
19        map.insert("71", ("Bahia", "Nordeste"));
20        map.insert("73", ("Bahia", "Nordeste"));
21        map.insert("74", ("Bahia", "Nordeste"));
22        map.insert("75", ("Bahia", "Nordeste"));
23        map.insert("77", ("Bahia", "Nordeste"));
24        map.insert("85", ("Ceará", "Nordeste"));
25        map.insert("88", ("Ceará", "Nordeste"));
26        map.insert("98", ("Maranhão", "Nordeste"));
27        map.insert("99", ("Maranhão", "Nordeste"));
28        map.insert("83", ("Paraíba", "Nordeste"));
29        map.insert("81", ("Pernambuco", "Nordeste"));
30        map.insert("87", ("Pernambuco", "Nordeste"));
31        map.insert("86", ("Piauí", "Nordeste"));
32        map.insert("89", ("Piauí", "Nordeste"));
33        map.insert("84", ("Rio Grande do Norte", "Nordeste"));
34        map.insert("79", ("Sergipe", "Nordeste"));
35
36        // Norte
37        map.insert("68", ("Acre", "Norte"));
38        map.insert("96", ("Amapá", "Norte"));
39        map.insert("92", ("Amazonas", "Norte"));
40        map.insert("97", ("Amazonas", "Norte"));
41        map.insert("91", ("Pará", "Norte"));
42        map.insert("93", ("Pará", "Norte"));
43        map.insert("94", ("Pará", "Norte"));
44        map.insert("69", ("Rondônia", "Norte"));
45        map.insert("95", ("Roraima", "Norte"));
46        map.insert("63", ("Tocantins", "Norte"));
47
48        // Sudeste
49        map.insert("27", ("Espírito Santo", "Sudeste"));
50        map.insert("28", ("Espírito Santo", "Sudeste"));
51        map.insert("31", ("Minas Gerais", "Sudeste"));
52        map.insert("32", ("Minas Gerais", "Sudeste"));
53        map.insert("33", ("Minas Gerais", "Sudeste"));
54        map.insert("34", ("Minas Gerais", "Sudeste"));
55        map.insert("35", ("Minas Gerais", "Sudeste"));
56        map.insert("37", ("Minas Gerais", "Sudeste"));
57        map.insert("38", ("Minas Gerais", "Sudeste"));
58        map.insert("21", ("Rio de Janeiro", "Sudeste"));
59        map.insert("22", ("Rio de Janeiro", "Sudeste"));
60        map.insert("24", ("Rio de Janeiro", "Sudeste"));
61        map.insert("11", ("São Paulo", "Sudeste"));
62        map.insert("12", ("São Paulo", "Sudeste"));
63        map.insert("13", ("São Paulo", "Sudeste"));
64        map.insert("14", ("São Paulo", "Sudeste"));
65        map.insert("15", ("São Paulo", "Sudeste"));
66        map.insert("16", ("São Paulo", "Sudeste"));
67        map.insert("17", ("São Paulo", "Sudeste"));
68        map.insert("18", ("São Paulo", "Sudeste"));
69        map.insert("19", ("São Paulo", "Sudeste"));
70
71        // Sul
72        map.insert("41", ("Paraná", "Sul"));
73        map.insert("42", ("Paraná", "Sul"));
74        map.insert("43", ("Paraná", "Sul"));
75        map.insert("44", ("Paraná", "Sul"));
76        map.insert("45", ("Paraná", "Sul"));
77        map.insert("46", ("Paraná", "Sul"));
78        map.insert("51", ("Rio Grande do Sul", "Sul"));
79        map.insert("53", ("Rio Grande do Sul", "Sul"));
80        map.insert("54", ("Rio Grande do Sul", "Sul"));
81        map.insert("55", ("Rio Grande do Sul", "Sul"));
82        map.insert("47", ("Santa Catarina", "Sul"));
83        map.insert("48", ("Santa Catarina", "Sul"));
84        map.insert("49", ("Santa Catarina", "Sul"));
85
86        map
87    })
88}
89
90pub struct PhoneValidationResult {
91    pub is_valid: bool,
92    pub phone_type: Option<String>,
93    pub region: Option<String>,
94    pub state: Option<String>,
95}
96
97pub fn phone(phone: &str) -> PhoneValidationResult {
98    let cleaned: String = phone.chars().filter(|c| c.is_digit(10)).collect();
99    let length = cleaned.len();
100
101    let is_valid_length = length == 10 || length == 11;
102
103    if !is_valid_length {
104        return PhoneValidationResult {
105            is_valid: false,
106            phone_type: None,
107            region: None,
108            state: None,
109        };
110    }
111
112    let phone_type = if length == 10 {
113        Some("Fixo".to_string())
114    } else {
115        Some("Móvel".to_string())
116    };
117
118    let (state, region) = if length == 10 || length == 11 {
119        let ddd = &cleaned[0..2];
120        ddd_map().get(ddd).map_or((None, None), |&(s, r)| {
121            (Some(s.to_string()), Some(r.to_string()))
122        })
123    } else {
124        (None, None)
125    };
126
127    let is_valid = is_valid_length && state.is_some();
128
129    PhoneValidationResult {
130        is_valid,
131        phone_type,
132        region,
133        state,
134    }
135}