diff --git a/src/national_number.rs b/src/national_number.rs index 249c738..36c8eef 100644 --- a/src/national_number.rs +++ b/src/national_number.rs @@ -18,7 +18,25 @@ use std::fmt; #[derive(Copy, Clone, Eq, PartialEq, Serialize, Deserialize, Hash, Debug)] pub struct NationalNumber { pub(crate) value: u64, +} + +impl NationalNumber { + pub fn new(value: u64, zeros: u8) -> Self { + // E.164 specifies a maximum of 15 decimals, which corresponds to slightly over 48.9 bits. + // 56 bits ought to cut it here. + assert!(value < (1 << 56), "number too long"); + Self { + value: ((zeros as u64) << 56) | value, + } + } + /// The number without any leading zeroes. + pub fn value(&self) -> u64 { + self.value & 0x00ffffffffffffff + } + + /// The number of leading zeroes. + /// /// In some countries, the national (significant) number starts with one or /// more "0"s without this being a national prefix or trunk code of some /// kind. For example, the leading zero in the national (significant) number @@ -35,18 +53,8 @@ pub struct NationalNumber { /// /// Clients who use the parsing or conversion functionality of the i18n phone /// number libraries will have these fields set if necessary automatically. - pub(crate) zeros: u8, -} - -impl NationalNumber { - /// The number without any leading zeroes. - pub fn value(&self) -> u64 { - self.value - } - - /// The number of leading zeroes. pub fn zeros(&self) -> u8 { - self.zeros + (self.value >> 56) as u8 } } @@ -58,10 +66,10 @@ impl From for u64 { impl fmt::Display for NationalNumber { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - for _ in 0..self.zeros { + for _ in 0..self.zeros() { write!(f, "0")?; } - write!(f, "{}", self.value) + write!(f, "{}", self.value()) } } diff --git a/src/parser/mod.rs b/src/parser/mod.rs index 542bad6..1648289 100644 --- a/src/parser/mod.rs +++ b/src/parser/mod.rs @@ -84,10 +84,10 @@ pub fn parse_with>( source: number.country, }, - national: NationalNumber { - value: number.national.parse()?, - zeros: number.national.chars().take_while(|&c| c == '0').count() as u8, - }, + national: NationalNumber::new( + number.national.parse()?, + 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())), @@ -109,10 +109,7 @@ mod test { source: country::Source::Default, }, - national: NationalNumber { - value: 33316005, - zeros: 0, - }, + national: NationalNumber::new(33316005, 0), extension: None, carrier: None, @@ -200,10 +197,7 @@ mod test { source: country::Source::Number, }, - national: NationalNumber { - value: 64123456, - zeros: 0, - }, + national: NationalNumber::new(64123456, 0), extension: None, carrier: None, @@ -221,10 +215,7 @@ mod test { source: country::Source::Default, }, - national: NationalNumber { - value: 30123456, - zeros: 0, - }, + national: NationalNumber::new(30123456, 0), extension: None, carrier: None, @@ -239,10 +230,7 @@ mod test { source: country::Source::Plus, }, - national: NationalNumber { - value: 2345, - zeros: 0, - }, + national: NationalNumber::new(2345, 0,), extension: None, carrier: None, @@ -257,10 +245,7 @@ mod test { source: country::Source::Default, }, - national: NationalNumber { - value: 12, - zeros: 0, - }, + national: NationalNumber::new(12, 0,), extension: None, carrier: None, @@ -275,10 +260,7 @@ mod test { source: country::Source::Default, }, - national: NationalNumber { - value: 3121286979, - zeros: 0, - }, + national: NationalNumber::new(3121286979, 0), extension: None, carrier: Some("12".into()),