@@ -1,4 +1,4 @@
1−{-# LANGUAGE PatternGuards #-}
1+{-# LANGUAGE PatternGuards, RankNTypes, ScopedTypeVariables #-}
22
33-- Module: Data.Aeson.Generic
44-- Copyright: (c) 2011 MailRank, Inc.
@@ -22,22 +22,25 @@ 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
2929import Data.Int (Int8, Int16, Int32, Int64)
3030import Data.IntSet (IntSet)
31+import Data.Maybe (fromJust)
3132import Data.Text (Text, pack, unpack)
3233import Data.Time.Clock (UTCTime)
3334import Data.Word (Word, Word8, Word16, Word32, Word64)
3435import qualified Data.Aeson.Types as T
3536import qualified Data.ByteString as B
3637import qualified Data.ByteString.Lazy as L
38+import qualified Data.HashMap.Strict as H
3739import qualified Data.Map as Map
38−import qualified Data.Traversable as T
3940import qualified Data.Set as Set
40−import qualified Data.Text.Lazy as L
41+import qualified Data.Text as DT
42+import qualified Data.Text.Lazy as LT
43+import qualified Data.Traversable as T
4144import qualified Data.Vector as V
4245
4346type T a = a -> Value
@@ -47,9 +50,8 @@ toJSON = toJSON_generic
4750 `ext1Q` list
4851 `ext1Q` vector
4952 `ext1Q` set
50− `ext1Q` mapText
51− `ext1Q` mapLazyText
52− `ext1Q` mapString
53+ `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)
@@ -68,7 +70,7 @@ toJSON = toJSON_generic
6870 `extQ` (T.toJSON :: T Rational)
6971 `extQ` (T.toJSON :: T Char)
7072 `extQ` (T.toJSON :: T Text)
71− `extQ` (T.toJSON :: T L.Text)
73+ `extQ` (T.toJSON :: T LT.Text)
7274 `extQ` (T.toJSON :: T String)
7375 `extQ` (T.toJSON :: T B.ByteString)
7476 `extQ` (T.toJSON :: T L.ByteString)
@@ -83,9 +85,25 @@ toJSON = toJSON_generic
8385 list xs = Array . V.fromList . map toJSON $ xs
8486 vector v = Array . V.map toJSON $ v
8587 set s = Array . V.fromList . map toJSON . Set.toList $ s
86− mapText m = Object . Map.map toJSON $ m
87− mapLazyText m = Object . transformMap L.toStrict toJSON $ m
88− mapString m = Object . transformMap pack toJSON $ m
88+
89+ mapAny m
90+ | tyrep == typeOf "" = remap pack
91+ | tyrep == typeOf DT.empty = remap id
92+ | tyrep == typeOf LT.empty = remap LT.toStrict
93+ | otherwise = modError "toJSON" $
94+ "cannot convert map keyed by type " ++ show tyrep
95+ where tyrep = typeOf . head . Map.keys $ m
96+ remap f = Object . transformMap (f . fromJust . cast) toJSON $ m
97+
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+
89107
90108toJSON_generic :: (Data a) => a -> Value
91109toJSON_generic = generic
@@ -104,8 +122,8 @@ toJSON_generic = generic
104122 AlgRep _ -> encodeConstr (toConstr a) (gmapQ toJSON a)
105123 rep -> err (dataTypeOf a) rep
106124 where
107− err dt r = error $ "Data.Aeson.Generic.toJSON: not AlgRep " ++
108− show r ++ "(" ++ show dt ++ ")"
125+ err dt r = modError "toJSON" $ "not AlgRep " ++
126+ show r ++ "(" ++ show dt ++ ")"
109127 -- Encode nullary constructor as a string.
110128 -- Encode non-nullary constructors as an object with the constructor
111129 -- name as the single field and the arguments as the value.
@@ -135,9 +153,8 @@ parseJSON :: (Data a) => Value -> Parser a
135153parseJSON j = parseJSON_generic j
136154 `ext1R` list
137155 `ext1R` vector
138− `ext1R` mapText
139− `ext1R` mapLazyText
140− `ext1R` mapString
156+ `ext2R'` mapAny
157+ -- Don't know how to support parsing HashMaps :-(
141158 -- Use the standard encoding for all base types.
142159 `extR` (value :: F Integer)
143160 `extR` (value :: F Int)
@@ -156,7 +173,7 @@ parseJSON j = parseJSON_generic j
156173 `extR` (value :: F Rational)
157174 `extR` (value :: F Char)
158175 `extR` (value :: F Text)
159− `extR` (value :: F L.Text)
176+ `extR` (value :: F LT.Text)
160177 `extR` (value :: F String)
161178 `extR` (value :: F B.ByteString)
162179 `extR` (value :: F L.ByteString)
@@ -174,15 +191,23 @@ parseJSON j = parseJSON_generic j
174191 vector :: (Data a) => Parser (V.Vector a)
175192 vector = case j of
176193 Array js -> V.mapM parseJSON js
177− _ -> modFail "parseJSON" $ "bad data: " ++ show j
178− mapText :: (Data a) => Parser (Map.Map Text a)
179− mapText = case j of
180− Object js -> T.mapM parseJSON js
181− _ -> modFail "parseJSON" $ "bad data: " ++ show j
182− mapLazyText :: (Data a) => Parser (Map.Map L.Text a)
183− mapLazyText = Map.mapKeysMonotonic L.fromStrict <$> parseJSON j
184− mapString :: (Data a) => Parser (Map.Map String a)
185− mapString = Map.mapKeysMonotonic unpack <$> parseJSON j
194+ _ -> myFail
195+ mapAny :: forall e f. (Data e, Data f) => Parser (Map.Map f e)
196+ mapAny
197+ | tyrep `elem` [typeOf LT.empty, typeOf DT.empty, typeOf ""] = res
198+ | otherwise = myFail
199+ where res = case j of
200+ Object js -> Map.mapKeysMonotonic trans <$> T.mapM parseJSON js
201+ _ -> myFail
202+ trans
203+ | tyrep == typeOf DT.empty = fromJust . cast . id
204+ | tyrep == typeOf LT.empty = fromJust . cast . LT.fromStrict
205+ | tyrep == typeOf "" = fromJust . cast . DT.unpack
206+ | otherwise = modError "parseJSON"
207+ "mapAny -- should never happen"
208+ tyrep = typeOf (undefined :: f)
209+ myFail = modFail "parseJSON" $ "bad data: " ++ show j
210+
186211
187212parseJSON_generic :: (Data a) => Value -> Parser a
188213parseJSON_generic j = generic
@@ -190,7 +215,7 @@ parseJSON_generic j = generic
190215 typ = dataTypeOf $ resType generic
191216 generic = case dataTypeRep typ of
192217 AlgRep [] -> case j of
193− Null -> return (error "Empty type")
218+ Null -> return (modError "parseJSON" "empty type")
194219 _ -> modFail "parseJSON" "no-constr bad data"
195220 AlgRep [_] -> decodeArgs (indexConstr typ 1) j
196221 AlgRep _ -> do (c, j') <- getConstr typ j; decodeArgs c j'
@@ -202,10 +227,10 @@ parseJSON_generic j = generic
202227 getConstr t (String js) = do c <- readConstr' t (unpack js)
203228 return (c, Null) -- handle nullary ctor
204229 getConstr _ _ = modFail "parseJSON" "bad constructor encoding"
205− readConstr' t s =
206− maybe (modFail "parseJSON" $ "unknown constructor: " ++ s ++ " " ++
207− show t)
208− return $ readConstr t s
230+ readConstr' t s =
231+ maybe (modFail "parseJSON" $ "unknown constructor: " ++ s ++ " " ++
232+ show t)
233+ return $ readConstr t s
209234
210235 decodeArgs c0 = go (numConstrArgs (resType generic) c0) c0
211236 (constrFields c0)
@@ -243,7 +268,40 @@ parseJSON_generic j = generic
243268 where f = do modify (+1); return undefined
244269
245270 resType :: MonadPlus m => m a -> a
246− resType _ = error "resType"
271+ resType _ = modError "parseJSON" "resType"
247272
248273modFail :: (Monad m) => String -> String -> m a
249274modFail func err = fail $ "Data.Aeson.Generic." ++ func ++ ": " ++ err
275+
276+modError :: String -> String -> a
277+modError func err = error $ "Data.Aeson.Generic." ++ func ++ ": " ++ err
278+
279+
280+-- Type extension for binary type constructors.
281+
282+-- | Flexible type extension
283+ext2' :: (Data a, Typeable2 t)
284+ => c a
285+ -> (forall d1 d2. (Data d1, Data d2) => c (t d1 d2))
286+ -> c a
287+ext2' def ext = maybe def id (dataCast2 ext)
288+
289+-- | Type extension of queries for type constructors
290+ext2Q' :: (Data d, Typeable2 t)
291+ => (d -> q)
292+ -> (forall d1 d2. (Data d1, Data d2) => t d1 d2 -> q)
293+ -> d -> q
294+ext2Q' def ext = unQ ((Q def) `ext2'` (Q ext))
295+
296+-- | Type extension of readers for type constructors
297+ext2R' :: (Monad m, Data d, Typeable2 t)
298+ => m d
299+ -> (forall d1 d2. (Data d1, Data d2) => m (t d1 d2))
300+ -> m d
301+ext2R' def ext = unR ((R def) `ext2'` (R ext))
302+
303+-- | The type constructor for queries
304+newtype Q q x = Q { unQ :: x -> q }
305+
306+-- | The type constructor for readers
307+newtype R m x = R { unR :: m x }