Compare commits

..

4 Commits

Author SHA1 Message Date
Vlasislav Kashin
e72187d2d7 Better None handling: Remove unwrap 2025-07-10 12:50:12 +03:00
Vlasislav Kashin
457bb65b9a Better error handling 2025-07-10 12:41:21 +03:00
Vlasislav Kashin
3f07806990 Ugrade methods to return iterators 2025-07-10 11:29:18 +03:00
Vlasislav Kashin
4f5571f7a7 Bug fixes and upgrades 2025-07-10 10:44:11 +03:00
7 changed files with 242 additions and 229 deletions

View File

@@ -64,32 +64,6 @@ pub enum MatchType {
// Separated enum ValidationResult into ValidationResult err and
// ValidationResultOk for using Result<Ok, Err>
/// Possible outcomes when testing if a PhoneNumber is possible.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Error)]
pub enum ValidationResultErr {
/// The number has an invalid country calling code.
#[error("The number has an invalid country calling code")]
InvalidCountryCode,
/// The number is shorter than all valid numbers for this region.
#[error("The number is shorter than all valid numbers for this region")]
TooShort,
/// The number is longer than the shortest valid numbers for this region,
/// shorter than the longest valid numbers for this region, and does not
/// itself have a number length that matches valid numbers for this region.
/// This can also be returned in the case where
/// IsPossibleNumberForTypeWithReason was called, and there are no numbers of
/// this type at all for this region.
#[error("\
The number is longer than the shortest valid numbers for this region,\
shorter than the longest valid numbers for this region, and does not\
itself have a number length that matches valid numbers for this region\
")]
InvalidLength,
/// The number is longer than all valid numbers for this region.
#[error("The number is longer than all valid numbers for this region")]
TooLong,
}
/// Possible outcomes when testing if a PhoneNumber is possible.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum ValidNumberLenType {

View File

@@ -6,13 +6,12 @@ use thiserror::Error;
use crate::regexp_cache::ErrorInvalidRegex;
#[derive(Debug, PartialEq, Error)]
pub enum PhoneNumberUtilError {
pub enum InternalLogicError {
#[error("{0}")]
InvalidRegexError(#[from] ErrorInvalidRegex),
#[error("Parse error: {0}")]
ParseError(#[from] ParseError),
#[error("Extract number error: {0}")]
ExtractNumberError(#[from] ExtractNumberError)
#[error("{0}")]
InvalidMetadataForValidRegionError(#[from] InvalidMetadataForValidRegionError)
}
#[derive(Debug, PartialEq, Error)]
@@ -50,7 +49,7 @@ pub enum GetExampleNumberError {
#[error("Parse error: {0}")]
ParseError(#[from] ParseError),
#[error("{0}")]
InvalidRegexError(#[from] ErrorInvalidRegex),
InternalLogicError(#[from] InternalLogicError),
#[error("No example number")]
NoExampleNumberError,
#[error("Could not get number")]
@@ -61,7 +60,35 @@ pub enum GetExampleNumberError {
#[derive(Error, Debug, PartialEq)]
pub enum MatchError {
#[error("Invalid number given")]
InvalidNumber(#[from] ParseError), // NOT_A_NUMBER in the java version.
#[error("Invalid number given")]
pub struct InvalidNumberError(#[from] pub ParseError); // NOT_A_NUMBER in the java version
#[derive(Debug, Error, PartialEq)]
#[error("Metadata for valid region MUST not be null")]
pub struct InvalidMetadataForValidRegionError;
/// Possible outcomes when testing if a PhoneNumber is possible.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Error)]
pub enum ValidationResultErr {
/// The number has an invalid country calling code.
#[error("The number has an invalid country calling code")]
InvalidCountryCode,
/// The number is shorter than all valid numbers for this region.
#[error("The number is shorter than all valid numbers for this region")]
TooShort,
/// The number is longer than the shortest valid numbers for this region,
/// shorter than the longest valid numbers for this region, and does not
/// itself have a number length that matches valid numbers for this region.
/// This can also be returned in the case where
/// IsPossibleNumberForTypeWithReason was called, and there are no numbers of
/// this type at all for this region.
#[error("\
The number is longer than the shortest valid numbers for this region,\
shorter than the longest valid numbers for this region, and does not\
itself have a number length that matches valid numbers for this region\
")]
InvalidLength,
/// The number is longer than all valid numbers for this region.
#[error("The number is longer than all valid numbers for this region")]
TooLong,
}

View File

@@ -15,7 +15,7 @@ pub const PLUS_CHARS: &'static str = "+\u{FF0B}";
pub const VALID_PUNCTUATION: &'static str = "-x\
\u{2010}-\u{2015}\u{2212}\u{30FC}\u{FF0D}-\u{FF0F} \u{00A0}\
\u{00AD}\u{200B}\u{2060}\u{3000}()\u{FF08}\u{FF09}\u{FF3B}\
\u{FF3D}.[]/~\u{2053}\u{223C}";
\u{FF3D}.\\[\\]/~\u{2053}\u{223C}";
// Regular expression of characters typically used to start a second phone
// number for the purposes of parsing. This allows us to strip off parts of

View File

@@ -12,7 +12,8 @@ use crate::{
};
use super::{
PhoneNumberFormat, PhoneNumberType, ValidNumberLenType, ValidationResultErr,
PhoneNumberFormat, PhoneNumberType, ValidNumberLenType,
errors::ValidationResultErr,
helper_constants::{
METADATA, OPTIONAL_EXT_SUFFIX, PLUS_SIGN, POSSIBLE_CHARS_AFTER_EXT_LABEL,
POSSIBLE_SEPARATORS_BETWEEN_NUMBER_AND_EXT_LABEL, RFC3966_EXTN_PREFIX, RFC3966_PREFIX,
@@ -20,14 +21,14 @@ use super::{
};
/// Loads metadata from helper constants METADATA array
pub(super) fn load_compiled_metadata() -> Result<PhoneMetadataCollection, protobuf::Error> {
pub fn load_compiled_metadata() -> Result<PhoneMetadataCollection, protobuf::Error> {
let result = PhoneMetadataCollection::parse_from_bytes(&METADATA)?;
Ok(result)
}
/// Returns a pointer to the description inside the metadata of the appropriate
/// type.
pub(super) fn get_number_desc_by_type(
pub fn get_number_desc_by_type(
metadata: &PhoneMetadata,
phone_number_type: PhoneNumberType,
) -> &PhoneNumberDesc {
@@ -48,7 +49,7 @@ pub(super) fn get_number_desc_by_type(
}
/// A helper function that is used by Format and FormatByPattern.
pub(super) fn prefix_number_with_country_calling_code(
pub fn prefix_number_with_country_calling_code(
country_calling_code: i32,
number_format: PhoneNumberFormat,
formatted_number: &mut String,
@@ -91,7 +92,7 @@ pub(super) fn prefix_number_with_country_calling_code(
// Returns true when one national number is the suffix of the other or both are
// the same.
pub(super) fn is_national_number_suffix_of_the_other(
pub fn is_national_number_suffix_of_the_other(
first_number: &PhoneNumber,
second_number: &PhoneNumber,
) -> bool {
@@ -106,7 +107,7 @@ pub(super) fn is_national_number_suffix_of_the_other(
/// Helper method for constructing regular expressions for parsing. Creates an
/// expression that captures up to max_length digits.
pub(super) fn extn_digits(max_length: u32) -> String {
pub fn extn_digits(max_length: u32) -> String {
let mut buf = itoa::Buffer::new();
let max_length_str = buf.format(max_length);
const HELPER_STR_LEN: usize = 2 + 4 + 2;
@@ -131,7 +132,7 @@ pub(super) fn extn_digits(max_length: u32) -> String {
// number is changed, MaybeStripExtension needs to be updated.
// - The only capturing groups should be around the digits that you want to
// capture as part of the extension, or else parsing will fail!
pub(super) fn create_extn_pattern(for_parsing: bool) -> String {
pub fn create_extn_pattern(for_parsing: bool) -> String {
// We cap the maximum length of an extension based on the ambiguity of the
// way the extension is prefixed. As per ITU, the officially allowed
// length for extensions is actually 40, but we don't support this since we
@@ -255,7 +256,7 @@ pub(super) fn create_extn_pattern(for_parsing: bool) -> String {
/// left unchanged in the number.
///
/// Returns: normalized_string
pub(super) fn normalize_helper(
pub fn normalize_helper(
normalization_replacements: &HashMap<char, char>,
remove_non_matches: bool,
phone_number: &str
@@ -276,7 +277,7 @@ pub(super) fn normalize_helper(
/// Returns `true` if there is any possible number data set for a particular
/// PhoneNumberDesc.
pub(super) fn desc_has_possible_number_data(desc: &PhoneNumberDesc) -> bool {
pub fn desc_has_possible_number_data(desc: &PhoneNumberDesc) -> bool {
// If this is empty, it means numbers of this type inherit from the "general
// desc" -> the value "-1" means that no numbers exist for this type.
return desc.possible_length.len() != 1
@@ -296,7 +297,7 @@ pub(super) fn desc_has_possible_number_data(desc: &PhoneNumberDesc) -> bool {
/// mention why during a review without needing to change MetadataFilter.
///
/// Returns `true` if there is any data set for a particular PhoneNumberDesc.
pub(super) fn desc_has_data(desc: &PhoneNumberDesc) -> bool {
pub fn desc_has_data(desc: &PhoneNumberDesc) -> bool {
// Checking most properties since we don't know what's present, since a custom
// build may have stripped just one of them (e.g. USE_METADATA_LITE strips
// exampleNumber). We don't bother checking the PossibleLengthsLocalOnly,
@@ -309,7 +310,7 @@ pub(super) fn desc_has_data(desc: &PhoneNumberDesc) -> bool {
/// Returns the types we have metadata for based on the PhoneMetadata object
/// passed in.
pub(super) fn populate_supported_types_for_metadata(
pub fn populate_supported_types_for_metadata(
metadata: &PhoneMetadata,
types: &mut HashSet<PhoneNumberType>,
) {
@@ -329,7 +330,7 @@ pub(super) fn populate_supported_types_for_metadata(
});
}
pub(super) fn get_supported_types_for_metadata(metadata: &PhoneMetadata) -> HashSet<PhoneNumberType> {
pub fn get_supported_types_for_metadata(metadata: &PhoneMetadata) -> HashSet<PhoneNumberType> {
const EFFECTIVE_NUMBER_TYPES: usize = 11 /* count */ - 2 /* filter type or unknown */;
let mut types = HashSet::with_capacity(EFFECTIVE_NUMBER_TYPES);
populate_supported_types_for_metadata(metadata, &mut types);
@@ -338,7 +339,7 @@ pub(super) fn get_supported_types_for_metadata(metadata: &PhoneMetadata) -> Hash
/// Helper method to check a number against possible lengths for this number
/// type, and determine whether it matches, or is too short or too long.
pub(super) fn test_number_length(
pub fn test_number_length(
phone_number: &str,
phone_metadata: &PhoneMetadata,
phone_number_type: PhoneNumberType,
@@ -425,7 +426,7 @@ pub(super) fn test_number_length(
/// Helper method to check a number against possible lengths for this region,
/// based on the metadata being passed in, and determine whether it matches, or
/// is too short or too long.
pub(super) fn test_number_length_with_unknown_type(
pub fn test_number_length_with_unknown_type(
phone_number: &str,
phone_metadata: &PhoneMetadata,
) -> Result<ValidNumberLenType, ValidationResultErr> {
@@ -454,7 +455,7 @@ pub(crate) fn copy_core_fields_only(from_number: &PhoneNumber) -> PhoneNumber {
/// Determines whether the given number is a national number match for the given
/// PhoneNumberDesc. Does not check against possible lengths!
pub(super) fn is_match(
pub fn is_match(
matcher_api: &Box<dyn MatcherApi>,
number: &str,
number_desc: &PhoneNumberDesc,

View File

@@ -9,7 +9,7 @@ pub(self) mod comparisons;
use std::sync::LazyLock;
pub use enums::{MatchType, PhoneNumberFormat, PhoneNumberType, ValidationResultErr, ValidNumberLenType};
pub use enums::{MatchType, PhoneNumberFormat, PhoneNumberType, ValidNumberLenType};
use thiserror::Error;
// use crate::phonenumberutil::phonenumberutil::PhoneNumberUtil;

View File

@@ -164,7 +164,13 @@ pub(super) struct PhoneNumberRegExpsAndMappings {
/// followed by a single digit, separated by valid phone number punctuation.
/// This prevents invalid punctuation (such as the star sign in Israeli star
/// numbers) getting into the output of the AYTF.
pub is_format_eligible_as_you_type_formatting_regex: Regex
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
}
impl PhoneNumberRegExpsAndMappings {
@@ -323,8 +329,17 @@ impl PhoneNumberRegExpsAndMappings {
is_format_eligible_as_you_type_formatting_regex: Regex::new(
&format!("[{}]*\\$1[{}]*(\\$\\d[{}]*)*",VALID_PUNCTUATION, VALID_PUNCTUATION, VALID_PUNCTUATION)
).unwrap(),
formatting_rule_has_first_group_only_regex: Regex::new("\\(?\\$1\\)?").unwrap()
};
instance.initialize_regexp_mappings();
instance
}
}
#[cfg(test)]
mod tests {
#[test]
fn check_regexps_are_compiling() {
super::PhoneNumberRegExpsAndMappings::new();
}
}

View File

@@ -1,15 +1,15 @@
use std::{
borrow::Cow, cmp::max, collections::{HashMap, HashSet, VecDeque}, sync::Arc
borrow::Cow, cmp::max, collections::{hash_map, HashMap, HashSet, VecDeque}, sync::Arc
};
use super::phone_number_regexps_and_mappings::PhoneNumberRegExpsAndMappings;
use crate::{
i18n, interfaces::MatcherApi, macros::owned_from_cow_or, phonenumberutil::{
errors::{ExtractNumberError, GetExampleNumberError, ParseError, PhoneNumberUtilError, MatchError}, helper_constants::{
errors::{ExtractNumberError, GetExampleNumberError, InternalLogicError, InvalidMetadataForValidRegionError, InvalidNumberError, ParseError, ValidationResultErr}, helper_constants::{
DEFAULT_EXTN_PREFIX, MAX_LENGTH_COUNTRY_CODE, MAX_LENGTH_FOR_NSN, MIN_LENGTH_FOR_NSN, NANPA_COUNTRY_CODE, PLUS_SIGN, REGION_CODE_FOR_NON_GEO_ENTITY, RFC3966_EXTN_PREFIX, RFC3966_ISDN_SUBADDRESS, RFC3966_PHONE_CONTEXT, RFC3966_PREFIX
}, helper_functions::{
self, copy_core_fields_only, get_number_desc_by_type, get_supported_types_for_metadata, is_national_number_suffix_of_the_other, load_compiled_metadata, normalize_helper, prefix_number_with_country_calling_code, test_number_length, test_number_length_with_unknown_type
}, helper_types::{PhoneNumberAndCarrierCode, PhoneNumberWithCountryCodeSource}, MatchType, PhoneNumberFormat, PhoneNumberType, ValidNumberLenType, ValidationResultErr
}, helper_types::{PhoneNumberAndCarrierCode, PhoneNumberWithCountryCodeSource}, MatchType, PhoneNumberFormat, PhoneNumberType, ValidNumberLenType
}, proto_gen::{
phonemetadata::{NumberFormat, PhoneMetadata, PhoneNumberDesc},
phonenumber::{phone_number::CountryCodeSource, PhoneNumber},
@@ -21,7 +21,6 @@ use log::{error, trace, warn};
use regex::Regex;
// Helper type for Result
pub type Result<T> = std::result::Result<T, PhoneNumberUtilError>;
pub type RegexResult<T> = std::result::Result<T, ErrorInvalidRegex>;
@@ -29,6 +28,9 @@ pub type ParseResult<T> = std::result::Result<T, ParseError>;
pub type ExampleNumberResult = std::result::Result<PhoneNumber, GetExampleNumberError>;
pub type ValidationResult = std::result::Result<ValidNumberLenType, ValidationResultErr>;
pub type MatchResult = std::result::Result<MatchType, InvalidNumberError>;
pub type ExtractNumberResult<T> = std::result::Result<T, ExtractNumberError>;
pub type InternalLogicResult<T> = std::result::Result<T, InternalLogicError>;
pub struct PhoneNumberUtil {
/// An API for validation checking.
@@ -126,32 +128,21 @@ impl PhoneNumberUtil {
instance
}
pub fn get_supported_regions(&self) -> Vec<&str> {
let mut regions = Vec::new();
for (k, _) in self.region_to_metadata_map.iter() {
regions.push(k.as_str());
}
regions
fn get_supported_regions(&self) -> impl Iterator<Item=&str> {
self.region_to_metadata_map.keys().map(| k | k.as_str())
}
pub fn get_supported_global_network_calling_codes(&self) -> HashSet<i32> {
let mut codes = HashSet::new();
for (k, _) in self.country_code_to_non_geographical_metadata_map.iter() {
codes.insert(*k);
}
codes
fn get_supported_global_network_calling_codes(&self) -> impl Iterator<Item=i32> {
self.country_code_to_non_geographical_metadata_map.keys().map(| k | *k)
}
pub fn get_supported_calling_codes(&self) -> HashSet<i32> {
let mut codes = HashSet::new();
for (k, _) in self.country_calling_code_to_region_code_map.iter() {
codes.insert(*k);
}
codes
fn get_supported_calling_codes(&self) -> impl Iterator<Item=i32> {
self.country_calling_code_to_region_code_map
.iter()
.map(| (k, _) | *k)
}
pub fn get_supported_types_for_region(
fn get_supported_types_for_region(
&self,
region_code: &str,
) -> Option<HashSet<PhoneNumberType>> {
@@ -164,7 +155,7 @@ impl PhoneNumberUtil {
})
}
pub fn get_supported_types_for_non_geo_entity(
fn get_supported_types_for_non_geo_entity(
&self,
country_calling_code: i32,
) -> Option<HashSet<PhoneNumberType>> {
@@ -180,21 +171,21 @@ impl PhoneNumberUtil {
})
}
fn get_extn_patterns_for_matching(&self) -> &str {
pub fn get_extn_patterns_for_matching(&self) -> &str {
return &self.reg_exps.extn_patterns_for_matching;
}
fn starts_with_plus_chars_pattern(&self, phone_number: &str) -> bool {
pub fn starts_with_plus_chars_pattern(&self, phone_number: &str) -> bool {
self.reg_exps
.plus_chars_pattern
.matches_start(phone_number)
}
fn contains_only_valid_digits(&self, s: &str) -> bool {
pub fn contains_only_valid_digits(&self, s: &str) -> bool {
self.reg_exps.digits_pattern.full_match(s)
}
fn trim_unwanted_end_chars<'a>(&self, phone_number: &'a str) -> &'a str {
pub fn trim_unwanted_end_chars<'a>(&self, phone_number: &'a str) -> &'a str {
let mut bytes_to_trim = 0;
for char in phone_number.chars().rev() {
@@ -216,7 +207,7 @@ impl PhoneNumberUtil {
}
}
fn is_format_eligible_for_as_you_type_formatter(&self, format: &str) -> bool {
pub fn is_format_eligible_for_as_you_type_formatter(&self, format: &str) -> bool {
// We require that the first
// group is present in the output pattern to ensure no data is lost while
// formatting; when we format as you type, this should always be the case.
@@ -226,20 +217,14 @@ impl PhoneNumberUtil {
.full_match(format);
}
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!");
pub fn formatting_rule_has_first_group_only(&self, national_prefix_formatting_rule: &str) -> bool {
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(
pub fn get_ndd_prefix_for_region(
&self,
region_code: &str,
strip_non_digits: bool,
@@ -260,11 +245,11 @@ impl PhoneNumberUtil {
}
/// 'hot' function wrapper for region_to_metadata_map.get
fn get_metadata_for_region(&self, region_code: &str) -> Option<&PhoneMetadata> {
pub fn get_metadata_for_region(&self, region_code: &str) -> Option<&PhoneMetadata> {
return self.region_to_metadata_map.get(region_code)
}
fn format<'b>(
pub fn format<'b>(
&self,
phone_number: &'b PhoneNumber,
number_format: PhoneNumberFormat,
@@ -319,7 +304,7 @@ impl PhoneNumberUtil {
Ok(Cow::Owned(formatted_number))
}
fn get_national_significant_number(phone_number: &PhoneNumber) -> String {
pub fn get_national_significant_number(phone_number: &PhoneNumber) -> String {
let zeros_start = if phone_number.italian_leading_zero() {
"0".repeat(max(phone_number.number_of_leading_zeros() as usize, 0))
} else {
@@ -338,38 +323,36 @@ impl PhoneNumberUtil {
/// Returns the region code that matches the specific country calling code. In
/// the case of no region code being found, the unknown region code will be
/// returned.
fn get_region_code_for_country_code(&self, country_calling_code: i32) -> &str {
pub 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.
fn get_region_codes_for_country_calling_code(
/// 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.
pub fn get_region_codes_for_country_calling_code(
&self,
country_calling_code: i32,
) -> Vec<&str> {
let mut acc = Vec::with_capacity(10);
) -> Option<impl Iterator<Item=&str>> {
// 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(
pub fn get_metadata_for_region_or_calling_code(
&self,
country_calling_code: i32,
region_code: &str,
@@ -382,7 +365,7 @@ impl PhoneNumberUtil {
};
}
fn format_nsn<'b>(
pub fn format_nsn<'b>(
&self,
phone_number: &'b str,
metadata: &PhoneMetadata,
@@ -421,7 +404,7 @@ impl PhoneNumberUtil {
}
}
fn choose_formatting_pattern_for_number<'b>(
pub fn choose_formatting_pattern_for_number<'b>(
&self,
available_formats: &'b [NumberFormat],
national_number: &str,
@@ -535,7 +518,7 @@ impl PhoneNumberUtil {
/// Simple wrapper of FormatNsnUsingPatternWithCarrier for the common case of
/// no carrier code.
fn format_nsn_using_pattern<'b>(
pub fn format_nsn_using_pattern<'b>(
&self,
national_number: &'b str,
formatting_pattern: &NumberFormat,
@@ -549,8 +532,8 @@ impl PhoneNumberUtil {
)
}
// Returns the formatted extension of a phone number, if the phone number had an
// extension specified else None.
/// Returns the formatted extension of a phone number, if the phone number had an
/// extension specified else None.
fn get_formatted_extension(
phone_number: &PhoneNumber,
metadata: &PhoneMetadata,
@@ -570,7 +553,7 @@ impl PhoneNumberUtil {
Some(fast_cat::concat_str!(prefix, phone_number.extension()))
}
fn format_by_pattern(
pub fn format_by_pattern(
&self,
phone_number: &PhoneNumber,
number_format: PhoneNumberFormat,
@@ -636,11 +619,11 @@ impl PhoneNumberUtil {
Ok(formatted_number)
}
fn format_national_number_with_carrier_code(
pub fn format_national_number_with_carrier_code(
&self,
phone_number: &PhoneNumber,
carrier_code: &str,
) -> Result<String> {
) -> RegexResult<String> {
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);
@@ -673,11 +656,11 @@ impl PhoneNumberUtil {
Ok(formatted_number)
}
fn format_national_number_with_preferred_carrier_code(
pub fn format_national_number_with_preferred_carrier_code(
&self,
phone_number: &PhoneNumber,
fallback_carrier_code: &str,
) -> Result<String> {
) -> RegexResult<String> {
let carrier_code = if !phone_number.preferred_domestic_carrier_code().is_empty() {
phone_number.preferred_domestic_carrier_code()
} else {
@@ -697,12 +680,12 @@ impl PhoneNumberUtil {
.is_ok();
}
fn format_number_for_mobile_dialing<'b>(
pub fn format_number_for_mobile_dialing<'b>(
&self,
phone_number: &'b PhoneNumber,
calling_from: &str,
with_formatting: bool,
) -> Result<Cow<'b, str>> {
) -> InternalLogicResult<Cow<'b, str>> {
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() {
@@ -749,7 +732,7 @@ impl PhoneNumberUtil {
// dialled in national format.
let region_metadata = self.region_to_metadata_map
.get(calling_from)
.unwrap() /* we've checked if number is valid at top of function */;
.ok_or(InvalidMetadataForValidRegionError{})?;
let national_number = Self::get_national_significant_number(&number_no_extension);
let format = if self.can_be_internationally_dialled(&number_no_extension)?
&& test_number_length_with_unknown_type(
@@ -828,7 +811,7 @@ impl PhoneNumberUtil {
}
}
fn get_number_type(&self, phone_number: &PhoneNumber) -> RegexResult<PhoneNumberType> {
pub fn get_number_type(&self, phone_number: &PhoneNumber) -> InternalLogicResult<PhoneNumberType> {
let region_code = self.get_region_code_for_number(phone_number)?;
let Some(metadata) = self
.get_metadata_for_region_or_calling_code(phone_number.country_code(), region_code)
@@ -839,13 +822,16 @@ impl PhoneNumberUtil {
Ok(self.get_number_type_helper(&national_significant_number, metadata))
}
fn get_region_code_for_number(&self, phone_number: &PhoneNumber) -> RegexResult<&str>{
pub fn get_region_code_for_number(&self, phone_number: &PhoneNumber) -> InternalLogicResult<&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::<Vec<_>>())
.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 {
@@ -853,16 +839,18 @@ impl PhoneNumberUtil {
}
}
fn get_region_code_for_number_from_region_list<'b>(
pub fn get_region_code_for_number_from_region_list<'b>(
&self,
phone_number: &PhoneNumber,
region_codes: &[&'b str],
) -> RegexResult<&'b str> {
) -> InternalLogicResult<&'b str> {
let national_number = Self::get_national_significant_number(phone_number);
for code in region_codes {
// Metadata cannot be NULL because the region codes come from the country
// calling code map.
let metadata = &self.region_to_metadata_map[*code];
let metadata = &self.region_to_metadata_map
.get(*code)
.ok_or(InvalidMetadataForValidRegionError{})?;
if metadata.has_leading_digits() {
if self.reg_exps.regexp_cache
.get_regex(metadata.leading_digits())?
@@ -946,7 +934,7 @@ impl PhoneNumberUtil {
return PhoneNumberType::Unknown;
}
fn is_number_matching_desc(
pub fn is_number_matching_desc(
&self,
national_number: &str,
number_desc: &PhoneNumberDesc
@@ -963,10 +951,10 @@ impl PhoneNumberUtil {
helper_functions::is_match(&self.matcher_api, national_number, number_desc)
}
fn can_be_internationally_dialled(
pub fn can_be_internationally_dialled(
&self,
phone_number: &PhoneNumber
) -> Result<bool> {
) -> InternalLogicResult<bool> {
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)
@@ -979,29 +967,29 @@ impl PhoneNumberUtil {
));
}
fn normalize_diallable_chars_only(&self, phone_number: &str) -> String {
pub fn normalize_diallable_chars_only(&self, phone_number: &str) -> String {
normalize_helper(
&self.reg_exps.diallable_char_mappings,
true, phone_number
)
}
fn normalize_digits_only<'a>(&self, phone_number: &'a str) -> String {
pub fn normalize_digits_only<'a>(&self, phone_number: &'a str) -> String {
phone_number.chars()
.filter_map(| c | c.to_decimal_utf8())
.filter_map(| i | char::from_u32(b'0' as u32 + i) )
.collect()
}
fn format_out_of_country_calling_number<'a>(
pub fn format_out_of_country_calling_number<'a>(
&self,
phone_number: &'a PhoneNumber,
calling_from: &str,
) -> RegexResult<Cow<'a, str>> {
) -> InternalLogicResult<Cow<'a, str>> {
let Some(metadata_calling_from) = self.region_to_metadata_map.get(calling_from) else {
trace!("Trying to format number from invalid region {calling_from}\
. International formatting applied.");
return self.format(phone_number, PhoneNumberFormat::International)
return Ok(self.format(phone_number, PhoneNumberFormat::International)?)
};
let country_code = phone_number.country_code();
let national_significant_number = Self::get_national_significant_number(
@@ -1032,7 +1020,7 @@ impl PhoneNumberUtil {
// those cases return the version including country calling code.
// Details here:
// http://www.petitfute.com/voyage/225-info-pratiques-reunion
return self.format(phone_number, PhoneNumberFormat::National)
return Ok(self.format(phone_number, PhoneNumberFormat::National)?)
}
// Metadata cannot be NULL because we checked 'IsValidRegionCode()' above.
let international_prefix = metadata_calling_from.international_prefix();
@@ -1054,7 +1042,7 @@ impl PhoneNumberUtil {
// Metadata cannot be NULL because the country_code is valid.
let metadata_for_region = self
.get_metadata_for_region_or_calling_code(country_code, region_code)
.expect("Metadata cannot be NULL because the country_code is valid");
.ok_or(InvalidMetadataForValidRegionError{})?;
let formatted_nsn = self
.format_nsn(
@@ -1104,18 +1092,18 @@ impl PhoneNumberUtil {
return format_rule.map(| rule | rule.is_some());
}
fn format_in_original_format<'a>(
pub fn format_in_original_format<'a>(
&self,
phone_number: &'a PhoneNumber,
region_calling_from: &str,
) -> RegexResult<Cow<'a, str>> {
) -> InternalLogicResult<Cow<'a, str>> {
if phone_number.has_raw_input() && !self.has_formatting_pattern_for_number(phone_number)? {
// We check if we have the formatting pattern because without that, we might
// format the number as a group without national prefix.
return Ok(Cow::Borrowed(phone_number.raw_input()))
}
if !phone_number.has_country_code_source() {
return self.format(phone_number, PhoneNumberFormat::National)
return Ok(self.format(phone_number, PhoneNumberFormat::National)?)
}
let formatted_number = match phone_number.country_code_source() {
CountryCodeSource::FROM_NUMBER_WITH_PLUS_SIGN =>
@@ -1221,7 +1209,7 @@ impl PhoneNumberUtil {
raw_input: &str,
national_prefix: &str,
region_code: &str
) -> RegexResult<bool> {
) -> InternalLogicResult<bool> {
let normalized_national_number = self.normalize_digits_only(raw_input);
if normalized_national_number.starts_with(national_prefix) {
// Some Japanese numbers (e.g. 00777123) might be mistaken to contain
@@ -1239,20 +1227,20 @@ impl PhoneNumberUtil {
Ok(false)
}
fn parse(&self, number_to_parse: &str, default_region: &str) -> ParseResult<PhoneNumber> {
pub fn parse(&self, number_to_parse: &str, default_region: &str) -> ParseResult<PhoneNumber> {
self.parse_helper(number_to_parse, default_region, false, true)
}
fn parse_and_keep_raw_input(&self, number_to_parse: &str, default_region: &str) -> ParseResult<PhoneNumber> {
pub fn parse_and_keep_raw_input(&self, number_to_parse: &str, default_region: &str) -> ParseResult<PhoneNumber> {
self.parse_helper(number_to_parse, default_region, true, true)
}
fn is_valid_number(&self, phone_number: &PhoneNumber) -> RegexResult<bool> {
pub fn is_valid_number(&self, phone_number: &PhoneNumber) -> InternalLogicResult<bool> {
let region_code = self.get_region_code_for_number(phone_number)?;
return Ok(self.is_valid_number_for_region(phone_number, region_code));
}
fn is_valid_number_for_region(&self, phone_number: &PhoneNumber, region_code: &str) -> bool {
pub fn is_valid_number_for_region(&self, phone_number: &PhoneNumber, region_code: &str) -> bool {
let country_code = phone_number.country_code();
let metadata =
self.get_metadata_for_region_or_calling_code(country_code, region_code);
@@ -1266,11 +1254,11 @@ impl PhoneNumberUtil {
}
}
fn format_out_of_country_keeping_alpha_chars<'a>(
pub fn format_out_of_country_keeping_alpha_chars<'a>(
&self,
phone_number: &'a PhoneNumber,
calling_from: &str,
) -> RegexResult<Cow<'a, str>> {
) -> InternalLogicResult<Cow<'a, str>> {
// If there is no raw input, then we can't keep alpha characters because there
// aren't any. In this case, we return FormatOutOfCountryCallingNumber.
if phone_number.raw_input().is_empty() {
@@ -1333,11 +1321,12 @@ impl PhoneNumberUtil {
// leading digits) decide whether a national prefix needs to be used, since
// we have overridden the pattern to match anything, but that is not the
// case in the metadata to date.
return self.format_nsn_using_pattern(
&normalized_raw_input,
&new_format,
PhoneNumberFormat::National
).map(| cow | Cow::Owned(cow.into_owned()) );
return Ok(self.format_nsn_using_pattern(
&normalized_raw_input,
&new_format,
PhoneNumberFormat::National
).map(| cow | Cow::Owned(cow.into_owned()) )?
);
}
// If an unsupported region-calling-from is entered, or a country with
@@ -1376,7 +1365,7 @@ impl PhoneNumberUtil {
// Metadata cannot be null because the country code is valid.
let metadata_for_region = self
.get_metadata_for_region_or_calling_code(country_code, region_code)
.expect("Metadata cannot be null because the country code is valid.");
.ok_or(InvalidMetadataForValidRegionError{})?;
// Strip any extension
let (phone_number_without_extension, _) = self
@@ -1396,7 +1385,7 @@ impl PhoneNumberUtil {
/// Returns whether the value of phoneContext follows the syntax defined in
/// RFC3966.
fn is_phone_context_valid(
pub fn is_phone_context_valid(
&self,
phone_context: &str
) -> bool {
@@ -1414,7 +1403,7 @@ impl PhoneNumberUtil {
/// Converts number_to_parse to a form that we can parse and write it to
/// national_number if it is written in RFC3966; otherwise extract a possible
/// number out of it and write to national_number.
fn build_national_number_for_parsing(
pub fn build_national_number_for_parsing(
&self, number_to_parse: &str
) -> ParseResult<String> {
let index_of_phone_context = number_to_parse.find(RFC3966_PHONE_CONTEXT);
@@ -1482,7 +1471,7 @@ impl PhoneNumberUtil {
///
/// Returns the extracted `Some(possibly empty)`, or a `None` if no
/// phone-context parameter is found.
fn extract_phone_context<'a>(
pub fn extract_phone_context<'a>(
number_to_extract_from: &'a str,
index_of_phone_context: usize
) -> &'a str {
@@ -1514,7 +1503,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> {
pub 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() {
@@ -1545,11 +1534,11 @@ impl PhoneNumberUtil {
)
}
fn is_possible_number(&self, phone_number: &PhoneNumber) -> bool{
pub fn is_possible_number(&self, phone_number: &PhoneNumber) -> bool{
self.is_possible_number_with_reason(phone_number).is_ok()
}
fn is_possible_number_for_type(
pub fn is_possible_number_for_type(
&self,
phone_number: &PhoneNumber,
phone_number_type: PhoneNumberType
@@ -1557,7 +1546,7 @@ impl PhoneNumberUtil {
self.is_possible_number_for_type_with_reason(phone_number, phone_number_type).is_ok()
}
fn is_possible_number_for_string(
pub fn is_possible_number_for_string(
&self,
phone_number: &str,
region_dialing_from: &str
@@ -1571,14 +1560,14 @@ impl PhoneNumberUtil {
}
}
fn is_possible_number_with_reason(
pub fn is_possible_number_with_reason(
&self, phone_number: &PhoneNumber
) -> ValidationResult {
self.is_possible_number_for_type_with_reason(phone_number, PhoneNumberType::Unknown)
}
fn is_possible_number_for_type_with_reason(
pub fn is_possible_number_for_type_with_reason(
&self, phone_number: &PhoneNumber, phone_number_type: PhoneNumberType
) -> ValidationResult {
let national_number = Self::get_national_significant_number(phone_number);
@@ -1604,7 +1593,7 @@ impl PhoneNumberUtil {
return test_number_length(&national_number, metadata, phone_number_type);
}
fn truncate_too_long_number(&self, phone_number: &mut PhoneNumber) -> RegexResult<bool> {
pub fn truncate_too_long_number(&self, phone_number: &mut PhoneNumber) -> InternalLogicResult<bool> {
if self.is_valid_number(&phone_number)? {
return Ok(true)
}
@@ -1629,7 +1618,7 @@ impl PhoneNumberUtil {
// Note if any new field is added to this method that should always be filled
// in, even when keepRawInput is false, it should also be handled in the
// CopyCoreFieldsOnly() method.
fn parse_helper(
pub fn parse_helper(
&self,
number_to_parse: &str,
default_region: &str,
@@ -1765,7 +1754,7 @@ impl PhoneNumberUtil {
/// method does not require the number to be normalized in advance - but does
/// assume that leading non-number symbols have been removed, such as by the
/// method `ExtractPossibleNumber`.
fn is_viable_phone_number(&self, phone_number: &str) -> bool {
pub fn is_viable_phone_number(&self, phone_number: &str) -> bool {
if phone_number.len() < MIN_LENGTH_FOR_NSN {
false
} else {
@@ -1777,7 +1766,7 @@ impl PhoneNumberUtil {
/// the number to parse starts with a + symbol so that we can attempt to infer
/// the country from the number. Returns false if it cannot use the region
/// provided and the region cannot be inferred.
fn check_region_for_parsing(
pub fn check_region_for_parsing(
&self,
number_to_parse: &str,
default_region: &str
@@ -1790,12 +1779,15 @@ impl PhoneNumberUtil {
/// Strips any extension (as in, the part of the number dialled after the call is
/// connected, usually indicated with extn, ext, x or similar) from the end of
/// the number, and returns stripped number and extension. The number passed in should be non-normalized.
fn maybe_strip_extension<'a>(&self, phone_number: &'a str) -> (&'a str, Option<&'a str>) {
pub fn maybe_strip_extension<'a>(&self, phone_number: &'a str) -> (&'a str, Option<&'a str>) {
let Some(captures) = self.reg_exps.extn_pattern.captures(phone_number) else {
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
@@ -1810,33 +1802,33 @@ impl PhoneNumberUtil {
(phone_number, None)
}
// Tries to extract a country calling code from a number. Country calling codes
// are extracted in the following ways:
// - by stripping the international dialing prefix of the region the person
// is dialing from, if this is present in the number, and looking at the next
// digits
// - by stripping the '+' sign if present and then looking at the next digits
// - by comparing the start of the number and the country calling code of the
// default region. If the number is not considered possible for the numbering
// plan of the default region initially, but starts with the country calling
// code of this region, validation will be reattempted after stripping this
// country calling code. If this number is considered a possible number, then
// the first digits will be considered the country calling code and removed as
// such.
//
// Returns NO_PARSING_ERROR if a country calling code was successfully
// extracted or none was present, or the appropriate error otherwise, such as
// if a + was present but it was not followed by a valid country calling code.
// If NO_PARSING_ERROR is returned, the national_number without the country
// calling code is populated, and the country_code of the phone_number passed
// in is set to the country calling code if found, otherwise to 0.
fn maybe_extract_country_code<'a>(
/// Tries to extract a country calling code from a number. Country calling codes
/// are extracted in the following ways:
/// - by stripping the international dialing prefix of the region the person
/// is dialing from, if this is present in the number, and looking at the next
/// digits
/// - by stripping the '+' sign if present and then looking at the next digits
/// - by comparing the start of the number and the country calling code of the
/// default region. If the number is not considered possible for the numbering
/// plan of the default region initially, but starts with the country calling
/// code of this region, validation will be reattempted after stripping this
/// country calling code. If this number is considered a possible number, then
/// the first digits will be considered the country calling code and removed as
/// such.
///
/// Returns `Ok` if a country calling code was successfully
/// extracted or none was present, or the appropriate error otherwise, such as
/// if a + was present but it was not followed by a valid country calling code.
/// If NO_PARSING_ERROR is returned, the national_number without the country
/// calling code is populated, and the country_code of the phone_number passed
/// in is set to the country calling code if found, otherwise to 0.
pub fn maybe_extract_country_code<'a>(
&self,
default_region_metadata: Option<&PhoneMetadata>,
keep_raw_input: bool,
national_number: &'a str,
phone_number: &mut PhoneNumber
) -> std::result::Result<Cow<'a, str>, ParseError> {
) -> ParseResult<Cow<'a, str>> {
// 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 {
@@ -1912,11 +1904,11 @@ impl PhoneNumberUtil {
/// Gets a valid fixed-line number for the specified region_code. Returns false
/// if no number exists.
fn get_example_number(&self, region_code: &str) -> ExampleNumberResult {
pub fn get_example_number(&self, region_code: &str) -> ExampleNumberResult {
self.get_example_number_for_type_and_region_code(region_code, PhoneNumberType::FixedLine)
}
fn get_invalid_example_number(&self, region_code: &str) -> ExampleNumberResult {
pub fn get_invalid_example_number(&self, region_code: &str) -> ExampleNumberResult {
let Some(region_metadata) = self.region_to_metadata_map.get(region_code) else {
warn!("Invalid or unknown region code ({}) provided.", region_code);
return Err(GetExampleNumberError::InvalidMetadataError)
@@ -1968,7 +1960,7 @@ impl PhoneNumberUtil {
// Gets a valid number for the specified region_code and type. Returns false if
// no number exists.
fn get_example_number_for_type_and_region_code(
pub fn get_example_number_for_type_and_region_code(
&self,
region_code: &str,
phone_number_type: PhoneNumberType,
@@ -1987,11 +1979,11 @@ impl PhoneNumberUtil {
Err(GetExampleNumberError::CouldNotGetNumberError)
}
fn get_example_number_for_type(
pub fn get_example_number_for_type(
&self,
phone_number_type: PhoneNumberType,
) -> ExampleNumberResult {
if let Some(number) = self.get_supported_regions().iter()
if let Some(number) = self.get_supported_regions()
.find_map(| region_code |
self.get_example_number_for_type_and_region_code(region_code, phone_number_type).ok()
) {
@@ -2025,7 +2017,7 @@ impl PhoneNumberUtil {
Err(GetExampleNumberError::CouldNotGetNumberError)
}
fn get_example_number_for_non_geo_entity(
pub fn get_example_number_for_non_geo_entity(
&self,
country_calling_code: i32
) -> ExampleNumberResult {
@@ -2073,7 +2065,7 @@ impl PhoneNumberUtil {
/// Returns true if an international dialing prefix could be removed from the
/// number, otherwise false if the number did not seem to be in international
/// format.
fn maybe_strip_international_prefix_and_normalize<'a>(
pub fn maybe_strip_international_prefix_and_normalize<'a>(
&self,
phone_number: &'a str,
possible_idd_prefix: &str,
@@ -2125,7 +2117,7 @@ impl PhoneNumberUtil {
/// - Wide-ascii digits are converted to normal ASCII (European) digits.
/// - Arabic-Indic numerals are converted to European numerals.
/// - Spurious alpha characters are stripped.
fn normalize(&self, phone_number: &str) -> String {
pub fn normalize(&self, phone_number: &str) -> String {
if self.reg_exps.valid_alpha_phone_pattern.is_match(phone_number) {
normalize_helper(
&self.reg_exps.alpha_phone_mappings,
@@ -2139,7 +2131,7 @@ impl PhoneNumberUtil {
/// Strips the IDD from the start of the number if present. Helper function used
/// by MaybeStripInternationalPrefixAndNormalize.
fn parse_prefix_as_idd<'a>(&self, phone_number: & 'a str, idd_pattern: Arc<Regex>) -> Option<&'a str> {
pub fn parse_prefix_as_idd<'a>(&self, phone_number: & 'a str, idd_pattern: Arc<Regex>) -> Option<&'a str> {
// First attempt to strip the idd_pattern at the start, if present. We make a
// copy so that we can revert to the original string if necessary.
let Some(idd_pattern_match) = idd_pattern.find_start(&phone_number) else {
@@ -2158,17 +2150,17 @@ impl PhoneNumberUtil {
Some(&phone_number[captured_range_end..])
}
fn is_number_geographical(
pub fn is_number_geographical(
&self,
phone_number: &PhoneNumber
) -> RegexResult<bool> {
) -> InternalLogicResult<bool> {
Ok(self.is_number_geographical_by_country_code_and_type(
self.get_number_type(phone_number)?,
phone_number.country_code()
))
}
fn is_number_geographical_by_country_code_and_type(
pub fn is_number_geographical_by_country_code_and_type(
&self,
phone_number_type: PhoneNumberType,
country_calling_code: i32
@@ -2182,9 +2174,9 @@ impl PhoneNumberUtil {
)
}
fn get_length_of_geographical_area_code(
pub fn get_length_of_geographical_area_code(
&self, phone_number: &PhoneNumber
) -> RegexResult<usize> {
) -> InternalLogicResult<usize> {
let region_code = self.get_region_code_for_number(phone_number)?;
let Some(metadata) = self.region_to_metadata_map.get(region_code) else {
return Ok(0)
@@ -2217,9 +2209,9 @@ impl PhoneNumberUtil {
return self.get_length_of_national_destination_code(phone_number);
}
fn get_length_of_national_destination_code(
pub fn get_length_of_national_destination_code(
&self, phone_number: &PhoneNumber
) -> RegexResult<usize> {
) -> InternalLogicResult<usize> {
let mut copied_proto = phone_number.clone();
if phone_number.has_extension() {
// Clear the extension so it's not included when formatting.
@@ -2259,7 +2251,7 @@ impl PhoneNumberUtil {
Ok(captured_groups[ndc_index])
}
fn get_country_mobile_token(&self, country_calling_code: i32) -> Option<char> {
pub fn get_country_mobile_token(&self, country_calling_code: i32) -> Option<char> {
self
.reg_exps
.mobile_token_mappings
@@ -2274,7 +2266,7 @@ impl PhoneNumberUtil {
///
/// Returns None if national_number doesn't start with a valid country calling code
/// Assumes the national_number is at least 3 characters long.
fn extract_country_code<'a>(&self, national_number: Cow<'a, str>) -> Option<(Cow<'a, str>, i32)> {
pub fn extract_country_code<'a>(&self, national_number: Cow<'a, str>) -> Option<(Cow<'a, str>, i32)> {
if national_number.as_ref().is_empty() || national_number.as_ref().starts_with('0') {
return None
}
@@ -2302,7 +2294,7 @@ impl PhoneNumberUtil {
// to strip any national dialing prefix from. The metadata should be for the
// region that we think this number is from. Returns true if a national prefix
// and/or carrier code was stripped.
fn maybe_strip_national_prefix_and_carrier_code<'a>(
pub fn maybe_strip_national_prefix_and_carrier_code<'a>(
&self,
metadata: &PhoneMetadata,
phone_number: &'a str,
@@ -2327,11 +2319,15 @@ impl PhoneNumberUtil {
let first_capture = captures.as_ref().and_then(| c | c.get(1));
let second_capture = captures.as_ref().and_then(| c | c.get(2));
if !transform_rule.is_empty() &&
second_capture.is_some_and(| c | !c.is_empty() && first_capture.is_some())
|| first_capture.is_some_and(| c | !c.is_empty() && second_capture.is_none()) {
let condition = |first_capture: &regex::Match<'_>| {
!transform_rule.is_empty() &&
(second_capture.is_some_and(| c | !c.is_empty()) ||
!first_capture.is_empty() && second_capture.is_none())
};
let first_capture = first_capture.unwrap();
if let Some(first_capture) = first_capture.filter(condition) {
// here we can safe unwrap because first_capture.is_some() anyway
let carrier_code_temp = if second_capture.is_some() {
Some(first_capture.as_str())
} else {
@@ -2368,7 +2364,7 @@ impl PhoneNumberUtil {
// A helper function to set the values related to leading zeros in a
// PhoneNumber.
fn get_italian_leading_zeros_for_phone_number(
pub fn get_italian_leading_zeros_for_phone_number(
national_number: &str
) -> Option<usize> {
if national_number.len() < 2 {
@@ -2384,7 +2380,7 @@ impl PhoneNumberUtil {
Some(zero_count)
}
fn convert_alpha_characters_in_number(&self, phone_number: &str) -> String {
pub fn convert_alpha_characters_in_number(&self, phone_number: &str) -> String {
normalize_helper(
&self.reg_exps.alpha_phone_mappings,
false,
@@ -2392,7 +2388,7 @@ impl PhoneNumberUtil {
)
}
fn is_number_match(
pub fn is_number_match(
&self,
first_number_in: &PhoneNumber,
second_number_in: &PhoneNumber,
@@ -2439,16 +2435,16 @@ impl PhoneNumberUtil {
return MatchType::NoMatch
}
fn is_number_match_with_two_strings(
pub fn is_number_match_with_two_strings(
&self,
first_number: &str,
second_number: &str
) -> std::result::Result<MatchType, MatchError> {
) -> 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) => {
if !matches!(err, ParseError::InvalidCountryCodeError) {
return Err(MatchError::InvalidNumber(err))
return Err(InvalidNumberError(err))
}
}
}
@@ -2456,7 +2452,7 @@ impl PhoneNumberUtil {
Ok(second_number_as_proto) => return self.is_number_match_with_one_string(&second_number_as_proto, first_number),
Err(err) => {
if !matches!(err, ParseError::InvalidCountryCodeError) {
return Err(MatchError::InvalidNumber(err))
return Err(InvalidNumberError(err))
}
let first_number_as_proto = self.parse_helper(
first_number, i18n::RegionCode::get_unknown(),
@@ -2473,11 +2469,11 @@ impl PhoneNumberUtil {
}
}
fn is_number_match_with_one_string(
pub fn is_number_match_with_one_string(
&self,
first_number: &PhoneNumber,
second_number: &str
) -> std::result::Result<MatchType, MatchError> {
) -> 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()) {
@@ -2486,7 +2482,7 @@ impl PhoneNumberUtil {
)),
Err(err) => {
if !matches!(err, ParseError::InvalidCountryCodeError) {
return Err(MatchError::InvalidNumber(err));
return Err(InvalidNumberError(err));
}
}
}