From bb15984d58761a5f0e28ad10b1b4379b843b484f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Tue, 22 Aug 2023 08:19:59 +0200 Subject: [PATCH 1/4] Parse mnc and mcc into Carrier --- src/carrier.rs | 38 ++++++++++++++++++++------------------ src/error.rs | 8 ++++++-- src/formatter.rs | 9 +++++++-- src/parser/mod.rs | 8 ++++++-- 4 files changed, 39 insertions(+), 24 deletions(-) diff --git a/src/carrier.rs b/src/carrier.rs index 8207b27..8c96bf7 100644 --- a/src/carrier.rs +++ b/src/carrier.rs @@ -14,34 +14,36 @@ use serde_derive::{Deserialize, Serialize}; use std::fmt; -use std::ops::Deref; + +use crate::ParseError; /// A phone number carrier. +/// see: https://en.wikipedia.org/wiki/Mobile_country_code#National_operators #[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Hash, Debug)] -pub struct Carrier(pub(crate) String); - -impl> From for Carrier { - fn from(value: T) -> Carrier { - Carrier(value.into()) - } +pub struct Carrier { + pub mcc: u16, // always 3 digits + pub mnc: u16, // 2 or 3 digits } -impl Deref for Carrier { - type Target = str; - - fn deref(&self) -> &str { - &self.0 - } -} +impl TryFrom<&str> for Carrier { + type Error = ParseError; -impl AsRef for Carrier { - fn as_ref(&self) -> &str { - &self.0 + fn try_from(value: &str) -> Result { + Ok(Self { + mcc: value + .get(0..3) + .and_then(|c| c.parse().ok()) + .ok_or(ParseError::InvalidCountryCode)?, + mnc: value + .get(3..) + .and_then(|c| c.parse().ok()) + .ok_or(ParseError::InvalidNetworkCode)?, + }) } } impl fmt::Display for Carrier { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.0) + write!(f, "{}{}", self.mcc, self.mnc) } } diff --git a/src/error.rs b/src/error.rs index 2cbcf72..6fe8d62 100644 --- a/src/error.rs +++ b/src/error.rs @@ -58,12 +58,16 @@ pub enum Parse { #[allow(unused)] // This is unused in the build script NoNumber, - /// The country code supplied did not belong to a supported country or - /// non-geographical entity. + /// The country code supplied is not correct. #[error("invalid country code")] #[allow(unused)] // This is unused in the build script InvalidCountryCode, + /// The network code supplied is not correct + #[error("invalid network code")] + #[allow(unused)] // This is unused in the build script + InvalidNetworkCode, + /// This indicates the string started with an international dialing prefix, /// but after this was stripped from the number, had less digits than any /// valid phone number (including country code) could have. diff --git a/src/formatter.rs b/src/formatter.rs index 999aa0e..48f1d91 100644 --- a/src/formatter.rs +++ b/src/formatter.rs @@ -16,6 +16,7 @@ use crate::{ consts, metadata::{Database, Format, Metadata, DATABASE}, phone_number::PhoneNumber, + Carrier, }; use std::{borrow::Cow, fmt}; @@ -234,7 +235,7 @@ fn replace( meta: &Metadata, formatter: &Format, transform: Option<&str>, - carrier: Option<&str>, + carrier: Option<&Carrier>, ) -> String { formatter .pattern() @@ -249,7 +250,11 @@ fn replace( .as_str(); let format = transform.replace(consts::NP, meta.national_prefix().unwrap_or("")); let format = format.replace(consts::FG, &format!("${}", first)); - let format = format.replace(consts::CC, carrier.unwrap_or("")); + let format = if let Some(carrier) = carrier.map(|c| c.to_string()) { + format.replace(consts::CC, &carrier) + } else { + format.replace(consts::CC, "") + }; consts::FIRST_GROUP.replace(formatter.format(), &*format) } else { diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 85d0fd6..4835111 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -12,7 +12,8 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::carrier::Carrier; +use std::borrow::Borrow; + use crate::consts; use crate::country; use crate::error; @@ -89,7 +90,10 @@ pub fn parse_with>( )?, extension: number.extension.map(|s| Extension(s.into_owned())), - carrier: number.carrier.map(|s| Carrier(s.into_owned())), + carrier: number.carrier.and_then(|s| { + let s: &str = s.borrow(); + s.try_into().ok() + }), }) } From 090d8c841fe6325ea1c1d238c5765fd4ba69cd8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gabriel=20F=C3=A9ron?= Date: Mon, 4 Sep 2023 09:04:47 +0200 Subject: [PATCH 2/4] Add short test --- src/carrier.rs | 12 ++++++++++++ src/parser/mod.rs | 2 +- 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/carrier.rs b/src/carrier.rs index 8c96bf7..9bc339a 100644 --- a/src/carrier.rs +++ b/src/carrier.rs @@ -47,3 +47,15 @@ impl fmt::Display for Carrier { write!(f, "{}{}", self.mcc, self.mnc) } } + +#[cfg(test)] +mod test { + use super::Carrier; + use std::convert::TryInto; + + #[test] + fn test_mobile_network_codes() { + assert_eq!(Carrier { mcc: 336, mnc: 1 }, "336001".try_into().unwrap()); + assert_eq!(Carrier { mcc: 336, mnc: 35 }, "33635".try_into().unwrap()); + } +} \ No newline at end of file diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 4835111..9acbeda 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -266,7 +266,7 @@ mod test { national: NationalNumber::new(3121286979, 0).unwrap(), extension: None, - carrier: Some("12".into()), + carrier: "12".try_into().ok(), }, parser::parse(Some(country::BR), "012 3121286979").unwrap() ); From dfd812e61ca1fd9d14b5a5232345f7038e7d4638 Mon Sep 17 00:00:00 2001 From: Ruben De Smet Date: Thu, 9 Oct 2025 12:56:34 +0200 Subject: [PATCH 3/4] retain mnc length --- src/carrier.rs | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/carrier.rs b/src/carrier.rs index 9bc339a..31dc3f1 100644 --- a/src/carrier.rs +++ b/src/carrier.rs @@ -23,6 +23,7 @@ use crate::ParseError; pub struct Carrier { pub mcc: u16, // always 3 digits pub mnc: u16, // 2 or 3 digits + pub mnc_3: bool, } impl TryFrom<&str> for Carrier { @@ -38,13 +39,18 @@ impl TryFrom<&str> for Carrier { .get(3..) .and_then(|c| c.parse().ok()) .ok_or(ParseError::InvalidNetworkCode)?, + mnc_3: value.len() == 6, }) } } impl fmt::Display for Carrier { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "{}{}", self.mcc, self.mnc) + if self.mnc_3 { + write!(f, "{:03}{:03}", self.mcc, self.mnc) + } else { + write!(f, "{:03}{:02}", self.mcc, self.mnc) + } } } @@ -55,7 +61,21 @@ mod test { #[test] fn test_mobile_network_codes() { - assert_eq!(Carrier { mcc: 336, mnc: 1 }, "336001".try_into().unwrap()); - assert_eq!(Carrier { mcc: 336, mnc: 35 }, "33635".try_into().unwrap()); + assert_eq!( + Carrier { + mcc: 336, + mnc: 1, + mnc_3: true + }, + "336001".try_into().unwrap() + ); + assert_eq!( + Carrier { + mcc: 336, + mnc: 35, + mnc_3: false + }, + "33635".try_into().unwrap() + ); } -} \ No newline at end of file +} From 000db7818cf3996f2f2f17c5d4593c6ee2b2c55f Mon Sep 17 00:00:00 2001 From: Ruben De Smet Date: Thu, 9 Oct 2025 13:02:17 +0200 Subject: [PATCH 4/4] fixup! Parse mnc and mcc into Carrier --- src/carrier.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/carrier.rs b/src/carrier.rs index 31dc3f1..8e1f2ac 100644 --- a/src/carrier.rs +++ b/src/carrier.rs @@ -18,7 +18,8 @@ use std::fmt; use crate::ParseError; /// A phone number carrier. -/// see: https://en.wikipedia.org/wiki/Mobile_country_code#National_operators +/// +/// See: https://en.wikipedia.org/wiki/Mobile_country_code#National_operators #[derive(Clone, Eq, PartialEq, Serialize, Deserialize, Hash, Debug)] pub struct Carrier { pub mcc: u16, // always 3 digits