use crate::metadata::{DATABASE, Database};
use crate::phone_number::{PhoneNumber, Type};
use crate::national_number::NationalNumber;
use crate::country;
use crate::extension::Extension;
use crate::carrier::Carrier;
use crate::consts;
use crate::validator::{self, Validation};
use crate::error;
use nom::{IResult, branch::alt};
#[macro_use]
pub mod helper;
pub mod valid;
pub mod rfc3966;
pub mod natural;
pub fn parse<S: AsRef<str>>(country: Option<country::Id>, string: S) -> Result<PhoneNumber, error::Parse> {
parse_with(&*DATABASE, country, string)
}
pub fn parse_with<S: AsRef<str>>(database: &Database, country: Option<country::Id>, string: S) -> Result<PhoneNumber, error::Parse> {
fn phone_number(i: &str) -> IResult<&str, helper::Number> {
parse! { i => alt((rfc3966::phone_number, natural::phone_number)) }
}
let (_, mut number) = phone_number(string.as_ref())
.or(Err(error::Parse::NoNumber))?;
number = helper::country_code(database, country, number)?;
if let Some(meta) = country.and_then(|c| database.by_id(c.as_ref())) {
let mut potential = helper::national_number(meta, number.clone());
if let Some(prefix) = meta.national_prefix.as_ref() {
if potential.national.starts_with(prefix) {
potential.national = helper::trim(potential.national, prefix.len());
}
}
if validator::length(meta, &potential, Type::Unknown) != Validation::TooShort {
number = potential;
}
}
if number.national.len() < consts::MIN_LENGTH_FOR_NSN {
return Err(error::Parse::TooShortNsn.into());
}
if number.national.len() > consts::MAX_LENGTH_FOR_NSN {
return Err(error::Parse::TooLong.into());
}
Ok(PhoneNumber {
code: country::Code {
value: number.prefix.map(|p| p.parse()).unwrap_or(Ok(0))?,
source: number.country,
},
national: NationalNumber {
value: number.national.parse()?,
zeros: number.national.chars().take_while(|&c| c == '0').count() as u8,
},
extension: number.extension.map(|s| Extension(s.into_owned())),
carrier: number.carrier.map(|s| Carrier(s.into_owned())),
})
}
#[cfg(test)]
mod test {
use crate::parser;
use crate::phone_number::PhoneNumber;
use crate::national_number::NationalNumber;
use crate::country;
#[test]
fn parse() {
let mut number = PhoneNumber {
code: country::Code {
value: 64,
source: country::Source::Default,
},
national: NationalNumber {
value: 33316005,
zeros: 0,
},
extension: None,
carrier: None,
};
number.code.source = country::Source::Default;
assert_eq!(number, parser::parse(Some(country::NZ), "033316005").unwrap());
assert_eq!(number, parser::parse(Some(country::NZ), "33316005").unwrap());
assert_eq!(number, parser::parse(Some(country::NZ), "03-331 6005").unwrap());
assert_eq!(number, parser::parse(Some(country::NZ), "03 331 6005").unwrap());
number.code.source = country::Source::Plus;
assert_eq!(number, parser::parse(Some(country::NZ), "tel:03-331-6005;phone-context=+64").unwrap());
assert_eq!(number, parser::parse(Some(country::NZ), "tel:03-331-6005;phone-context=+64;a=%A1").unwrap());
assert_eq!(number, parser::parse(Some(country::NZ), "tel:03-331-6005;isub=12345;phone-context=+64").unwrap());
assert_eq!(number, parser::parse(Some(country::NZ), "tel:+64-3-331-6005;isub=12345").unwrap());
assert_eq!(number, parser::parse(Some(country::NZ), "03-331-6005;phone-context=+64").unwrap());
number.code.source = country::Source::Idd;
assert_eq!(number, parser::parse(Some(country::NZ), "0064 3 331 6005").unwrap());
assert_eq!(number, parser::parse(Some(country::US), "01164 3 331 6005").unwrap());
number.code.source = country::Source::Plus;
assert_eq!(number, parser::parse(Some(country::US), "+64 3 331 6005").unwrap());
assert_eq!(number, parser::parse(Some(country::US), "+01164 3 331 6005").unwrap());
assert_eq!(number, parser::parse(Some(country::NZ), "+0064 3 331 6005").unwrap());
assert_eq!(number, parser::parse(Some(country::NZ), "+ 00 64 3 331 6005").unwrap());
let number = PhoneNumber {
code: country::Code {
value: 64,
source: country::Source::Number,
},
national: NationalNumber {
value: 64123456,
zeros: 0,
},
extension: None,
carrier: None,
};
assert_eq!(number, parser::parse(Some(country::NZ), "64(0)64123456").unwrap());
assert_eq!(PhoneNumber {
code: country::Code {
value: 49,
source: country::Source::Default,
},
national: NationalNumber {
value: 30123456,
zeros: 0,
},
extension: None,
carrier: None,
}, parser::parse(Some(country::DE), "301/23456").unwrap());
assert_eq!(PhoneNumber {
code: country::Code {
value: 81,
source: country::Source::Plus,
},
national: NationalNumber {
value: 2345,
zeros: 0,
},
extension: None,
carrier: None,
}, parser::parse(Some(country::JP), "+81 *2345").unwrap());
assert_eq!(PhoneNumber {
code: country::Code {
value: 64,
source: country::Source::Default,
},
national: NationalNumber {
value: 12,
zeros: 0,
},
extension: None,
carrier: None,
}, parser::parse(Some(country::NZ), "12").unwrap());
assert_eq!(PhoneNumber {
code: country::Code {
value: 55,
source: country::Source::Default,
},
national: NationalNumber {
value: 3121286979,
zeros: 0,
},
extension: None,
carrier: Some("12".into()),
}, parser::parse(Some(country::BR), "012 3121286979").unwrap());
}
}