@@ -1,4 +1,4 @@
1−{-# LANGUAGE PatternGuards #-}
1+{-# LANGUAGE PatternGuards, RankNTypes, ScopedTypeVariables #-}
3-- Module: Data.Aeson.Generic
3-- Module: Data.Aeson.Generic
4-- Copyright: (c) 2011 MailRank, Inc.
4-- Copyright: (c) 2011 MailRank, Inc.
@@ -22,22 +22,25 @@ module Data.Aeson.Generic
22import Control.Applicative ((<$>))
22import Control.Applicative ((<$>))
23import Control.Arrow (first)
23import Control.Arrow (first)
24import Control.Monad.State.Strict
24import Control.Monad.State.Strict
25−import Data.Aeson.Functions (transformMap)
25+import Data.Aeson.Functions (hashMap, transformMap)
26import Data.Aeson.Types hiding (FromJSON(..), ToJSON(..), fromJSON)
26import Data.Aeson.Types hiding (FromJSON(..), ToJSON(..), fromJSON)
27import Data.Attoparsec.Number (Number)
27import Data.Attoparsec.Number (Number)
28import Data.Generics
28import Data.Generics
29import Data.Int (Int8, Int16, Int32, Int64)
29import Data.Int (Int8, Int16, Int32, Int64)
30import Data.IntSet (IntSet)
30import Data.IntSet (IntSet)
31+import Data.Maybe (fromJust)
31import Data.Text (Text, pack, unpack)
32import Data.Text (Text, pack, unpack)
32import Data.Time.Clock (UTCTime)
33import Data.Time.Clock (UTCTime)
33import Data.Word (Word, Word8, Word16, Word32, Word64)
34import Data.Word (Word, Word8, Word16, Word32, Word64)
34import qualified Data.Aeson.Types as T
35import qualified Data.Aeson.Types as T
35import qualified Data.ByteString as B
36import qualified Data.ByteString as B
36import qualified Data.ByteString.Lazy as L
37import qualified Data.ByteString.Lazy as L
38+import qualified Data.HashMap.Strict as H
37import qualified Data.Map as Map
39import qualified Data.Map as Map
38−import qualified Data.Traversable as T
39import qualified Data.Set as Set
40import 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
41import qualified Data.Vector as V
44import qualified Data.Vector as V
43type T a = a -> Value
46type T a = a -> Value
@@ -47,9 +50,8 @@ toJSON = toJSON_generic
47 `ext1Q` list
50 `ext1Q` list
48 `ext1Q` vector
51 `ext1Q` vector
49 `ext1Q` set
52 `ext1Q` set
50− `ext1Q` mapText
53+ `ext2Q'` mapAny
51− `ext1Q` mapLazyText
54+ `ext2Q'` hashMapAny
53 -- Use the standard encoding for all base types.
55 -- Use the standard encoding for all base types.
54 `extQ` (T.toJSON :: T Integer)
56 `extQ` (T.toJSON :: T Integer)
55 `extQ` (T.toJSON :: T Int)
57 `extQ` (T.toJSON :: T Int)
@@ -68,7 +70,7 @@ toJSON = toJSON_generic
68 `extQ` (T.toJSON :: T Rational)
70 `extQ` (T.toJSON :: T Rational)
69 `extQ` (T.toJSON :: T Char)
71 `extQ` (T.toJSON :: T Char)
70 `extQ` (T.toJSON :: T Text)
72 `extQ` (T.toJSON :: T Text)
71− `extQ` (T.toJSON :: T L.Text)
73+ `extQ` (T.toJSON :: T LT.Text)
72 `extQ` (T.toJSON :: T String)
74 `extQ` (T.toJSON :: T String)
73 `extQ` (T.toJSON :: T B.ByteString)
75 `extQ` (T.toJSON :: T B.ByteString)
74 `extQ` (T.toJSON :: T L.ByteString)
76 `extQ` (T.toJSON :: T L.ByteString)
@@ -83,9 +85,25 @@ toJSON = toJSON_generic
83 list xs = Array . V.fromList . map toJSON $ xs
85 list xs = Array . V.fromList . map toJSON $ xs
84 vector v = Array . V.map toJSON $ v
86 vector v = Array . V.map toJSON $ v
85 set s = Array . V.fromList . map toJSON . Set.toList $ s
87 set s = Array . V.fromList . map toJSON . Set.toList $ s
86− mapText m = Object . Map.map toJSON $ m
88+
87− mapLazyText m = Object . transformMap L.toStrict toJSON $ m
89+ mapAny m
88− mapString m = Object . transformMap pack toJSON $ 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
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
90toJSON_generic :: (Data a) => a -> Value
108toJSON_generic :: (Data a) => a -> Value
91toJSON_generic = generic
109toJSON_generic = generic
@@ -104,8 +122,8 @@ toJSON_generic = generic
104 AlgRep _ -> encodeConstr (toConstr a) (gmapQ toJSON a)
122 AlgRep _ -> encodeConstr (toConstr a) (gmapQ toJSON a)
105 rep -> err (dataTypeOf a) rep
123 rep -> err (dataTypeOf a) rep
107− err dt r = error $ "Data.Aeson.Generic.toJSON: not AlgRep " ++
125+ err dt r = modError "toJSON" $ "not AlgRep " ++
108− show r ++ "(" ++ show dt ++ ")"
126+ show r ++ "(" ++ show dt ++ ")"
109 -- Encode nullary constructor as a string.
127 -- Encode nullary constructor as a string.
110 -- Encode non-nullary constructors as an object with the constructor
128 -- Encode non-nullary constructors as an object with the constructor
111 -- name as the single field and the arguments as the value.
129 -- name as the single field and the arguments as the value.
@@ -135,9 +153,8 @@ parseJSON :: (Data a) => Value -> Parser a
135parseJSON j = parseJSON_generic j
153parseJSON j = parseJSON_generic j
136 `ext1R` list
154 `ext1R` list
137 `ext1R` vector
155 `ext1R` vector
138− `ext1R` mapText
156+ `ext2R'` mapAny
139− `ext1R` mapLazyText
157+ -- Don't know how to support parsing HashMaps :-(
141 -- Use the standard encoding for all base types.
158 -- Use the standard encoding for all base types.
142 `extR` (value :: F Integer)
159 `extR` (value :: F Integer)
143 `extR` (value :: F Int)
160 `extR` (value :: F Int)
@@ -156,7 +173,7 @@ parseJSON j = parseJSON_generic j
156 `extR` (value :: F Rational)
173 `extR` (value :: F Rational)
157 `extR` (value :: F Char)
174 `extR` (value :: F Char)
158 `extR` (value :: F Text)
175 `extR` (value :: F Text)
159− `extR` (value :: F L.Text)
176+ `extR` (value :: F LT.Text)
160 `extR` (value :: F String)
177 `extR` (value :: F String)
161 `extR` (value :: F B.ByteString)
178 `extR` (value :: F B.ByteString)
162 `extR` (value :: F L.ByteString)
179 `extR` (value :: F L.ByteString)
@@ -174,15 +191,23 @@ parseJSON j = parseJSON_generic j
174 vector :: (Data a) => Parser (V.Vector a)
191 vector :: (Data a) => Parser (V.Vector a)
175 vector = case j of
192 vector = case j of
176 Array js -> V.mapM parseJSON js
193 Array js -> V.mapM parseJSON js
177− _ -> modFail "parseJSON" $ "bad data: " ++ show j
194+ _ -> myFail
178− mapText :: (Data a) => Parser (Map.Map Text a)
195+ mapAny :: forall e f. (Data e, Data f) => Parser (Map.Map f e)
197+ | tyrep `elem` [typeOf LT.empty, typeOf DT.empty, typeOf ""] = res
198+ | otherwise = myFail
179− mapText = case j of
199+ where res = case j of
180− Object js -> T.mapM parseJSON js
200+ Object js -> Map.mapKeysMonotonic trans <$> T.mapM parseJSON js
181− _ -> modFail "parseJSON" $ "bad data: " ++ show j
201+ _ -> myFail
182− mapLazyText :: (Data a) => Parser (Map.Map L.Text a)
202+ trans
183− mapLazyText = Map.mapKeysMonotonic L.fromStrict <$> parseJSON j
203+ | tyrep == typeOf DT.empty = fromJust . cast . id
184− mapString :: (Data a) => Parser (Map.Map String a)
204+ | tyrep == typeOf LT.empty = fromJust . cast . LT.fromStrict
185− mapString = Map.mapKeysMonotonic unpack <$> parseJSON j
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
187parseJSON_generic :: (Data a) => Value -> Parser a
212parseJSON_generic :: (Data a) => Value -> Parser a
188parseJSON_generic j = generic
213parseJSON_generic j = generic
@@ -190,7 +215,7 @@ parseJSON_generic j = generic
190 typ = dataTypeOf $ resType generic
215 typ = dataTypeOf $ resType generic
191 generic = case dataTypeRep typ of
216 generic = case dataTypeRep typ of
192 AlgRep [] -> case j of
217 AlgRep [] -> case j of
193− Null -> return (error "Empty type")
218+ Null -> return (modError "parseJSON" "empty type")
194 _ -> modFail "parseJSON" "no-constr bad data"
219 _ -> modFail "parseJSON" "no-constr bad data"
195 AlgRep [_] -> decodeArgs (indexConstr typ 1) j
220 AlgRep [_] -> decodeArgs (indexConstr typ 1) j
196 AlgRep _ -> do (c, j') <- getConstr typ j; decodeArgs c j'
221 AlgRep _ -> do (c, j') <- getConstr typ j; decodeArgs c j'
@@ -202,10 +227,10 @@ parseJSON_generic j = generic
202 getConstr t (String js) = do c <- readConstr' t (unpack js)
227 getConstr t (String js) = do c <- readConstr' t (unpack js)
203 return (c, Null) -- handle nullary ctor
228 return (c, Null) -- handle nullary ctor
204 getConstr _ _ = modFail "parseJSON" "bad constructor encoding"
229 getConstr _ _ = modFail "parseJSON" "bad constructor encoding"
205− readConstr' t s =
230+ readConstr' t s =
206− maybe (modFail "parseJSON" $ "unknown constructor: " ++ s ++ " " ++
231+ maybe (modFail "parseJSON" $ "unknown constructor: " ++ s ++ " " ++
207− show t)
232+ show t)
208− return $ readConstr t s
233+ return $ readConstr t s
210 decodeArgs c0 = go (numConstrArgs (resType generic) c0) c0
235 decodeArgs c0 = go (numConstrArgs (resType generic) c0) c0
211 (constrFields c0)
236 (constrFields c0)
@@ -243,7 +268,40 @@ parseJSON_generic j = generic
243 where f = do modify (+1); return undefined
268 where f = do modify (+1); return undefined
245 resType :: MonadPlus m => m a -> a
270 resType :: MonadPlus m => m a -> a
246− resType _ = error "resType"
271+ resType _ = modError "parseJSON" "resType"
248modFail :: (Monad m) => String -> String -> m a
273modFail :: (Monad m) => String -> String -> m a
249modFail func err = fail $ "Data.Aeson.Generic." ++ func ++ ": " ++ err
274modFail func err = fail $ "Data.Aeson.Generic." ++ func ++ ": " ++ err
276+modError :: String -> String -> a
277+modError func err = error $ "Data.Aeson.Generic." ++ func ++ ": " ++ err
280+-- Type extension for binary type constructors.
282+-- | Flexible type extension
283+ext2' :: (Data a, Typeable2 t)
285+ -> (forall d1 d2. (Data d1, Data d2) => c (t d1 d2))
287+ext2' def ext = maybe def id (dataCast2 ext)
289+-- | Type extension of queries for type constructors
290+ext2Q' :: (Data d, Typeable2 t)
292+ -> (forall d1 d2. (Data d1, Data d2) => t d1 d2 -> q)
294+ext2Q' def ext = unQ ((Q def) `ext2'` (Q ext))
296+-- | Type extension of readers for type constructors
297+ext2R' :: (Monad m, Data d, Typeable2 t)
299+ -> (forall d1 d2. (Data d1, Data d2) => m (t d1 d2))
301+ext2R' def ext = unR ((R def) `ext2'` (R ext))
303+-- | The type constructor for queries
304+newtype Q q x = Q { unQ :: x -> q }
306+-- | The type constructor for readers
307+newtype R m x = R { unR :: m x }