git.iko.soy/typeable/libphonenumber
on main help sign in
Handle ZZ/001 internally to the library
commit831cd18583a8e551376b549b2018123d3f707880 authormniip <mniip@mniip.com> dateFri 17 Mar 2023, 18:37 (4 years ago) parent4cb8c2f
1 file changed+65−44
src/Data/PhoneNumber/Util.hs+65−44
src/Data/PhoneNumber/Util.hs+65−44
@@ -29,7 +29,7 @@ module Data.PhoneNumber.Util
2929 , supportedTypesForNonGeoEntity
3030 -- * 'Region'/'CountryCode' Queries
3131 , Region(..)
32− , noRegion
32+ , NonGeoRegion(..)
3333 , CountryCode(..)
3434 , countryCodeForRegion
3535 , regionForCountryCode
@@ -59,19 +59,31 @@ import GHC.Generics
5959import GHC.Exts
6060import GHC.IO
6161
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.
62+-- | An ISO 3166-1 alpha-2 country code in upper case.
6863newtype Region = Region ByteString
6964 deriving newtype (Eq, Ord, Show, Read, IsString, NFData)
7065 deriving stock (Data, Generic)
7166
72−-- | A default or unspecified region, the user-assigned alpha-2 code @\"ZZ\"@
73−noRegion :: Region
74−noRegion = "ZZ"
67+-- | A "region" corresponding to non-geographical entities. The library
68+-- internally uses the UN M.49 code @"001"@ (meaning the world) for this.
69+data NonGeoRegion = Region001
70+ deriving stock (Eq, Ord, Show, Read, Data, Generic)
71+ deriving anyclass (NFData)
72+
73+filter001 :: ByteString -> Either NonGeoRegion Region
74+filter001 region
75+ | region == "001" = Left Region001
76+ | otherwise = Right $ Region region
77+
78+filter001ZZ :: ByteString -> Maybe (Either NonGeoRegion Region)
79+filter001ZZ region
80+ | region == "ZZ" = Nothing
81+ | region == "001" = Just $ Left Region001
82+ | otherwise = Just $ Right $ Region region
83+
84+filter0 :: Int -> Maybe CountryCode
85+filter0 0 = Nothing
86+filter0 cc = Just $ CountryCode cc
7587
7688-- | All geographical regions the library has metadata for
7789supportedRegions :: S.Set Region
@@ -81,8 +93,8 @@ supportedRegions = S.fromList $ unsafeDupablePerformIO $ mask_ $
8193-- | All global network calling codes (country calling codes for
8294-- non-geographical entities) the library has metadata for
8395supportedGlobalNetworkCallingCodes :: S.Set CountryCode
84−supportedGlobalNetworkCallingCodes = S.fromList $ unsafeDupablePerformIO $ mask_ $
85− map (CountryCode . fromIntegral) <$>
96+supportedGlobalNetworkCallingCodes = S.fromList $ map (CountryCode . fromIntegral) $
97+ unsafeDupablePerformIO $ mask_ $
8698 c_phone_number_util_get_supported_global_network_calling_codes
8799
88100-- | All country calling codes the library has metadata for, covering both
@@ -90,8 +102,8 @@ supportedGlobalNetworkCallingCodes = S.fromList $ unsafeDupablePerformIO $ mask_
90102-- geographical entities. This could be used to populate a drop-down box of
91103-- country calling codes for a phone-number widget, for instance.
92104supportedCallingCodes :: S.Set CountryCode
93−supportedCallingCodes = S.fromList $ unsafeDupablePerformIO $ mask_ $
94− map (CountryCode . fromIntegral) <$>
105+supportedCallingCodes = S.fromList $ map (CountryCode . fromIntegral) $
106+ unsafeDupablePerformIO $ mask_ $
95107 c_phone_number_util_get_supported_calling_codes
96108
97109-- | Returns the types for a given region which the library has metadata for.
@@ -101,8 +113,9 @@ supportedCallingCodes = S.fromList $ unsafeDupablePerformIO $ mask_ $
101113--
102114-- No types will be returned for invalid or unknown region codes.
103115supportedTypesForRegion :: Region -> S.Set PhoneNumberType
104−supportedTypesForRegion (Region region) = S.fromList $ unsafeDupablePerformIO $ mask_ $
105− c_phone_number_util_get_supported_types_for_region region
116+supportedTypesForRegion (Region region) = S.fromList $
117+ unsafeDupablePerformIO $ mask_ $
118+ c_phone_number_util_get_supported_types_for_region region
106119
107120-- | Returns the types for a country-code belonging to a non-geographical entity
108121-- which the library has metadata for. Will not include 'FixedLineOrMobile' (if
@@ -113,8 +126,9 @@ supportedTypesForRegion (Region region) = S.fromList $ unsafeDupablePerformIO $
113126-- No types will be returned for country calling codes that do not map to a
114127-- known non-geographical entity.
115128supportedTypesForNonGeoEntity :: 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
129+supportedTypesForNonGeoEntity (CountryCode cc) = S.fromList $
130+ unsafeDupablePerformIO $ mask_ $
131+ c_phone_number_util_get_supported_types_for_non_geo_entity $ fromIntegral cc
118132
119133-- | Returns true if the number is a valid vanity (alpha) number such as
120134-- @"800 MICROSOFT"@. A valid vanity number will start with at least 3 digits
@@ -275,24 +289,27 @@ numberType pn = unsafeDupablePerformIO $
275289-- @+41 (0) 78 927 2696@ can be parsed into a number with country code @"41"@
276290-- and National Significant Number @"789272696"@. This is valid, while the
277291-- original string is not dialable.
278−isValidNumber :: Maybe Region -> PhoneNumber -> Bool
292+isValidNumber :: Maybe (Either NonGeoRegion Region) -> PhoneNumber -> Bool
279293isValidNumber Nothing pn = unsafeDupablePerformIO $
280294 c_phone_number_util_is_valid_number pn
281−isValidNumber (Just (Region region)) pn = unsafeDupablePerformIO $
295+isValidNumber (Just (Left Region001)) pn = unsafeDupablePerformIO $
296+ c_phone_number_util_is_valid_number_for_region pn "001"
297+isValidNumber (Just (Right (Region region))) pn = unsafeDupablePerformIO $
282298 c_phone_number_util_is_valid_number_for_region pn region
283299
284300-- | Returns the region where a phone number is from. This could be used for
285301-- geocoding at the region level. Only guarantees correct results for valid,
286302-- 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
303+regionForNumber :: PhoneNumber -> Maybe (Either NonGeoRegion Region)
304+regionForNumber pn = filter001ZZ $
305+ unsafeDupablePerformIO $ mask_ $
306+ c_phone_number_util_get_region_code_for_number pn
290307
291308-- | Returns the country calling code for a specific region. For example, this
292309-- would be @1@ for the United States, and @64@ for New Zealand.
293−countryCodeForRegion :: Region -> CountryCode
294−countryCodeForRegion (Region region) = unsafeDupablePerformIO $
295− CountryCode . fromIntegral <$>
310+countryCodeForRegion :: Region -> Maybe CountryCode
311+countryCodeForRegion (Region region) = filter0 $ fromIntegral $
312+ unsafeDupablePerformIO $
296313 c_phone_number_util_get_country_code_for_region region
297314
298315-- | Returns the region code that matches the specific country code. Note that
@@ -300,18 +317,19 @@ countryCodeForRegion (Region region) = unsafeDupablePerformIO $
300317-- (e.g. US and Canada), and in that case, only one of the regions (normally the
301318-- one with the largest population) is returned. If the country calling code
302319-- 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
320+-- non-geographical calling codes like @800@) @'Region001'@ will be returned.
321+regionForCountryCode :: CountryCode -> Maybe (Either NonGeoRegion Region)
322+regionForCountryCode (CountryCode cc) = filter001ZZ $
323+ unsafeDupablePerformIO $ mask_ $
324+ c_phone_number_util_get_region_code_for_country_code $ fromIntegral cc
308325
309326-- | 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
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.
329+regionsForCountryCode :: CountryCode -> [Either NonGeoRegion Region]
330+regionsForCountryCode (CountryCode cc) = map filter001 $
331+ unsafeDupablePerformIO $ mask_ $
332+ c_phone_number_util_get_region_codes_for_country_calling_code $ fromIntegral cc
315333
316334-- | Checks if this is a region under the North American Numbering Plan
317335-- Administration (NANPA).
@@ -431,16 +449,16 @@ data ParseMode
431449-- number is not in international format (does not start with @\'+\'@).
432450parseNumber
433451 :: 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.
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.
441459 -> ByteString -- ^ Input.
442460 -> Either ErrorType PhoneNumber
443−parseNumber mode (Region region) number = case err of
461+parseNumber mode mRegion number = case err of
444462 I.NoParsingError -> Right pn
445463 I.InvalidCountryCodeError -> Left InvalidCountryCodeError
446464 I.NotANumber -> Left NotANumber
@@ -448,6 +466,9 @@ parseNumber mode (Region region) number = case err of
448466 I.TooShortNsn -> Left TooShortNsn
449467 I.TooLongNsn -> Left TooLongNsn
450468 where
469+ region = case mRegion of
470+ Nothing -> "ZZ"
471+ Just (Region reg) -> reg
451472 (err, pn) = case mode of
452473 Canonicalize -> unsafeDupablePerformIO $ mask_ $
453474 c_phone_number_util_parse number region