packages feed

country 0.1.1 → 0.1.2

raw patch · 5 files changed

+147/−85 lines, 5 filesdep +aesondep +scientificPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: aeson, scientific

API changes (from Hackage documentation)

- Country.Unsafe: instance Data.Hashable.Class.Hashable Country.Unsafe.Country
- Country.Unsafe: instance Data.Primitive.Types.Prim Country.Unsafe.Country
- Country.Unsafe: instance GHC.Classes.Eq Country.Unsafe.Country
- Country.Unsafe: instance GHC.Classes.Ord Country.Unsafe.Country
- Country.Unsafe: instance GHC.Show.Show Country.Unsafe.Country

Files

country.cabal view
@@ -1,5 +1,5 @@ name: country-version: 0.1.1+version: 0.1.2 synopsis: Country data type and functions description:   The `country` library provides a data type for dealing with@@ -46,6 +46,8 @@     , unordered-containers >= 0.2 && < 0.3     , ghc-prim >= 0.5 && < 0.6     , hashable >= 1.2 && < 1.3+    , aeson >= 0.11 && < 1.3+    , scientific >= 0.3 && < 0.4   default-language: Haskell2010  test-suite test
src/Country.hs view
@@ -1,6 +1,8 @@ {-# LANGUAGE BangPatterns #-} {-# LANGUAGE MagicHash #-} +{-# OPTIONS_GHC -Wall #-}+ module Country   ( Country     -- * Three digit code@@ -20,8 +22,7 @@  import Country.Unsafe (Country(..)) import Country.Unexposed.Encode.English (countryNameQuads)-import Country.Unexposed.ExtraNames (extraNames)-import Country.Unexposed.Names (englishCountryNamesText,numberOfPossibleCodes)+import Country.Unexposed.Names (englishCountryNamesText,numberOfPossibleCodes,alphaTwoHashMap,alphaThreeHashMap,decodeMap,decodeNumeric,encodeEnglish) import Country.Unexposed.Enumerate (enumeratedCountries) import Data.Text (Text) import Data.ByteString (ByteString)@@ -39,7 +40,6 @@ import Data.Bits (unsafeShiftL,unsafeShiftR) import qualified Data.List as L import qualified Data.HashMap.Strict as HM-import qualified Data.Text as T import qualified Data.Text.Array as TA import qualified Data.Text.Internal as TI @@ -48,18 +48,7 @@ encodeNumeric :: Country -> Word16 encodeNumeric (Country n) = n --- | Get a country from a numeric code. Any code greater than---   999 will not have a country associated with it. Additionally,---   many codes are unassigned.-decodeNumeric :: Word16 -> Maybe Country-decodeNumeric n = if n < 1000 && indexByteArray numericValidities (word16ToInt n) == (1 :: Word8)-  then Just (Country n)-  else Nothing --- | The name of a country given in English-encodeEnglish :: Country -> Text-encodeEnglish (Country n) = indexArray englishCountryNamesText (word16ToInt n)- -- | The alpha-2 country code, uppercase alphaTwoUpper :: Country -> Text alphaTwoUpper c = TI.text allAlphaTwoUpper (timesTwo (indexOfCountry c)) 2@@ -82,26 +71,6 @@ decodeAlphaThree :: Text -> Maybe Country decodeAlphaThree = flip HM.lookup alphaThreeHashMap -alphaTwoHashMap :: HashMap Text Country-alphaTwoHashMap = L.foldl'-  (\hm (countryNum,_,(c1,c2),_) ->-      HM.insert (T.pack [c1,c2]) (Country countryNum)-    $ HM.insert (T.pack [toLower c1, toLower c2]) (Country countryNum)-    $ hm-  )-  HM.empty countryNameQuads-{-# NOINLINE alphaTwoHashMap #-}--alphaThreeHashMap :: HashMap Text Country-alphaThreeHashMap = L.foldl'-  (\hm (countryNum,_,_,(c1,c2,c3)) -> -      HM.insert (T.pack [c1,c2,c3]) (Country countryNum)-    $ HM.insert (T.pack [toLower c1, toLower c2, toLower c3]) (Country countryNum)-    $ hm-  )-  HM.empty countryNameQuads-{-# NOINLINE alphaThreeHashMap #-}- half :: Int -> Int half x = unsafeShiftR x 1 @@ -129,15 +98,6 @@ word16ToChar :: Word16 -> Char word16ToChar = chr . fromIntegral --decodeMap :: HashMap Text Country-decodeMap = -  let baseMap = HM.union alphaTwoHashMap alphaThreeHashMap-      hm1 = L.foldl' (\hm (country,name) -> HM.insert name country hm) baseMap extraNames-      hm2 = L.foldl' (\hm (countryNum,name,_,_) -> HM.insert name (Country countryNum) hm) hm1 countryNameQuads-   in hm2-{-# NOINLINE decodeMap #-}- arrayFoldl' :: (a -> b -> a) -> a -> Array b -> a arrayFoldl' f z a = go 0 z   where@@ -150,19 +110,6 @@  numberOfCountries :: Int numberOfCountries = length countryNameQuads---- | The elements in this array are Word8 (basically boolean)-numericValidities :: ByteArray-numericValidities = runST $ do-  m <- newByteArray numberOfPossibleCodes-  let clear !ix = if ix < numberOfPossibleCodes-        then writeByteArray m ix (0 :: Word8)-        else return ()-  clear 0-  forM_ countryNameQuads $ \(n,_,_,_) -> do-    writeByteArray m (word16ToInt n) (1 :: Word8)-  unsafeFreezeByteArray m-{-# NOINLINE numericValidities #-}  -- | The elements in this array are Word16 positions :: ByteArray
src/Country/Unexposed/ExtraNames.hs view
@@ -1,22 +1,11 @@ {-# LANGUAGE OverloadedStrings #-}  module Country.Unexposed.ExtraNames-  ( extraNames-  ) where+  ( ) where  import Country.Unsafe (Country) import Country.Identifier import Data.Text (Text) import Data.Primitive (indexArray,newArray,unsafeFreezeArray,writeArray,   writeByteArray,indexByteArray,unsafeFreezeByteArray,newByteArray)--extraNames :: [(Country,Text)]-extraNames =-  [ (unitedStatesOfAmerica,"United States")-  , (unitedStatesOfAmerica,"USA")-  , (unitedStatesOfAmerica,"U.S.A.")-  , (mexico,"Estados Unidos Mexicanos")-  , (mexico,"México")-  , (mexico,"Méjico")-  ] 
src/Country/Unexposed/Names.hs view
@@ -1,9 +1,36 @@+{-# LANGUAGE OverloadedStrings #-}+{-# LANGUAGE BangPatterns #-}+{-# LANGUAGE MagicHash #-}+{-# LANGUAGE UnboxedTuples #-}+{-# LANGUAGE GeneralizedNewtypeDeriving #-}++{-# OPTIONS_HADDOCK not-home #-}+ module Country.Unexposed.Names   ( englishCountryNamesText   , englishIdentifierNamesText   , numberOfPossibleCodes+  , decodeMap+  , alphaTwoHashMap+  , alphaThreeHashMap+  , decodeNumeric+  , encodeEnglish+  , Country(..)   ) where +import Data.Word (Word16)+import Data.Hashable (Hashable)+import Data.Primitive.Types (Prim)+import Data.HashMap.Strict (HashMap)+import Data.Primitive (indexArray)+import Data.Primitive.Array (Array(..))+import Data.Primitive.ByteArray (ByteArray(..))+import Control.Monad+import qualified Data.Text as T+import qualified Data.Aeson as AE+import qualified Data.Aeson.Types as AET+import qualified Data.HashMap.Strict as HM+import qualified Data.List as L import Control.Monad.ST import Data.Text (Text) import Data.Word@@ -12,7 +39,44 @@ import Data.Primitive (Array,indexArray,newArray,unsafeFreezeArray,writeArray,   writeByteArray,indexByteArray,unsafeFreezeByteArray,newByteArray) import qualified Data.Text as T+import qualified Data.Scientific as SCI +-- | The name of a country given in English+encodeEnglish :: Country -> Text+encodeEnglish (Country n) = indexArray englishCountryNamesText (word16ToInt n)++mexico :: Country+mexico = Country 484++unitedStatesOfAmerica :: Country+unitedStatesOfAmerica = Country 840++ålandIslands :: Country+ålandIslands = Country 248++venezuelaBolivarianRepublicOf :: Country+venezuelaBolivarianRepublicOf = Country 862++boliviaPlurinationalStateOf :: Country+boliviaPlurinationalStateOf = Country 68++extraNames :: [(Country,Text)]+extraNames =+  [ (unitedStatesOfAmerica,"United States")+  , (unitedStatesOfAmerica,"The United States")+  , (unitedStatesOfAmerica,"USA")+  , (unitedStatesOfAmerica,"U.S.A.")+  , (unitedStatesOfAmerica,"Estados Unidos de América")+  , (mexico,"Estados Unidos Mexicanos")+  , (mexico,"México")+  , (mexico,"Méjico")+  , (ålandIslands,"Aland Islands")+  , (venezuelaBolivarianRepublicOf,"Venezuela")+  , (venezuelaBolivarianRepublicOf,"Bolivarian Republic of Venezuela")+  , (boliviaPlurinationalStateOf,"Bolivia")+  , (boliviaPlurinationalStateOf,"Plurinational State of Bolivia")+  ]+ englishCountryNamesText :: Array Text englishCountryNamesText = runST $ do   m <- newArray numberOfPossibleCodes unnamed@@ -42,4 +106,79 @@  word16ToInt :: Word16 -> Int word16ToInt = fromIntegral++decodeMap :: HashMap Text Country+decodeMap = +  let baseMap = HM.union alphaTwoHashMap alphaThreeHashMap+      hm1 = L.foldl' (\hm (country,name) -> HM.insert name country hm) baseMap extraNames+      hm2 = L.foldl' (\hm (countryNum,name,_,_) -> HM.insert name (Country countryNum) hm) hm1 countryNameQuads+   in hm2+{-# NOINLINE decodeMap #-}++-- | A country recognized by ISO 3166.+newtype Country = Country Word16+  deriving (Eq,Ord,Prim,Hashable)++instance Show Country where+  show (Country n) = T.unpack (indexArray englishIdentifierNamesText (word16ToInt n))++-- todo: add support for encoding directly to bytestring.+-- Also, add suport for ToJSONKey and FromJSONKey once everything+-- finally gets off of aeson-0.11 (looking at you, reflex-platform)+instance AE.ToJSON Country where+  toJSON = AET.String . encodeEnglish++instance AE.FromJSON Country where+  parseJSON x = case x of+    AET.String t -> case HM.lookup t decodeMap of+      Nothing -> fail $ "invalid country name " ++ T.unpack t+      Just country -> return country+    AET.Number n -> case SCI.toBoundedInteger n of+      Nothing -> fail errMsg+      Just w -> case decodeNumeric w of+        Just c -> return c+        Nothing -> fail errMsg+      where errMsg = fail $ "invalid country code " ++ show n+    _ -> AET.typeMismatch "Country" x++-- | Get a country from a numeric code. Any code greater than+--   999 will not have a country associated with it. Additionally,+--   many codes are unassigned.+decodeNumeric :: Word16 -> Maybe Country+decodeNumeric n = if n < 1000 && indexByteArray numericValidities (word16ToInt n) == (1 :: Word8)+  then Just (Country n)+  else Nothing++-- | The elements in this array are Word8 (basically boolean)+numericValidities :: ByteArray+numericValidities = runST $ do+  m <- newByteArray numberOfPossibleCodes+  let clear !ix = if ix < numberOfPossibleCodes+        then writeByteArray m ix (0 :: Word8)+        else return ()+  clear 0+  forM_ countryNameQuads $ \(n,_,_,_) -> do+    writeByteArray m (word16ToInt n) (1 :: Word8)+  unsafeFreezeByteArray m+{-# NOINLINE numericValidities #-}++alphaTwoHashMap :: HashMap Text Country+alphaTwoHashMap = L.foldl'+  (\hm (countryNum,_,(c1,c2),_) ->+      HM.insert (T.pack [c1,c2]) (Country countryNum)+    $ HM.insert (T.pack [toLower c1, toLower c2]) (Country countryNum)+    $ hm+  )+  HM.empty countryNameQuads+{-# NOINLINE alphaTwoHashMap #-}++alphaThreeHashMap :: HashMap Text Country+alphaThreeHashMap = L.foldl'+  (\hm (countryNum,_,_,(c1,c2,c3)) -> +      HM.insert (T.pack [c1,c2,c3]) (Country countryNum)+    $ HM.insert (T.pack [toLower c1, toLower c2, toLower c3]) (Country countryNum)+    $ hm+  )+  HM.empty countryNameQuads+{-# NOINLINE alphaThreeHashMap #-} 
src/Country/Unsafe.hs view
@@ -14,20 +14,5 @@   ( Country(..)   ) where -import Data.Word (Word16)-import Data.Hashable (Hashable)-import Data.Primitive.Types (Prim)-import Data.Primitive (indexArray)-import Country.Unexposed.Names (englishIdentifierNamesText)-import qualified Data.Text as T---- | A country recognized by ISO 3166.-newtype Country = Country Word16-  deriving (Eq,Ord,Prim,Hashable)--instance Show Country where-  show (Country n) = T.unpack (indexArray englishIdentifierNamesText (word16ToInt n))--word16ToInt :: Word16 -> Int-word16ToInt = fromIntegral+import Country.Unexposed.Names (Country(..))