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