phonenumber_fixed/parser/
mod.rs1use crate::metadata::{DATABASE, Database};
16use crate::phone_number::{PhoneNumber, Type};
17use crate::national_number::NationalNumber;
18use crate::country;
19use crate::extension::Extension;
20use crate::carrier::Carrier;
21use crate::consts;
22use crate::validator::{self, Validation};
23use crate::error;
24
25use nom::{IResult, branch::alt};
26
27#[macro_use]
28pub mod helper;
29pub mod valid;
30pub mod rfc3966;
31pub mod natural;
32
33pub fn parse<S: AsRef<str>>(country: Option<country::Id>, string: S) -> Result<PhoneNumber, error::Parse> {
35 parse_with(&*DATABASE, country, string)
36}
37
38pub fn parse_with<S: AsRef<str>>(database: &Database, country: Option<country::Id>, string: S) -> Result<PhoneNumber, error::Parse> {
40 fn phone_number(i: &str) -> IResult<&str, helper::Number> {
41 parse! { i => alt((rfc3966::phone_number, natural::phone_number)) }
42 }
43
44 let (_, mut number) = phone_number(string.as_ref())
46 .or(Err(error::Parse::NoNumber))?;
47
48 number = helper::country_code(database, country, number)?;
50
51 if let Some(meta) = country.and_then(|c| database.by_id(c.as_ref())) {
53 let mut potential = helper::national_number(meta, number.clone());
54
55 if let Some(prefix) = meta.national_prefix.as_ref() {
57 if potential.national.starts_with(prefix) {
58 potential.national = helper::trim(potential.national, prefix.len());
59 }
60 }
61
62 if validator::length(meta, &potential, Type::Unknown) != Validation::TooShort {
63 number = potential;
64 }
65 }
66
67 if number.national.len() < consts::MIN_LENGTH_FOR_NSN {
68 return Err(error::Parse::TooShortNsn.into());
69 }
70
71 if number.national.len() > consts::MAX_LENGTH_FOR_NSN {
72 return Err(error::Parse::TooLong.into());
73 }
74
75 Ok(PhoneNumber {
76 code: country::Code {
77 value: number.prefix.map(|p| p.parse()).unwrap_or(Ok(0))?,
78 source: number.country,
79 },
80
81 national: NationalNumber {
82 value: number.national.parse()?,
83 zeros: number.national.chars().take_while(|&c| c == '0').count() as u8,
84 },
85
86 extension: number.extension.map(|s| Extension(s.into_owned())),
87 carrier: number.carrier.map(|s| Carrier(s.into_owned())),
88 })
89}
90
91#[cfg(test)]
92mod test {
93 use crate::parser;
94 use crate::phone_number::PhoneNumber;
95 use crate::national_number::NationalNumber;
96 use crate::country;
97
98 #[test]
99 fn parse() {
100 let mut number = PhoneNumber {
101 code: country::Code {
102 value: 64,
103 source: country::Source::Default,
104 },
105
106 national: NationalNumber {
107 value: 33316005,
108 zeros: 0,
109 },
110
111 extension: None,
112 carrier: None,
113 };
114
115 number.code.source = country::Source::Default;
116 assert_eq!(number, parser::parse(Some(country::NZ), "033316005").unwrap());
117 assert_eq!(number, parser::parse(Some(country::NZ), "33316005").unwrap());
118 assert_eq!(number, parser::parse(Some(country::NZ), "03-331 6005").unwrap());
119 assert_eq!(number, parser::parse(Some(country::NZ), "03 331 6005").unwrap());
120
121 number.code.source = country::Source::Plus;
122 assert_eq!(number, parser::parse(Some(country::NZ), "tel:03-331-6005;phone-context=+64").unwrap());
123 assert_eq!(number, parser::parse(Some(country::NZ), "tel:03-331-6005;phone-context=+64;a=%A1").unwrap());
127 assert_eq!(number, parser::parse(Some(country::NZ), "tel:03-331-6005;isub=12345;phone-context=+64").unwrap());
128 assert_eq!(number, parser::parse(Some(country::NZ), "tel:+64-3-331-6005;isub=12345").unwrap());
129 assert_eq!(number, parser::parse(Some(country::NZ), "03-331-6005;phone-context=+64").unwrap());
130
131 number.code.source = country::Source::Idd;
132 assert_eq!(number, parser::parse(Some(country::NZ), "0064 3 331 6005").unwrap());
133 assert_eq!(number, parser::parse(Some(country::US), "01164 3 331 6005").unwrap());
134
135 number.code.source = country::Source::Plus;
136 assert_eq!(number, parser::parse(Some(country::US), "+64 3 331 6005").unwrap());
137
138 assert_eq!(number, parser::parse(Some(country::US), "+01164 3 331 6005").unwrap());
139 assert_eq!(number, parser::parse(Some(country::NZ), "+0064 3 331 6005").unwrap());
140 assert_eq!(number, parser::parse(Some(country::NZ), "+ 00 64 3 331 6005").unwrap());
141
142 let number = PhoneNumber {
143 code: country::Code {
144 value: 64,
145 source: country::Source::Number,
146 },
147
148 national: NationalNumber {
149 value: 64123456,
150 zeros: 0,
151 },
152
153 extension: None,
154 carrier: None,
155 };
156
157 assert_eq!(number, parser::parse(Some(country::NZ), "64(0)64123456").unwrap());
158
159 assert_eq!(PhoneNumber {
160 code: country::Code {
161 value: 49,
162 source: country::Source::Default,
163 },
164
165 national: NationalNumber {
166 value: 30123456,
167 zeros: 0,
168 },
169
170 extension: None,
171 carrier: None,
172 }, parser::parse(Some(country::DE), "301/23456").unwrap());
173
174 assert_eq!(PhoneNumber {
175 code: country::Code {
176 value: 81,
177 source: country::Source::Plus,
178 },
179
180 national: NationalNumber {
181 value: 2345,
182 zeros: 0,
183 },
184
185 extension: None,
186 carrier: None,
187 }, parser::parse(Some(country::JP), "+81 *2345").unwrap());
188
189 assert_eq!(PhoneNumber {
190 code: country::Code {
191 value: 64,
192 source: country::Source::Default,
193 },
194
195 national: NationalNumber {
196 value: 12,
197 zeros: 0,
198 },
199
200 extension: None,
201 carrier: None,
202 }, parser::parse(Some(country::NZ), "12").unwrap());
203
204 assert_eq!(PhoneNumber {
205 code: country::Code {
206 value: 55,
207 source: country::Source::Default,
208 },
209
210 national: NationalNumber {
211 value: 3121286979,
212 zeros: 0,
213 },
214
215 extension: None,
216 carrier: Some("12".into()),
217 }, parser::parse(Some(country::BR), "012 3121286979").unwrap());
218 }
219}