use std::fmt;
use super::extract_digits;
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
pub enum Operator {
MCI,
Irancell,
RighTel,
ShatelMobile,
Aptel,
Other,
}
impl fmt::Display for Operator {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let s = match self {
Operator::MCI => "MCI",
Operator::Irancell => "Irancell",
Operator::RighTel => "RighTel",
Operator::ShatelMobile => "Shatel Mobile",
Operator::Aptel => "Aptel",
Operator::Other => "Other",
};
f.write_str(s)
}
}
impl Operator {
#[must_use]
pub fn persian_name(&self) -> &'static str {
match self {
Operator::MCI => "همراه اول",
Operator::Irancell => "ایرانسل",
Operator::RighTel => "رایتل",
Operator::ShatelMobile => "شاتل موبایل",
Operator::Aptel => "آپتل",
Operator::Other => "نامشخص",
}
}
}
#[must_use]
pub fn validate(phone: &str) -> bool {
canonicalize(phone).is_some()
}
#[must_use]
pub fn canonicalize(phone: &str) -> Option<String> {
let digits = extract_digits(phone);
let body = if digits.len() == 14 && digits.starts_with("0098") {
&digits[4..] } else if digits.len() == 12 && digits.starts_with("98") {
&digits[2..] } else if digits.len() == 11 && digits.starts_with("09") {
return Some(digits);
} else {
return None;
};
if body.len() == 10 && body.starts_with('9') {
Some(format!("0{body}"))
} else {
None
}
}
#[must_use]
pub fn operator(phone: &str) -> Option<Operator> {
let canon = canonicalize(phone)?;
let prefix = &canon[..4];
Some(match prefix {
"0910" | "0911" | "0912" | "0913" | "0914" | "0915" | "0916" | "0917" | "0918" | "0919" => {
Operator::MCI
}
"0991" | "0992" | "0994" | "0995" | "0996" | "0999" => Operator::MCI,
"0920" | "0921" | "0922" => Operator::RighTel,
"0930" | "0933" | "0935" | "0936" | "0937" | "0938" | "0939" => Operator::Irancell,
"0901" | "0902" | "0903" | "0904" | "0905" | "0941" => Operator::Irancell,
"0998" => Operator::ShatelMobile,
"0993" => Operator::Aptel,
_ => Operator::Other,
})
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn validates_local_format() {
assert!(validate("09121234567"));
}
#[test]
fn validates_international_plus() {
assert!(validate("+989121234567"));
}
#[test]
fn validates_international_00() {
assert!(validate("00989121234567"));
}
#[test]
fn rejects_wrong_country() {
assert!(!validate("0812345678"));
}
#[test]
fn rejects_short() {
assert!(!validate("0912123456"));
}
#[test]
fn canonical_form() {
assert_eq!(
canonicalize("+989121234567").as_deref(),
Some("09121234567")
);
assert_eq!(
canonicalize("00989121234567").as_deref(),
Some("09121234567")
);
assert_eq!(canonicalize("09121234567").as_deref(), Some("09121234567"));
}
#[test]
fn operator_detection() {
assert_eq!(operator("09121234567"), Some(Operator::MCI));
assert_eq!(operator("09351234567"), Some(Operator::Irancell));
assert_eq!(operator("09211234567"), Some(Operator::RighTel));
assert_eq!(operator("09981234567"), Some(Operator::ShatelMobile));
}
#[test]
fn operator_returns_other_for_unknown_prefix() {
assert_eq!(operator("09001234567"), Some(Operator::Other));
}
#[test]
fn operator_persian_name() {
assert_eq!(Operator::MCI.persian_name(), "همراه اول");
assert_eq!(Operator::Irancell.persian_name(), "ایرانسل");
}
}