@@ -0,0 +1,489 @@
1+-- | Utilities for international phone numbers
2+module Data.PhoneNumber.Util
3+ ( -- * Parsing
4+ parseNumber
5+ , ParseMode(..)
6+ , ErrorType(..)
7+ -- * Formatting
8+ , formatNumber
9+ , PhoneNumberFormat(..)
10+ -- * Analysis
11+ , matchNumbers
12+ , MatchType(..)
13+ , regionForNumber
14+ , nationalSignificantNumber
15+ , isValidNumber
16+ , numberType
17+ , PhoneNumberType(..)
18+ , possibleNumber
19+ , ValidationResult(..)
20+ , canBeInternationallyDialed
21+ , isGeographicalNumber
22+ , isGeographicalNumberType
23+ , isAlphaNumber
24+ -- * Library Support
25+ , supportedRegions
26+ , supportedGlobalNetworkCallingCodes
27+ , supportedCallingCodes
28+ , supportedTypesForRegion
29+ , supportedTypesForNonGeoEntity
30+ -- * 'Region'/'CountryCode' Queries
31+ , Region(..)
32+ , noRegion
33+ , CountryCode(..)
34+ , countryCodeForRegion
35+ , regionForCountryCode
36+ , regionsForCountryCode
37+ , isNANPACountry
38+ , countryMobileToken
39+ , nddPrefixForRegion
40+ -- * Miscellaneous
41+ , truncateTooLongNumber
42+ , convertAlphaNumber
43+ , normalizeNumber
44+ , Normalize(..)
45+ -- * Re-exports
46+ , PhoneNumber
47+ )
48+ where
49+
50+import Control.DeepSeq
51+import Data.ByteString (ByteString)
52+import Data.Coerce
53+import Data.Data
54+import Data.PhoneNumber.Number
55+import Data.PhoneNumber.Internal.Util hiding (ErrorType(..), PhoneNumberFormat(..))
56+import qualified Data.PhoneNumber.Internal.Util as I
57+import qualified Data.Set as S
58+import GHC.Generics
59+import GHC.Exts
60+import GHC.IO
61+
62+-- | Most of the time an ISO 3166-1 alpha-2 country code in upper case, except
63+-- in some cases the UN M.49 code @"001"@ (meaning the world) used to represent
64+-- non-geographical entities.
65+--
66+-- In some situations, the 'noRegion' value corresponds to a default or
67+-- unspecified region.
68+newtype Region = Region ByteString
69+ deriving newtype (Eq, Ord, Show, Read, IsString, NFData)
70+ deriving stock (Data, Generic)
71+
72+-- | A default or unspecified region, the user-assigned alpha-2 code @\"ZZ\"@
73+noRegion :: Region
74+noRegion = "ZZ"
75+
76+-- | All geographical regions the library has metadata for
77+supportedRegions :: S.Set Region
78+supportedRegions = S.fromList $ unsafeDupablePerformIO $ mask_ $
79+ coerce c_phone_number_util_get_supported_regions
80+
81+-- | All global network calling codes (country calling codes for
82+-- non-geographical entities) the library has metadata for
83+supportedGlobalNetworkCallingCodes :: S.Set CountryCode
84+supportedGlobalNetworkCallingCodes = S.fromList $ unsafeDupablePerformIO $ mask_ $
85+ map (CountryCode . fromIntegral) <$>
86+ c_phone_number_util_get_supported_global_network_calling_codes
87+
88+-- | All country calling codes the library has metadata for, covering both
89+-- non-geographical entities (global network calling codes) and those used for
90+-- geographical entities. This could be used to populate a drop-down box of
91+-- country calling codes for a phone-number widget, for instance.
92+supportedCallingCodes :: S.Set CountryCode
93+supportedCallingCodes = S.fromList $ unsafeDupablePerformIO $ mask_ $
94+ map (CountryCode . fromIntegral) <$>
95+ c_phone_number_util_get_supported_calling_codes
96+
97+-- | Returns the types for a given region which the library has metadata for.
98+-- Will not include 'FixedLineOrMobile' (if numbers for this non-geographical
99+-- entity could be classified as 'FixedLineOrMobile', both 'FixedLine' and
100+-- 'Mobile' would be present) and 'Unknown'.
101+--
102+-- No types will be returned for invalid or unknown region codes.
103+supportedTypesForRegion :: Region -> S.Set PhoneNumberType
104+supportedTypesForRegion (Region region) = S.fromList $ unsafeDupablePerformIO $ mask_ $
105+ c_phone_number_util_get_supported_types_for_region region
106+
107+-- | Returns the types for a country-code belonging to a non-geographical entity
108+-- which the library has metadata for. Will not include 'FixedLineOrMobile' (if
109+-- numbers for this non-geographical entity could be classified as
110+-- 'FixedLineOrMobile', both 'FixedLine' and 'Mobile' would be present) and
111+-- 'Unknown'.
112+--
113+-- No types will be returned for country calling codes that do not map to a
114+-- known non-geographical entity.
115+supportedTypesForNonGeoEntity :: CountryCode -> S.Set PhoneNumberType
116+supportedTypesForNonGeoEntity (CountryCode cc) = S.fromList $ unsafeDupablePerformIO $ mask_ $
117+ c_phone_number_util_get_supported_types_for_non_geo_entity $ fromIntegral cc
118+
119+-- | Returns true if the number is a valid vanity (alpha) number such as
120+-- @"800 MICROSOFT"@. A valid vanity number will start with at least 3 digits
121+-- and will have three or more alpha characters. This does not do
122+-- region-specific checks - to work out if this number is actually valid for a
123+-- region, you should use 'parseNumber' and 'possibleNumber'/'isValidNumber'.
124+isAlphaNumber :: ByteString -> Bool
125+isAlphaNumber bs = unsafeDupablePerformIO $
126+ c_phone_number_util_is_alpha_number bs
127+
128+-- | Converts all alpha characters in a number to their respective digits on
129+-- a keypad, but retains existing formatting
130+convertAlphaNumber :: ByteString -> ByteString
131+convertAlphaNumber bs = unsafeDupablePerformIO $ mask_ $
132+ c_phone_number_util_convert_alpha_characters_in_number bs
133+
134+-- | How 'normalizeNumber' should normalize a phone number
135+data Normalize
136+ = Digits -- ^ Convert wide-ascii and arabic-indic numerals to European
137+ -- numerals, and strip punctuation and alpha characters
138+ | Dialable -- ^ Strip all characters which are not diallable on a mobile phone
139+ -- keypad (including all non-ASCII digits)
140+ deriving stock (Eq, Ord, Show, Read, Data, Generic)
141+ deriving anyclass (NFData)
142+
143+-- | Normalizes a string of characters representing a phone number. See
144+-- 'Normalize'.
145+normalizeNumber :: Normalize -> ByteString -> ByteString
146+normalizeNumber Digits bs = unsafeDupablePerformIO $ mask_ $
147+ c_phone_number_util_normalize_digits_only bs
148+normalizeNumber Dialable bs = unsafeDupablePerformIO $ mask_ $
149+ c_phone_number_util_normalize_dialable_chars_only bs
150+
151+-- | Gets the National Significant Number (NSN) of a phone number. Note an NSN
152+-- doesn't contain a national prefix or any formatting.
153+nationalSignificantNumber :: PhoneNumber -> ByteString
154+nationalSignificantNumber pn = unsafeDupablePerformIO $ mask_ $
155+ c_phone_number_util_get_national_significant_number pn
156+
157+-- | Returns the mobile token for the provided country calling code if it has
158+-- one, otherwise returns an empty string. A mobile token is a number inserted
159+-- before the area code when dialing a mobile number from that country from
160+-- abroad.
161+countryMobileToken :: CountryCode -> ByteString
162+countryMobileToken (CountryCode cc) = unsafeDupablePerformIO $ mask_ $
163+ c_phone_number_util_get_country_mobile_token $ fromIntegral cc
164+
165+-- | How 'formatNumber' should format a phone number
166+data PhoneNumberFormat
167+ = International -- ^ Consistent with the definition in ITU-T Recommendation
168+ -- E.123. However we follow local conventions such as using @\'-\'@
169+ -- instead of whitespace as separators. E.g. @"+41 44 668 1800"@.
170+ | National -- ^ Consistent with E.123, and also following local conventions
171+ -- for separators. E.g. @"044 668 1800"@.
172+ | E164 -- ^ Same as 'International' but with no formatting, e.g.
173+ -- @"+41446681800"@. See https://en.wikipedia.org/wiki/E.164.
174+ | RFC3966 -- ^ Same as 'International' but with all separating symbols
175+ -- replaced with a hyphen, and with any phone number extension appended
176+ -- with @";ext="@. It will also have a prefix of @"tel:"@ added, e.g.
177+ -- @"tel:+41-44-668-1800"@.
178+ | NationalWithCarrierCodeOverride ByteString -- ^ Same as 'National' but
179+ -- for dialing using the specified domestic carrier code.
180+ | NationalWithCarrierCodeFallback ByteString -- ^ Same as 'National' but
181+ -- use the phone number's 'preferredDomesticCarrierCode' (which is only
182+ -- set if parsed with 'KeepRawInput'). If a preferred carrier code is
183+ -- absent, the provided string is used as fallback.
184+ | ForMobileDialing -- ^ Format in such a way that it can be dialed from a
185+ -- mobile phone in a specific region. If the number cannot be reached from
186+ -- the region (e.g. some countries block toll-free numbers from being
187+ -- called outside of the country), will format to an empty string.
188+ { from :: Region
189+ , withFormatting :: Bool -- ^ Whether to strip formatting as in 'E164'.
190+ }
191+ | OutOfCountry -- ^ Format for out-of-country dialing purposes. This takes
192+ -- care of the case of calling inside of NANPA and between Russia and
193+ -- Kazakhstan (who share the same country calling code). In those cases,
194+ -- no international prefix is used. For regions which have multiple
195+ -- international prefixes, formats as 'International'.
196+ { from :: Region
197+ , keepAlphaChars :: Bool -- ^ Attempt to keep alpha chars and grouping
198+ -- information, if 'rawInput' is available. Setting this to 'True' comes
199+ -- with a number of caveats:
200+ --
201+ -- 1. This will not produce good results if the country calling code is
202+ -- both present in 'rawInput' /and/ is the start of the national number.
203+ -- This is not a problem in the regions which typically use alpha numbers.
204+ --
205+ -- 2. This will also not produce good results if 'rawInput' has any
206+ -- grouping information within the first three digits of the national
207+ -- number, and if the function needs to strip preceding digits/words in
208+ -- 'rawInput' before these digits. Normally people group the first three
209+ -- digits together so this is not a huge problem.
210+ }
211+ | Original -- ^ Use 'rawInput' verbatim if present, otherwise infer
212+ -- 'National', 'International', or 'OutOfCountry' based on
213+ -- 'countryCodeSource'.
214+ { from :: Region
215+ }
216+
217+-- | Formats a phone number in the specified 'PhoneNumberFormat' using default
218+-- rules. Note that this does not promise to produce a phone number that the
219+-- user can dial from where they are - as we do not currently support a more
220+-- abbreviated format, such as for users in the same area who could potentially
221+-- dial the number without area code.
222+formatNumber :: PhoneNumberFormat -> PhoneNumber -> ByteString
223+formatNumber fmt pn = case fmt of
224+ E164 -> unsafeDupablePerformIO $ mask_ $
225+ c_phone_number_util_format pn I.E164
226+ International -> unsafeDupablePerformIO $ mask_ $
227+ c_phone_number_util_format pn I.International
228+ National -> unsafeDupablePerformIO $ mask_ $
229+ c_phone_number_util_format pn I.National
230+ RFC3966 -> unsafeDupablePerformIO $ mask_ $
231+ c_phone_number_util_format pn I.Rfc3966
232+ NationalWithCarrierCodeOverride cc -> unsafeDupablePerformIO $ mask_ $
233+ c_phone_number_util_format_national_number_with_carrier_code pn cc
234+ NationalWithCarrierCodeFallback cc -> unsafeDupablePerformIO $ mask_ $
235+ c_phone_number_util_format_national_number_with_preferred_carrier_code pn cc
236+ ForMobileDialing (Region region) keepFmt -> unsafeDupablePerformIO $ mask_ $
237+ c_phone_number_util_format_number_for_mobile_dialing pn region keepFmt
238+ Original (Region region) -> unsafeDupablePerformIO $ mask_ $
239+ c_phone_number_util_format_in_original_format pn region
240+ OutOfCountry (Region region) False -> unsafeDupablePerformIO $ mask_ $
241+ c_phone_number_util_format_out_of_country_calling_number pn region
242+ OutOfCountry (Region region) True -> unsafeDupablePerformIO $ mask_ $
243+ c_phone_number_util_format_out_of_country_keeping_alpha_chars pn region
244+
245+-- | Attempts to extract a valid number from a phone number that is too long to
246+-- be valid. Returns 'Nothing' if no valid number could be extracted.
247+truncateTooLongNumber :: PhoneNumber -> Maybe PhoneNumber
248+truncateTooLongNumber pn = unsafeDupablePerformIO $ mask_ $
249+ c_phone_number_util_truncate_too_long_number pn
250+
251+-- | Gets the phone number type. Returns 'Unknown' if invalid.
252+numberType :: PhoneNumber -> PhoneNumberType
253+numberType pn = unsafeDupablePerformIO $
254+ c_phone_number_util_get_number_type pn
255+
256+-- | Tests whether a phone number is valid for a certain region (if unspecified,
257+-- the region the number is from). Note this doesn't verify the number is
258+-- actually in use, which is impossible to tell by just looking at a number
259+-- itself.
260+--
261+-- If the country calling code is not the same as the country calling code for
262+-- the provided region, this immediately returns 'False'. After this, the
263+-- specific number pattern rules for the region are examined.
264+--
265+-- Specifying a region may be useful for determining for example whether a
266+-- particular number is valid for Canada, rather than just a valid NANPA number.
267+-- On the other hand this may lead to undesirable results, for example numbers
268+-- from British Crown dependencies such as the Isle of Man are considered
269+-- invalid for the region @\"GB\"@ (United Kingdom), since it has its own region
270+-- code, @\"IM\"@.
271+--
272+-- Note that it only verifies whether the parsed, canonicalised number is valid:
273+-- not whether a particular series of digits entered by the user is dialable
274+-- from the region provided when parsing. For example, the number
275+-- @+41 (0) 78 927 2696@ can be parsed into a number with country code @"41"@
276+-- and National Significant Number @"789272696"@. This is valid, while the
277+-- original string is not dialable.
278+isValidNumber :: Maybe Region -> PhoneNumber -> Bool
279+isValidNumber Nothing pn = unsafeDupablePerformIO $
280+ c_phone_number_util_is_valid_number pn
281+isValidNumber (Just (Region region)) pn = unsafeDupablePerformIO $
282+ c_phone_number_util_is_valid_number_for_region pn region
283+
284+-- | Returns the region where a phone number is from. This could be used for
285+-- geocoding at the region level. Only guarantees correct results for valid,
286+-- full numbers (not short-codes, or invalid numbers).
287+regionForNumber :: PhoneNumber -> Region
288+regionForNumber pn = unsafeDupablePerformIO $ mask_ $
289+ coerce $ c_phone_number_util_get_region_code_for_number pn
290+
291+-- | Returns the country calling code for a specific region. For example, this
292+-- would be @1@ for the United States, and @64@ for New Zealand.
293+countryCodeForRegion :: Region -> CountryCode
294+countryCodeForRegion (Region region) = unsafeDupablePerformIO $
295+ CountryCode . fromIntegral <$>
296+ c_phone_number_util_get_country_code_for_region region
297+
298+-- | Returns the region code that matches the specific country code. Note that
299+-- it is possible that several regions share the same country calling code
300+-- (e.g. US and Canada), and in that case, only one of the regions (normally the
301+-- one with the largest population) is returned. If the country calling code
302+-- entered is valid but doesn't match a specific region (such as in the case of
303+-- non-geographical calling codes like @800@) the @'Region' "001"@ will be
304+-- returned.
305+regionForCountryCode :: CountryCode -> Region
306+regionForCountryCode (CountryCode cc) = unsafeDupablePerformIO $ mask_ $
307+ coerce $ c_phone_number_util_get_region_code_for_country_code $ fromIntegral cc
308+
309+-- | Returns a list of the region codes that match the specific country calling
310+-- code. For non-geographical country calling codes, the region code @"001"@ is
311+-- returned. Also, in the case of no region code being found, the list is empty.
312+regionsForCountryCode :: CountryCode -> [Region]
313+regionsForCountryCode (CountryCode cc) = unsafeDupablePerformIO $ mask_ $
314+ coerce $ c_phone_number_util_get_region_codes_for_country_calling_code $ fromIntegral cc
315+
316+-- | Checks if this is a region under the North American Numbering Plan
317+-- Administration (NANPA).
318+isNANPACountry :: Region -> Bool
319+isNANPACountry (Region region) = unsafeDupablePerformIO $
320+ c_phone_number_util_is_nanpa_country region
321+
322+-- | Returns the National Direct Dialling prefix (NDD prefix) for a specific
323+-- region. For example, this would be @"1"@ for the United States, and @"0"@ for
324+-- New Zealand. Note that this may contain symbols like @\'~\'@ (which indicates
325+-- a wait for a dialing tone). Returns an empty string if no national prefix is
326+-- present.
327+nddPrefixForRegion
328+ :: Bool -- ^ Whether to strip non-digits like @\'~\'@
329+ -> Region
330+ -> ByteString
331+nddPrefixForRegion strip (Region region) = unsafeDupablePerformIO $ mask_ $
332+ c_phone_number_util_get_ndd_prefix_for_region region strip
333+
334+-- | Check whether a phone number is a possible number of a particular type.
335+-- Pass the type 'Unknown' to check whether a number is possible at all.
336+--
337+-- For more specific types that don't exist in a particular region, this will
338+-- return a result that isn't so useful; it is recommended that you use
339+-- 'supportedTypesForRegion' or 'supportedTypesForNonGeoEntity' respectively
340+-- before calling this function to determine you should pass a more specific
341+-- type instead of 'Unknown'.
342+--
343+-- This function provides a more lenient check than 'isValidNumber' in the
344+-- following sense:
345+--
346+-- 1. It only checks the length of phone numbers. In particular, it doesn't
347+-- check starting digits of the number.
348+--
349+-- 2. If 'Unknown' is provided, it doesn't attempt to figure out the type of the
350+-- number, but uses general rules which apply to all types of phone numbers in a
351+-- region. Therefore, it is much faster than 'isValidNumber'.
352+--
353+-- 3. For some numbers (particularly fixed-line), many regions have the concept
354+-- of area code, which together with subscriber number constitute the National
355+-- Significant Number. It is sometimes okay to dial only the subscriber number
356+-- when dialing in the same area. This function will return IsPossibleLocalOnly
357+-- if the subscriber-number-only version is passed in. On the other hand,
358+-- because 'isValidNumber' validates using information on both starting digits
359+-- (for fixed line numbers, that would most likely be area codes) and length
360+-- (obviously includes the length of area codes for fixed line numbers), it will
361+-- return 'False' for the subscriber-number-only version.
362+possibleNumber :: PhoneNumberType -> PhoneNumber -> ValidationResult
363+possibleNumber ntype pn = unsafeDupablePerformIO $
364+ c_phone_number_util_is_possible_number_for_type_with_reason pn ntype
365+
366+-- | Returns 'True' if the number can be dialed from outside the region, or
367+-- unknown. If the number can only be dialled from within the region, returns
368+-- 'False'. Does not check the number is a valid number. Note that, at the
369+-- moment, this method does not handle short numbers (which are currently all
370+-- presumed to not be diallable from outside their country).
371+canBeInternationallyDialed :: PhoneNumber -> Bool
372+canBeInternationallyDialed pn = unsafeDupablePerformIO $
373+ c_phone_number_util_can_be_internationally_dialed pn
374+
375+-- | Tests whether a phone number has a geographical association. It checks if
376+-- the number is associated with a certain region in the country to which it
377+-- belongs. Note that this doesn't verify if the number is actually in use.
378+isGeographicalNumber :: PhoneNumber -> Bool
379+isGeographicalNumber pn = unsafeDupablePerformIO $
380+ c_phone_number_util_is_number_geographical_1 pn
381+
382+-- | A less expensive version of 'isGeographicalNumber' if we already know the
383+-- 'PhoneNumberType'
384+isGeographicalNumberType :: PhoneNumberType -> CountryCode -> Bool
385+isGeographicalNumberType ntype (CountryCode cc) = unsafeDupablePerformIO $
386+ c_phone_number_util_is_number_geographical_2 ntype $ fromIntegral cc
387+
388+-- | Phone number parsing error
389+data ErrorType
390+ = InvalidCountryCodeError -- ^ The number did not contain a country code and
391+ -- there was no default region supplied, or the number contained an invalid
392+ -- country code
393+ | NotANumber -- ^ Does not look like a phone number
394+ | TooShortAfterIdd -- ^ Input starts with an International Direct Dialing
395+ -- prefix, but ends too shortly thereafter
396+ | TooShortNsn -- ^ The National Significant Number is too short
397+ | TooLongNsn -- ^ The National Significant Number is too long
398+ deriving stock (Eq, Ord, Show, Read, Data, Generic)
399+ deriving anyclass (NFData)
400+
401+-- | How much information to retain when parsing
402+data ParseMode
403+ = Canonicalize -- ^ Canonicalize the phone number such that different
404+ -- representations can be easily compared, no matter what form it was
405+ -- originally entered in (e.g. national, international)
406+ | KeepRawInput -- ^ Record context about the number being parsed, such as
407+ -- 'rawInput', 'countryCodeSource', and 'preferredDomesticCarrierCode'
408+ deriving stock (Eq, Ord, Show, Read, Data, Generic)
409+ deriving anyclass (NFData)
410+
411+-- | Parse a phone number.
412+--
413+-- The function is quite lenient and looks for a number in the input
414+-- 'ByteString' and does not check whether the string is definitely only a phone
415+-- number. To do this, it ignores punctuation and white-space, as well as any
416+-- text before the number (e.g. a leading @"Tel: "@) and trims the non-number
417+-- bits. It will accept a number in any format (E164, national, international
418+-- etc.), assuming it can be interpreted with the default t'Region' supplied. It
419+-- also attempts to convert any alpha characters into digits if it thinks this
420+-- is a vanity number of the type @"1800 MICROSOFT"@.
421+--
422+-- The input can contain formatting such as @+@, @(@ and @-@, as well as a phone
423+-- number extension. It can also be provided in RFC3966 format.
424+--
425+-- Note that validation of whether the number is actually a valid number for a
426+-- particular region is not performed. This can be done separately with
427+-- 'isValidNumber'.
428+--
429+-- Returns an error if the string is not considered to be a viable phone number
430+-- (e.g. too few or too many digits) or if 'noRegion' was supplied and the
431+-- number is not in international format (does not start with @\'+\'@).
432+parseNumber
433+ :: ParseMode
434+ -> Region -- ^ Default region, the country that we are expecting the number to
435+ -- be dialed from, which affects national and international dialing
436+ -- prefixes. This is only used if the number being parsed is not written in
437+ -- international format. In such cases the 'countryCode' of the number would
438+ -- be that of the default region supplied. If the number is guaranteed to
439+ -- start with a @\'+\'@ followed by the country calling code, then
440+ -- 'noRegion' can be supplied.
441+ -> ByteString -- ^ Input.
442+ -> Either ErrorType PhoneNumber
443+parseNumber mode (Region region) number = case err of
444+ I.NoParsingError -> Right pn
445+ I.InvalidCountryCodeError -> Left InvalidCountryCodeError
446+ I.NotANumber -> Left NotANumber
447+ I.TooShortAfterIdd -> Left TooShortAfterIdd
448+ I.TooShortNsn -> Left TooShortNsn
449+ I.TooLongNsn -> Left TooLongNsn
450+ where
451+ (err, pn) = case mode of
452+ Canonicalize -> unsafeDupablePerformIO $ mask_ $
453+ c_phone_number_util_parse number region
454+ KeepRawInput -> unsafeDupablePerformIO $ mask_ $
455+ c_phone_number_util_parse_and_keep_raw_input number region
456+
457+-- | Compares two numbers for equality. A number can be provided as a string, in
458+-- which case it is parsed without assuming its region.
459+--
460+-- Returns 'ExactMatch' if the country calling code, National Significant
461+-- Number (NSN), presence of a leading zero for Italian numbers and any
462+-- extension present are the same.
463+--
464+-- Returns 'NsnMatch' if either or both has no country calling code specified,
465+-- and the NSNs and extensions are the same.
466+--
467+-- Returns 'ShortNsnMatch' if either or both has no country calling code
468+-- specified, or the country calling code specified is the same, and one NSN
469+-- could be a shorter version of the other number. This includes the case where
470+-- one has an extension specified, and the other does not.
471+--
472+-- Returns 'InvalidNumber' if a number that was provided as a string could not
473+-- be parsed.
474+--
475+-- Returns 'NoMatch' otherwise.
476+--
477+-- For example, the numbers @1 345 657 1234@ and @657 1234@ are a
478+-- 'ShortNsnMatch'. The numbers @1 345 657 1234@ and @345 657@ are a 'NoMatch'.
479+-- Note that none of these numbers can be parsed by 'parseNumber' without
480+-- assuming a region.
481+matchNumbers :: Either ByteString PhoneNumber -> Either ByteString PhoneNumber -> MatchType
482+matchNumbers (Left pn1) (Left pn2) = unsafeDupablePerformIO $
483+ c_phone_number_util_is_number_match_with_two_strings pn1 pn2
484+matchNumbers (Left pn1) (Right pn2) = unsafeDupablePerformIO $
485+ c_phone_number_util_is_number_match_with_one_string pn2 pn1
486+matchNumbers (Right pn1) (Left pn2) = unsafeDupablePerformIO $
487+ c_phone_number_util_is_number_match_with_one_string pn1 pn2
488+matchNumbers (Right pn1) (Right pn2) = unsafeDupablePerformIO $
489+ c_phone_number_util_is_number_match pn1 pn2