From 3f07806990cb219d3c63a296c54bfb48e3219542 Mon Sep 17 00:00:00 2001 From: Vlasislav Kashin <99754299+vloldik@users.noreply.github.com> Date: Thu, 10 Jul 2025 11:29:18 +0300 Subject: [PATCH] Ugrade methods to return iterators --- .../phone_number_regexps_and_mappings.rs | 3 + src/phonenumberutil/phonenumberutil.rs | 67 +++++++++---------- 2 files changed, 36 insertions(+), 34 deletions(-) diff --git a/src/phonenumberutil/phone_number_regexps_and_mappings.rs b/src/phonenumberutil/phone_number_regexps_and_mappings.rs index e176d97..cf1081b 100644 --- a/src/phonenumberutil/phone_number_regexps_and_mappings.rs +++ b/src/phonenumberutil/phone_number_regexps_and_mappings.rs @@ -167,6 +167,9 @@ pub(super) struct PhoneNumberRegExpsAndMappings { pub is_format_eligible_as_you_type_formatting_regex: Regex, /// Added for function `formatting_rule_has_first_group_only` + /// A pattern that is used to determine if the national prefix formatting rule + /// has the first group only, i.e., does not start with the national prefix. + /// Note that the pattern explicitly allows for unbalanced parentheses. pub formatting_rule_has_first_group_only_regex: Regex } diff --git a/src/phonenumberutil/phonenumberutil.rs b/src/phonenumberutil/phonenumberutil.rs index 8a68063..7c8678b 100644 --- a/src/phonenumberutil/phonenumberutil.rs +++ b/src/phonenumberutil/phonenumberutil.rs @@ -21,7 +21,6 @@ use log::{error, trace, warn}; use regex::Regex; // Helper type for Result -pub type Result = std::result::Result; pub type RegexResult = std::result::Result; @@ -29,6 +28,8 @@ pub type ParseResult = std::result::Result; pub type ExampleNumberResult = std::result::Result; pub type ValidationResult = std::result::Result; +pub type MatchResult = std::result::Result; +pub type ExtractNumberResult = std::result::Result; pub struct PhoneNumberUtil { /// An API for validation checking. @@ -216,16 +217,10 @@ impl PhoneNumberUtil { } fn formatting_rule_has_first_group_only(&self, national_prefix_formatting_rule: &str) -> bool { - // A pattern that is used to determine if the national prefix formatting rule - // has the first group only, i.e., does not start with the national prefix. - // Note that the pattern explicitly allows for unbalanced parentheses. - let first_group_only_prefix_pattern = self - .reg_exps - .regexp_cache - .get_regex("\\(?\\$1\\)?") - .expect("Invalid constant pattern!"); return national_prefix_formatting_rule.is_empty() - || first_group_only_prefix_pattern.full_match(national_prefix_formatting_rule); + || self.reg_exps + .formatting_rule_has_first_group_only_regex + .full_match(national_prefix_formatting_rule); } fn get_ndd_prefix_for_region( @@ -330,32 +325,30 @@ impl PhoneNumberUtil { fn get_region_code_for_country_code(&self, country_calling_code: i32) -> &str { let region_codes = self.get_region_codes_for_country_calling_code(country_calling_code); return region_codes - .first() - .map(|v| *v) + .and_then(| mut codes | codes.next()) + .map(|v| v) .unwrap_or(i18n::RegionCode::get_unknown()); } - // Returns the region codes that matches the specific country calling code. In - // the case of no region code being found, region_codes will be left empty. + /// Returns the region codes that matches the specific country calling code. In + /// the case of no region code being found, region_codes will be left empty. fn get_region_codes_for_country_calling_code( &self, country_calling_code: i32, - ) -> Vec<&str> { - let mut acc = Vec::with_capacity(10); + ) -> Option> { // Create a IntRegionsPair with the country_code passed in, and use it to // locate the pair with the same country_code in the sorted vector. self.country_calling_code_to_region_code_map .binary_search_by_key(&country_calling_code, |(code, _)| *code) + .ok() .map(|index| { self.country_calling_code_to_region_code_map[index] .1 .iter() - .for_each(|v| { - acc.push(v.as_str()); - }); - }) /* suppress Result ignoring */ - .ok(); - acc + .map(|v| + v.as_str() + ) + }) } fn get_metadata_for_region_or_calling_code( @@ -629,7 +622,7 @@ impl PhoneNumberUtil { &self, phone_number: &PhoneNumber, carrier_code: &str, - ) -> Result { + ) -> RegexResult { let country_calling_code = phone_number.country_code(); let national_significant_number = Self::get_national_significant_number(phone_number); let region_code = self.get_region_code_for_country_code(country_calling_code); @@ -666,7 +659,7 @@ impl PhoneNumberUtil { &self, phone_number: &PhoneNumber, fallback_carrier_code: &str, - ) -> Result { + ) -> RegexResult { let carrier_code = if !phone_number.preferred_domestic_carrier_code().is_empty() { phone_number.preferred_domestic_carrier_code() } else { @@ -691,7 +684,7 @@ impl PhoneNumberUtil { phone_number: &'b PhoneNumber, calling_from: &str, with_formatting: bool, - ) -> Result> { + ) -> RegexResult> { let country_calling_code = phone_number.country_code(); if !self.has_valid_country_calling_code(country_calling_code) { return if phone_number.has_raw_input() { @@ -831,10 +824,13 @@ impl PhoneNumberUtil { fn get_region_code_for_number(&self, phone_number: &PhoneNumber) -> RegexResult<&str>{ let country_calling_code = phone_number.country_code(); let region_codes = self.get_region_codes_for_country_calling_code(country_calling_code); - if region_codes.len() == 0 { - log::trace!("Missing/invalid country calling code ({})", country_calling_code); + let Some(region_codes) = region_codes + .map(| codes | codes.collect::>()) + .filter(| codes | codes.len() > 0) + else { + trace!("Missing/invalid country calling code ({})", country_calling_code); return Ok(i18n::RegionCode::get_unknown()) - } + }; if region_codes.len() == 1 { return Ok(region_codes[0]) } else { @@ -955,7 +951,7 @@ impl PhoneNumberUtil { fn can_be_internationally_dialled( &self, phone_number: &PhoneNumber - ) -> Result { + ) -> RegexResult { let region_code = self.get_region_code_for_number(phone_number)?; let Some(metadata) = self.region_to_metadata_map.get(region_code) else { // Note numbers belonging to non-geographical entities (e.g. +800 numbers) @@ -1503,7 +1499,7 @@ impl PhoneNumberUtil { /// second extension here makes this actually two phone numbers, (530) 583-6985 /// x302 and (530) 583-6985 x2303. We remove the second extension so that the /// first number is parsed correctly. - fn extract_possible_number<'a>(&self, phone_number: &'a str) -> std::result::Result<&'a str, ExtractNumberError> { + fn extract_possible_number<'a>(&self, phone_number: &'a str) -> ExtractNumberResult<&'a str> { // Rust note: skip UTF-8 validation since in rust strings are already UTF-8 valid let mut i: usize = 0; for c in phone_number.chars() { @@ -1784,7 +1780,10 @@ impl PhoneNumberUtil { return (phone_number, None); }; - let full_capture = captures.get(0).expect("first capture MUST always be not None"); + // first capture is always not None, this should not happen, but use this for safety. + let Some(full_capture) = captures.get(0) else { + return (phone_number, None); + }; // Replace the extensions in the original string here. let phone_number_no_extn = &phone_number[..full_capture.start()]; // If we find a potential extension, and the number preceding this is a @@ -1825,7 +1824,7 @@ impl PhoneNumberUtil { keep_raw_input: bool, national_number: &'a str, phone_number: &mut PhoneNumber - ) -> std::result::Result, ParseError> { + ) -> ParseResult> { // Set the default prefix to be something that will never match if there is no // default region. let possible_country_idd_prefix = if let Some(default_region_metadata) = default_region_metadata { @@ -2432,7 +2431,7 @@ impl PhoneNumberUtil { &self, first_number: &str, second_number: &str - ) -> std::result::Result { + ) -> MatchResult { match self.parse(first_number, i18n::RegionCode::get_unknown()) { Ok(first_number_as_proto) => return self.is_number_match_with_one_string(&first_number_as_proto, second_number), Err(err) => { @@ -2466,7 +2465,7 @@ impl PhoneNumberUtil { &self, first_number: &PhoneNumber, second_number: &str - ) -> std::result::Result { + ) -> MatchResult { // First see if the second number has an implicit country calling code, by // attempting to parse it. match self.parse(second_number, i18n::RegionCode::get_unknown()) {