on master help sign in
Add support for HashMap from the unordered-containers package.
commit5b07f02493068804e2be072b44c79fd9cfd8d6f5 authorBryan O'Sullivan <bos@mailrank.com> dateTue 8 Mar 2011, 16:11 (16 years ago) parentad3254f
4 files changed+65−11
Data/Aeson/Functions.hs+19−3 Data/Aeson/Generic.hs+15−3 Data/Aeson/Types.hs+29−5 aeson.cabal+2
Data/Aeson/Functions.hs+19−3
@@ -1,13 +1,29 @@
11module Data.Aeson.Functions
22 (
3− transformMap
3+ hashMap
4+ , mapHash
5+ , transformMap
46 ) where
57
6−import Control.Arrow ((***))
8+import Control.Arrow ((***), first)
9+import Data.Hashable (Hashable)
10+import qualified Data.HashMap.Strict as H
711import qualified Data.Map as M
812
913-- | Transform one map into another. The ordering of keys must be
10−-- preserved.
14+-- preserved by the key transformation function.
1115transformMap :: (Ord k2) => (k1 -> k2) -> (v1 -> v2)
1216 -> M.Map k1 v1 -> M.Map k2 v2
1317transformMap fk fv = M.fromAscList . map (fk *** fv) . M.toAscList
18+{-# INLINE transformMap #-}
19+
20+-- | Transform a 'H.HashMap' into a 'M.Map'.
21+hashMap :: (Ord k2) => (k1 -> k2) -> (v1 -> v2)
22+ -> H.HashMap k1 v1 -> M.Map k2 v2
23+hashMap fk kv = M.fromList . map (fk *** kv) . H.toList
24+{-# INLINE hashMap #-}
25+
26+-- | Transform a 'M.Map' into a 'H.HashMap'.
27+mapHash :: (Eq k2, Hashable k2) => (k1 -> k2) -> M.Map k1 v -> H.HashMap k2 v
28+mapHash fk = H.fromList . map (first fk) . M.toList
29+{-# INLINE mapHash #-}
Data/Aeson/Generic.hs+15−3
@@ -22,7 +22,7 @@ module Data.Aeson.Generic
2222import Control.Applicative ((<$>))
2323import Control.Arrow (first)
2424import Control.Monad.State.Strict
25−import Data.Aeson.Functions (transformMap)
25+import Data.Aeson.Functions (hashMap, transformMap)
2626import Data.Aeson.Types hiding (FromJSON(..), ToJSON(..), fromJSON)
2727import Data.Attoparsec.Number (Number)
2828import Data.Generics
@@ -35,6 +35,7 @@ import Data.Word (Word, Word8, Word16, Word32, Word64)
3535import qualified Data.Aeson.Types as T
3636import qualified Data.ByteString as B
3737import qualified Data.ByteString.Lazy as L
38+import qualified Data.HashMap.Strict as H
3839import qualified Data.Map as Map
3940import qualified Data.Set as Set
4041import qualified Data.Text as DT
@@ -50,6 +51,7 @@ toJSON = toJSON_generic
5051 `ext1Q` vector
5152 `ext1Q` set
5253 `ext2Q'` mapAny
54+ `ext2Q'` hashMapAny
5355 -- Use the standard encoding for all base types.
5456 `extQ` (T.toJSON :: T Integer)
5557 `extQ` (T.toJSON :: T Int)
@@ -90,9 +92,18 @@ toJSON = toJSON_generic
9092 | tyrep == typeOf LT.empty = remap LT.toStrict
9193 | otherwise = modError "toJSON" $
9294 "cannot convert map keyed by type " ++ show tyrep
93− where tyrep = typeOf $ head $ Map.keys m
95+ where tyrep = typeOf . head . Map.keys $ m
9496 remap f = Object . transformMap (f . fromJust . cast) toJSON $ m
9597
98+ hashMapAny m
99+ | tyrep == typeOf "" = remap pack
100+ | tyrep == typeOf DT.empty = remap id
101+ | tyrep == typeOf LT.empty = remap LT.toStrict
102+ | otherwise = modError "toJSON" $
103+ "cannot convert map keyed by type " ++ show tyrep
104+ where tyrep = typeOf . head . H.keys $ m
105+ remap f = Object . hashMap (f . fromJust . cast) toJSON $ m
106+
96107
97108toJSON_generic :: (Data a) => a -> Value
98109toJSON_generic = generic
@@ -143,6 +154,7 @@ parseJSON j = parseJSON_generic j
143154 `ext1R` list
144155 `ext1R` vector
145156 `ext2R'` mapAny
157+ -- Don't know how to support parsing HashMaps :-(
146158 -- Use the standard encoding for all base types.
147159 `extR` (value :: F Integer)
148160 `extR` (value :: F Int)
@@ -186,7 +198,7 @@ parseJSON j = parseJSON_generic j
186198 | otherwise = myFail
187199 where res = case j of
188200 Object js -> Map.mapKeysMonotonic trans <$> T.mapM parseJSON js
189− _ -> myFail
201+ _ -> myFail
190202 trans
191203 | tyrep == typeOf DT.empty = fromJust . cast . id
192204 | tyrep == typeOf LT.empty = fromJust . cast . LT.fromStrict
Data/Aeson/Types.hs+29−5
@@ -36,32 +36,33 @@ module Data.Aeson.Types
3636 ) where
3737
3838import Control.Applicative
39−import Control.Monad (MonadPlus(..))
40−import Data.Monoid (Monoid(..))
4139import Control.DeepSeq (NFData(..))
40+import Control.Monad (MonadPlus(..))
41+import Data.Aeson.Functions (hashMap, mapHash, transformMap)
42+import Data.Attoparsec.Char8 (Number(..))
4243import Data.Data (Data)
4344import Data.Int (Int8, Int16, Int32, Int64)
44−import qualified Data.IntSet as IntSet
4545import Data.Map (Map)
4646import Data.Monoid (Dual(..), First(..), Last(..))
47+import Data.Monoid (Monoid(..))
4748import Data.Ratio (Ratio)
4849import Data.Text (Text, pack, unpack)
4950import Data.Text.Encoding (decodeUtf8, encodeUtf8)
5051import Data.Time.Clock (UTCTime)
5152import Data.Time.Format (FormatTime, formatTime, parseTime)
52−import Data.Attoparsec.Char8 (Number(..))
5353import Data.Typeable (Typeable)
5454import Data.Vector (Vector)
5555import Data.Word (Word, Word8, Word16, Word32, Word64)
5656import System.Locale (defaultTimeLocale)
5757import qualified Data.ByteString as B
5858import qualified Data.ByteString.Lazy as LB
59+import qualified Data.HashMap.Strict as H
60+import qualified Data.IntSet as IntSet
5961import qualified Data.Map as M
6062import qualified Data.Set as Set
6163import qualified Data.Text as T
6264import qualified Data.Text.Lazy as LT
6365import qualified Data.Vector as V
64−import Data.Aeson.Functions
6566
6667-- | The result of running a 'Parser'.
6768data Result a = Error String
@@ -526,6 +527,29 @@ instance (ToJSON v) => ToJSON (M.Map String v) where
526527instance (FromJSON v) => FromJSON (M.Map String v) where
527528 parseJSON = fmap (M.mapKeysMonotonic unpack) . parseJSON
528529
530+instance (ToJSON v) => ToJSON (H.HashMap Text v) where
531+ toJSON = Object . hashMap id toJSON
532+ {-# INLINE toJSON #-}
533+
534+instance (FromJSON v) => FromJSON (H.HashMap Text v) where
535+ parseJSON (Object o) = H.fromList <$> go (M.toList o)
536+ where
537+ go ((k,v):kvs) = ((:) . (,) k) <$> parseJSON v <*> go kvs
538+ go _ = pure []
539+ parseJSON _ = empty
540+
541+instance (ToJSON v) => ToJSON (H.HashMap LT.Text v) where
542+ toJSON = Object . M.fromList . H.foldrWithKey (\k v -> ((LT.toStrict k,toJSON v) :)) []
543+
544+instance (FromJSON v) => FromJSON (H.HashMap LT.Text v) where
545+ parseJSON = fmap (mapHash LT.fromStrict) . parseJSON
546+
547+instance (ToJSON v) => ToJSON (H.HashMap String v) where
548+ toJSON = Object . hashMap pack toJSON
549+
550+instance (FromJSON v) => FromJSON (H.HashMap String v) where
551+ parseJSON = fmap (mapHash unpack) . parseJSON
552+
529553instance ToJSON Value where
530554 toJSON a = a
531555 {-# INLINE toJSON #-}
aeson.cabal+2
@@ -78,11 +78,13 @@ library
7878 bytestring,
7979 containers,
8080 deepseq,
81+ hashable,
8182 monads-fd,
8283 old-locale,
8384 syb,
8485 text >= 0.11.0.2,
8586 time,
87+ unordered-containers,
8688 vector >= 0.7
8789
8890 if flag(developer)