@@ -29,7 +29,7 @@ module Data.PhoneNumber.Util
29 , supportedTypesForNonGeoEntity
29 , supportedTypesForNonGeoEntity
30 -- * 'Region'/'CountryCode' Queries
30 -- * 'Region'/'CountryCode' Queries
31 , Region(..)
31 , Region(..)
32− , noRegion
32+ , NonGeoRegion(..)
33 , CountryCode(..)
33 , CountryCode(..)
34 , countryCodeForRegion
34 , countryCodeForRegion
35 , regionForCountryCode
35 , regionForCountryCode
@@ -59,19 +59,31 @@ import GHC.Generics
59import GHC.Exts
59import GHC.Exts
60import GHC.IO
60import GHC.IO
62−-- | Most of the time an ISO 3166-1 alpha-2 country code in upper case, except
62+-- | An ISO 3166-1 alpha-2 country code in upper case.
63−-- in some cases the UN M.49 code @"001"@ (meaning the world) used to represent
64−-- non-geographical entities.
66−-- In some situations, the 'noRegion' value corresponds to a default or
67−-- unspecified region.
68newtype Region = Region ByteString
63newtype Region = Region ByteString
69 deriving newtype (Eq, Ord, Show, Read, IsString, NFData)
64 deriving newtype (Eq, Ord, Show, Read, IsString, NFData)
70 deriving stock (Data, Generic)
65 deriving stock (Data, Generic)
72−-- | A default or unspecified region, the user-assigned alpha-2 code @\"ZZ\"@
67+-- | A "region" corresponding to non-geographical entities. The library
73−noRegion :: Region
68+-- internally uses the UN M.49 code @"001"@ (meaning the world) for this.
74−noRegion = "ZZ"
69+data NonGeoRegion = Region001
70+ deriving stock (Eq, Ord, Show, Read, Data, Generic)
71+ deriving anyclass (NFData)
73+filter001 :: ByteString -> Either NonGeoRegion Region
75+ | region == "001" = Left Region001
76+ | otherwise = Right $ Region region
78+filter001ZZ :: ByteString -> Maybe (Either NonGeoRegion Region)
80+ | region == "ZZ" = Nothing
81+ | region == "001" = Just $ Left Region001
82+ | otherwise = Just $ Right $ Region region
84+filter0 :: Int -> Maybe CountryCode
86+filter0 cc = Just $ CountryCode cc
76-- | All geographical regions the library has metadata for
88-- | All geographical regions the library has metadata for
77supportedRegions :: S.Set Region
89supportedRegions :: S.Set Region
@@ -81,8 +93,8 @@ supportedRegions = S.fromList $ unsafeDupablePerformIO $ mask_ $
81-- | All global network calling codes (country calling codes for
93-- | All global network calling codes (country calling codes for
82-- non-geographical entities) the library has metadata for
94-- non-geographical entities) the library has metadata for
83supportedGlobalNetworkCallingCodes :: S.Set CountryCode
95supportedGlobalNetworkCallingCodes :: S.Set CountryCode
84−supportedGlobalNetworkCallingCodes = S.fromList $ unsafeDupablePerformIO $ mask_ $
96+supportedGlobalNetworkCallingCodes = S.fromList $ map (CountryCode . fromIntegral) $
85− map (CountryCode . fromIntegral) <$>
97+ unsafeDupablePerformIO $ mask_ $
86 c_phone_number_util_get_supported_global_network_calling_codes
98 c_phone_number_util_get_supported_global_network_calling_codes
88-- | All country calling codes the library has metadata for, covering both
100-- | All country calling codes the library has metadata for, covering both
@@ -90,8 +102,8 @@ supportedGlobalNetworkCallingCodes = S.fromList $ unsafeDupablePerformIO $ mask_
90-- geographical entities. This could be used to populate a drop-down box of
102-- geographical entities. This could be used to populate a drop-down box of
91-- country calling codes for a phone-number widget, for instance.
103-- country calling codes for a phone-number widget, for instance.
92supportedCallingCodes :: S.Set CountryCode
104supportedCallingCodes :: S.Set CountryCode
93−supportedCallingCodes = S.fromList $ unsafeDupablePerformIO $ mask_ $
94− map (CountryCode . fromIntegral) <$>
105+supportedCallingCodes = S.fromList $ map (CountryCode . fromIntegral) $
106+ unsafeDupablePerformIO $ mask_ $
95 c_phone_number_util_get_supported_calling_codes
107 c_phone_number_util_get_supported_calling_codes
97-- | Returns the types for a given region which the library has metadata for.
109-- | Returns the types for a given region which the library has metadata for.
@@ -101,8 +113,9 @@ supportedCallingCodes = S.fromList $ unsafeDupablePerformIO $ mask_ $
102-- No types will be returned for invalid or unknown region codes.
114-- No types will be returned for invalid or unknown region codes.
103supportedTypesForRegion :: Region -> S.Set PhoneNumberType
115supportedTypesForRegion :: Region -> S.Set PhoneNumberType
104−supportedTypesForRegion (Region region) = S.fromList $ unsafeDupablePerformIO $ mask_ $
116+supportedTypesForRegion (Region region) = S.fromList $
117+ unsafeDupablePerformIO $ mask_ $
105− c_phone_number_util_get_supported_types_for_region region
118+ c_phone_number_util_get_supported_types_for_region region
107-- | Returns the types for a country-code belonging to a non-geographical entity
120-- | 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
121-- which the library has metadata for. Will not include 'FixedLineOrMobile' (if
@@ -113,8 +126,9 @@ supportedTypesForRegion (Region region) = S.fromList $ unsafeDupablePerformIO $
113-- No types will be returned for country calling codes that do not map to a
126-- No types will be returned for country calling codes that do not map to a
114-- known non-geographical entity.
127-- known non-geographical entity.
115supportedTypesForNonGeoEntity :: CountryCode -> S.Set PhoneNumberType
128supportedTypesForNonGeoEntity :: CountryCode -> S.Set PhoneNumberType
116−supportedTypesForNonGeoEntity (CountryCode cc) = S.fromList $ unsafeDupablePerformIO $ mask_ $
129+supportedTypesForNonGeoEntity (CountryCode cc) = S.fromList $
130+ unsafeDupablePerformIO $ mask_ $
117− c_phone_number_util_get_supported_types_for_non_geo_entity $ fromIntegral cc
131+ c_phone_number_util_get_supported_types_for_non_geo_entity $ fromIntegral cc
119-- | Returns true if the number is a valid vanity (alpha) number such as
133-- | 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
134-- @"800 MICROSOFT"@. A valid vanity number will start with at least 3 digits
@@ -275,24 +289,27 @@ numberType pn = unsafeDupablePerformIO $
275-- @+41 (0) 78 927 2696@ can be parsed into a number with country code @"41"@
289-- @+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
290-- and National Significant Number @"789272696"@. This is valid, while the
277-- original string is not dialable.
291-- original string is not dialable.
278−isValidNumber :: Maybe Region -> PhoneNumber -> Bool
292+isValidNumber :: Maybe (Either NonGeoRegion Region) -> PhoneNumber -> Bool
279isValidNumber Nothing pn = unsafeDupablePerformIO $
293isValidNumber Nothing pn = unsafeDupablePerformIO $
280 c_phone_number_util_is_valid_number pn
294 c_phone_number_util_is_valid_number pn
295+isValidNumber (Just (Left Region001)) pn = unsafeDupablePerformIO $
296+ c_phone_number_util_is_valid_number_for_region pn "001"
281−isValidNumber (Just (Region region)) pn = unsafeDupablePerformIO $
297+isValidNumber (Just (Right (Region region))) pn = unsafeDupablePerformIO $
282 c_phone_number_util_is_valid_number_for_region pn region
298 c_phone_number_util_is_valid_number_for_region pn region
284-- | Returns the region where a phone number is from. This could be used for
300-- | 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,
301-- geocoding at the region level. Only guarantees correct results for valid,
286-- full numbers (not short-codes, or invalid numbers).
302-- full numbers (not short-codes, or invalid numbers).
287−regionForNumber :: PhoneNumber -> Region
303+regionForNumber :: PhoneNumber -> Maybe (Either NonGeoRegion Region)
304+regionForNumber pn = filter001ZZ $
288−regionForNumber pn = unsafeDupablePerformIO $ mask_ $
305+ unsafeDupablePerformIO $ mask_ $
289− coerce $ c_phone_number_util_get_region_code_for_number pn
306+ c_phone_number_util_get_region_code_for_number pn
291-- | Returns the country calling code for a specific region. For example, this
308-- | 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.
309-- would be @1@ for the United States, and @64@ for New Zealand.
293−countryCodeForRegion :: Region -> CountryCode
310+countryCodeForRegion :: Region -> Maybe CountryCode
294−countryCodeForRegion (Region region) = unsafeDupablePerformIO $
311+countryCodeForRegion (Region region) = filter0 $ fromIntegral $
295− CountryCode . fromIntegral <$>
312+ unsafeDupablePerformIO $
296 c_phone_number_util_get_country_code_for_region region
313 c_phone_number_util_get_country_code_for_region region
298-- | Returns the region code that matches the specific country code. Note that
315-- | Returns the region code that matches the specific country code. Note that
@@ -300,18 +317,19 @@ countryCodeForRegion (Region region) = unsafeDupablePerformIO $
300-- (e.g. US and Canada), and in that case, only one of the regions (normally the
317-- (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
318-- 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
319-- 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
320+-- non-geographical calling codes like @800@) @'Region001'@ will be returned.
305−regionForCountryCode :: CountryCode -> Region
321+regionForCountryCode :: CountryCode -> Maybe (Either NonGeoRegion Region)
306−regionForCountryCode (CountryCode cc) = unsafeDupablePerformIO $ mask_ $
322+regionForCountryCode (CountryCode cc) = filter001ZZ $
323+ unsafeDupablePerformIO $ mask_ $
307− coerce $ c_phone_number_util_get_region_code_for_country_code $ fromIntegral cc
324+ c_phone_number_util_get_region_code_for_country_code $ fromIntegral cc
309-- | Returns a list of the region codes that match the specific country calling
326-- | 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
327+-- code. For non-geographical country calling codes, 'Region001' is returned.
311−-- returned. Also, in the case of no region code being found, the list is empty.
328+-- Also, in the case of no region code being found, the list is empty.
312−regionsForCountryCode :: CountryCode -> [Region]
329+regionsForCountryCode :: CountryCode -> [Either NonGeoRegion Region]
313−regionsForCountryCode (CountryCode cc) = unsafeDupablePerformIO $ mask_ $
330+regionsForCountryCode (CountryCode cc) = map filter001 $
331+ unsafeDupablePerformIO $ mask_ $
314− coerce $ c_phone_number_util_get_region_codes_for_country_calling_code $ fromIntegral cc
332+ c_phone_number_util_get_region_codes_for_country_calling_code $ fromIntegral cc
316-- | Checks if this is a region under the North American Numbering Plan
334-- | Checks if this is a region under the North American Numbering Plan
317-- Administration (NANPA).
335-- Administration (NANPA).
@@ -431,16 +449,16 @@ data ParseMode
431-- number is not in international format (does not start with @\'+\'@).
449-- number is not in international format (does not start with @\'+\'@).
432parseNumber
450parseNumber
433 :: ParseMode
451 :: ParseMode
434− -> Region -- ^ Default region, the country that we are expecting the number to
452+ -> Maybe Region -- ^ Default region, the country that we are expecting the
435− -- be dialed from, which affects national and international dialing
453+ -- number to be dialed from, which affects national and international
436− -- prefixes. This is only used if the number being parsed is not written in
454+ -- dialing prefixes. This is only used if the number being parsed is not
437− -- international format. In such cases the 'countryCode' of the number would
455+ -- written in international format. In such cases the 'countryCode' of the
438− -- be that of the default region supplied. If the number is guaranteed to
456+ -- number would be that of the default region supplied. If the number is
439− -- start with a @\'+\'@ followed by the country calling code, then
457+ -- guaranteed to start with a @\'+\'@ followed by the country calling code,
440− -- 'noRegion' can be supplied.
458+ -- then this can be omitted.
441 -> ByteString -- ^ Input.
459 -> ByteString -- ^ Input.
442 -> Either ErrorType PhoneNumber
460 -> Either ErrorType PhoneNumber
443−parseNumber mode (Region region) number = case err of
461+parseNumber mode mRegion number = case err of
444 I.NoParsingError -> Right pn
462 I.NoParsingError -> Right pn
445 I.InvalidCountryCodeError -> Left InvalidCountryCodeError
463 I.InvalidCountryCodeError -> Left InvalidCountryCodeError
446 I.NotANumber -> Left NotANumber
464 I.NotANumber -> Left NotANumber
@@ -448,6 +466,9 @@ parseNumber mode (Region region) number = case err of
448 I.TooShortNsn -> Left TooShortNsn
466 I.TooShortNsn -> Left TooShortNsn
449 I.TooLongNsn -> Left TooLongNsn
467 I.TooLongNsn -> Left TooLongNsn
469+ region = case mRegion of
471+ Just (Region reg) -> reg
451 (err, pn) = case mode of
472 (err, pn) = case mode of
452 Canonicalize -> unsafeDupablePerformIO $ mask_ $
473 Canonicalize -> unsafeDupablePerformIO $ mask_ $
453 c_phone_number_util_parse number region
474 c_phone_number_util_parse number region