packages feed

aeson 0.2.0.0 → 0.3.0.0

raw patch · 5 files changed

+210/−63 lines, 5 filesdep +bytestring-showdep +hashabledep +unordered-containersdep ~timePVP ok

version bump matches the API change (PVP)

Dependencies added: bytestring-show, hashable, unordered-containers

Dependency ranges changed: time

API changes (from Hackage documentation)

+ Data.Aeson: fromDotNetTime :: DotNetTime -> UTCTime
+ Data.Aeson.Types: fromDotNetTime :: DotNetTime -> UTCTime
+ Data.Aeson.Types: instance [incoherent] FromJSON v => FromJSON (HashMap ByteString v)
+ Data.Aeson.Types: instance [incoherent] FromJSON v => FromJSON (HashMap String v)
+ Data.Aeson.Types: instance [incoherent] FromJSON v => FromJSON (HashMap Text v)
+ Data.Aeson.Types: instance [incoherent] FromJSON v => FromJSON (Map ByteString v)
+ Data.Aeson.Types: instance [incoherent] ToJSON v => ToJSON (HashMap ByteString v)
+ Data.Aeson.Types: instance [incoherent] ToJSON v => ToJSON (HashMap String v)
+ Data.Aeson.Types: instance [incoherent] ToJSON v => ToJSON (HashMap Text v)
+ Data.Aeson.Types: instance [incoherent] ToJSON v => ToJSON (Map ByteString v)

Files

Data/Aeson/Encode.hs view
@@ -18,19 +18,21 @@ import Blaze.ByteString.Builder import Blaze.ByteString.Builder.Char.Utf8 import Data.Aeson.Types (ToJSON(..), Value(..))+import Data.Attoparsec.Number (Number(..)) import Data.Monoid (mappend) import Numeric (showHex)-import qualified Data.ByteString.Char8 as B import qualified Data.ByteString.Lazy.Char8 as L import qualified Data.Map as M import qualified Data.Text as T import qualified Data.Vector as V+import qualified Text.Show.ByteString as S  -- | Encode a JSON value to a 'Builder'. fromValue :: Value -> Builder fromValue Null = fromByteString "null" fromValue (Bool b) = fromByteString $ if b then "true" else "false"-fromValue (Number n) = fromByteString (B.pack (show n))+fromValue (Number (I n)) = fromLazyByteString (S.show n)+fromValue (Number (D n)) = fromLazyByteString (S.show n) fromValue (String s) = string s fromValue (Array v)     | V.null v = fromByteString "[]"@@ -52,7 +54,7 @@   where     quote q = case T.uncons t of                 Just (c,t') -> fromText h `mappend` escape c `mappend` quote t'-                Nothing -> fromText h+                Nothing     -> fromText h         where (h,t) = T.break isEscape q     isEscape c = c == '\"' || c == '\\' || c < '\x20'     escape '\"' = fromByteString "\\\""
Data/Aeson/Functions.hs view
@@ -1,13 +1,49 @@ module Data.Aeson.Functions     (-      transformMap+      hashMap+    , mapHash+    , transformMap+    -- * String conversions+    , decode+    , strict+    , lazy     ) where -import Control.Arrow ((***))+import Control.Arrow ((***), first)+import Data.Hashable (Hashable)+import Data.Text (Text)+import Data.Text.Encoding (decodeUtf8, encodeUtf8)+import qualified Data.ByteString as B+import qualified Data.ByteString.Lazy as L+import qualified Data.HashMap.Strict as H import qualified Data.Map as M  -- | Transform one map into another.  The ordering of keys must be--- preserved.-transformMap :: (Ord k1, Ord k2) => (k1 -> k2) -> (v1 -> v2)+-- preserved by the key transformation function.+transformMap :: (Ord k2) => (k1 -> k2) -> (v1 -> v2)              -> M.Map k1 v1 -> M.Map k2 v2 transformMap fk fv = M.fromAscList . map (fk *** fv) . M.toAscList+{-# INLINE transformMap #-}++-- | Transform a 'H.HashMap' into a 'M.Map'.+hashMap :: (Ord k2) => (k1 -> k2) -> (v1 -> v2)+        -> H.HashMap k1 v1 -> M.Map k2 v2+hashMap fk kv = M.fromList . map (fk *** kv) . H.toList+{-# INLINE hashMap #-}++-- | Transform a 'M.Map' into a 'H.HashMap'.+mapHash :: (Eq k2, Hashable k2) => (k1 -> k2) -> M.Map k1 v -> H.HashMap k2 v+mapHash fk = H.fromList . map (first fk) . M.toList+{-# INLINE mapHash #-}++strict :: L.ByteString -> Text+strict = decode . B.concat . L.toChunks+{-# INLINE strict #-}++lazy :: Text -> L.ByteString+lazy = L.fromChunks . (:[]) . encodeUtf8+{-# INLINE lazy #-}++decode :: B.ByteString -> Text+decode = decodeUtf8+{-# INLINE decode #-}
Data/Aeson/Generic.hs view
@@ -1,4 +1,4 @@-{-# LANGUAGE PatternGuards #-}+{-# LANGUAGE PatternGuards, RankNTypes, ScopedTypeVariables  #-}  -- Module:      Data.Aeson.Generic -- Copyright:   (c) 2011 MailRank, Inc.@@ -22,22 +22,26 @@ import Control.Applicative ((<$>)) import Control.Arrow (first) import Control.Monad.State.Strict-import Data.Aeson.Functions (transformMap)+import Data.Aeson.Functions import Data.Aeson.Types hiding (FromJSON(..), ToJSON(..), fromJSON) import Data.Attoparsec.Number (Number) import Data.Generics import Data.Int (Int8, Int16, Int32, Int64) import Data.IntSet (IntSet)+import Data.Maybe (fromJust) import Data.Text (Text, pack, unpack)+import Data.Text.Encoding (encodeUtf8) import Data.Time.Clock (UTCTime) import Data.Word (Word, Word8, Word16, Word32, Word64) import qualified Data.Aeson.Types as T import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as L+import qualified Data.HashMap.Strict as H import qualified Data.Map as Map-import qualified Data.Traversable as T import qualified Data.Set as Set-import qualified Data.Text.Lazy as L+import qualified Data.Text as DT+import qualified Data.Text.Lazy as LT+import qualified Data.Traversable as T import qualified Data.Vector as V  type T a = a -> Value@@ -47,9 +51,8 @@          `ext1Q` list          `ext1Q` vector          `ext1Q` set-         `ext1Q` mapText-         `ext1Q` mapLazyText-         `ext1Q` mapString+         `ext2Q'` mapAny+         `ext2Q'` hashMapAny          -- Use the standard encoding for all base types.          `extQ` (T.toJSON :: T Integer)          `extQ` (T.toJSON :: T Int)@@ -68,7 +71,7 @@          `extQ` (T.toJSON :: T Rational)          `extQ` (T.toJSON :: T Char)          `extQ` (T.toJSON :: T Text)-         `extQ` (T.toJSON :: T L.Text)+         `extQ` (T.toJSON :: T LT.Text)          `extQ` (T.toJSON :: T String)          `extQ` (T.toJSON :: T B.ByteString)          `extQ` (T.toJSON :: T L.ByteString)@@ -83,10 +86,30 @@     list xs = Array . V.fromList . map toJSON $ xs     vector v = Array . V.map toJSON $ v     set s = Array . V.fromList . map toJSON . Set.toList $ s-    mapText m = Object . Map.map toJSON $ m-    mapLazyText m = Object . transformMap L.toStrict toJSON $ m-    mapString m = Object . transformMap pack toJSON $ m +    mapAny m+      | tyrep == typeOf DT.empty = remap id+      | tyrep == typeOf LT.empty = remap LT.toStrict+      | tyrep == typeOf ""       = remap pack+      | tyrep == typeOf B.empty  = remap decode+      | tyrep == typeOf L.empty  = remap strict+      | otherwise = modError "toJSON" $+                             "cannot convert map keyed by type " ++ show tyrep+      where tyrep = typeOf . head . Map.keys $ m+            remap f = Object . transformMap (f . fromJust . cast) toJSON $ m++    hashMapAny m+      | tyrep == typeOf DT.empty = remap id+      | tyrep == typeOf LT.empty = remap LT.toStrict+      | tyrep == typeOf ""       = remap pack+      | tyrep == typeOf B.empty  = remap decode+      | tyrep == typeOf L.empty  = remap strict+      | otherwise = modError "toJSON" $+                             "cannot convert map keyed by type " ++ show tyrep+      where tyrep = typeOf . head . H.keys $ m+            remap f = Object . hashMap (f . fromJust . cast) toJSON $ m++ toJSON_generic :: (Data a) => a -> Value toJSON_generic = generic   where@@ -104,8 +127,8 @@                 AlgRep _   -> encodeConstr (toConstr a) (gmapQ toJSON a)                 rep        -> err (dataTypeOf a) rep            where-              err dt r = error $ "Data.Aeson.Generic.toJSON: not AlgRep " ++-                                 show r ++ "(" ++ show dt ++ ")"+              err dt r = modError "toJSON" $ "not AlgRep " +++                                  show r ++ "(" ++ show dt ++ ")"         -- Encode nullary constructor as a string.         -- Encode non-nullary constructors as an object with the constructor         -- name as the single field and the arguments as the value.@@ -135,9 +158,8 @@ parseJSON j = parseJSON_generic j              `ext1R` list              `ext1R` vector-             `ext1R` mapText-             `ext1R` mapLazyText-             `ext1R` mapString+             `ext2R'` mapAny+             -- Don't know how to support parsing HashMaps :-(              -- Use the standard encoding for all base types.              `extR` (value :: F Integer)              `extR` (value :: F Int)@@ -156,7 +178,7 @@              `extR` (value :: F Rational)              `extR` (value :: F Char)              `extR` (value :: F Text)-             `extR` (value :: F L.Text)+             `extR` (value :: F LT.Text)              `extR` (value :: F String)              `extR` (value :: F B.ByteString)              `extR` (value :: F L.ByteString)@@ -174,15 +196,27 @@     vector :: (Data a) => Parser (V.Vector a)     vector = case j of                Array js -> V.mapM parseJSON js-               _        -> modFail "parseJSON" $ "bad data: " ++ show j-    mapText :: (Data a) => Parser (Map.Map Text a)-    mapText = case j of-                Object js -> T.mapM parseJSON js-                _         -> modFail "parseJSON" $ "bad data: " ++ show j-    mapLazyText :: (Data a) => Parser (Map.Map L.Text a)-    mapLazyText = Map.mapKeysMonotonic L.fromStrict <$> parseJSON j-    mapString :: (Data a) => Parser (Map.Map String a)-    mapString = Map.mapKeysMonotonic unpack <$> parseJSON j+               _        -> myFail+    mapAny :: forall e f. (Data e, Data f) => Parser (Map.Map f e)+    mapAny+        | tyrep `elem` stringyTypes = res+        | otherwise = myFail+      where res = case j of+                Object js -> Map.mapKeysMonotonic trans <$> T.mapM parseJSON js+                _         -> myFail+            trans+               | tyrep == typeOf DT.empty = remap id+               | tyrep == typeOf LT.empty = remap LT.fromStrict+               | tyrep == typeOf ""       = remap DT.unpack+               | tyrep == typeOf B.empty  = remap encodeUtf8+               | tyrep == typeOf L.empty  = remap lazy+               | otherwise = modError "parseJSON"+                                      "mapAny -- should never happen"+            tyrep = typeOf (undefined :: f)+            remap f = fromJust . cast . f+    myFail = modFail "parseJSON" $ "bad data: " ++ show j+    stringyTypes = [typeOf LT.empty, typeOf DT.empty, typeOf B.empty, +                    typeOf L.empty, typeOf ""]  parseJSON_generic :: (Data a) => Value -> Parser a parseJSON_generic j = generic@@ -190,7 +224,7 @@         typ = dataTypeOf $ resType generic         generic = case dataTypeRep typ of                     AlgRep []  -> case j of-                                    Null -> return (error "Empty type")+                                    Null -> return (modError "parseJSON" "empty type")                                     _ -> modFail "parseJSON" "no-constr bad data"                     AlgRep [_] -> decodeArgs (indexConstr typ 1) j                     AlgRep _   -> do (c, j') <- getConstr typ j; decodeArgs c j'@@ -202,10 +236,10 @@         getConstr t (String js) = do c <- readConstr' t (unpack js)                                      return (c, Null) -- handle nullary ctor         getConstr _ _ = modFail "parseJSON" "bad constructor encoding"-        readConstr' t s = -	  maybe (modFail "parseJSON" $ "unknown constructor: " ++ s ++ " " ++-                         show t) -	        return $ readConstr t s+        readConstr' t s =+          maybe (modFail "parseJSON" $ "unknown constructor: " ++ s ++ " " +++                         show t)+                return $ readConstr t s          decodeArgs c0 = go (numConstrArgs (resType generic) c0) c0                            (constrFields c0)@@ -243,7 +277,40 @@           where f = do modify (+1); return undefined          resType :: MonadPlus m => m a -> a-        resType _ = error "resType"+        resType _ = modError "parseJSON" "resType"  modFail :: (Monad m) => String -> String -> m a modFail func err = fail $ "Data.Aeson.Generic." ++ func ++ ": " ++ err++modError :: String -> String -> a+modError func err = error $ "Data.Aeson.Generic." ++ func ++ ": " ++ err+++-- Type extension for binary type constructors.++-- | Flexible type extension+ext2' :: (Data a, Typeable2 t)+     => c a+     -> (forall d1 d2. (Data d1, Data d2) => c (t d1 d2))+     -> c a+ext2' def ext = maybe def id (dataCast2 ext)++-- | Type extension of queries for type constructors+ext2Q' :: (Data d, Typeable2 t)+      => (d -> q)+      -> (forall d1 d2. (Data d1, Data d2) => t d1 d2 -> q)+      -> d -> q+ext2Q' def ext = unQ ((Q def) `ext2'` (Q ext))++-- | Type extension of readers for type constructors+ext2R' :: (Monad m, Data d, Typeable2 t)+      => m d+      -> (forall d1 d2. (Data d1, Data d2) => m (t d1 d2))+      -> m d+ext2R' def ext = unR ((R def) `ext2'` (R ext))++-- | The type constructor for queries+newtype Q q x = Q { unQ :: x -> q }++-- | The type constructor for readers+newtype R m x = R { unR :: m x }
Data/Aeson/Types.hs view
@@ -36,33 +36,34 @@     ) where  import Control.Applicative-import Control.Monad (MonadPlus(..))-import Data.Monoid (Monoid(..)) import Control.DeepSeq (NFData(..))+import Control.Monad (MonadPlus(..))+import Data.Aeson.Functions+import Data.Attoparsec.Char8 (Number(..)) import Data.Data (Data) import Data.Int (Int8, Int16, Int32, Int64)-import qualified Data.IntSet as IntSet import Data.Map (Map) import Data.Monoid (Dual(..), First(..), Last(..))+import Data.Monoid (Monoid(..)) import Data.Ratio (Ratio) import Data.String (IsString(..)) import Data.Text (Text, pack, unpack)-import Data.Text.Encoding (decodeUtf8, encodeUtf8)+import Data.Text.Encoding (encodeUtf8) import Data.Time.Clock (UTCTime) import Data.Time.Format (FormatTime, formatTime, parseTime)-import Data.Attoparsec.Char8 (Number(..)) import Data.Typeable (Typeable) import Data.Vector (Vector) import Data.Word (Word, Word8, Word16, Word32, Word64) import System.Locale (defaultTimeLocale) import qualified Data.ByteString as B import qualified Data.ByteString.Lazy as LB+import qualified Data.HashMap.Strict as H+import qualified Data.IntSet as IntSet import qualified Data.Map as M import qualified Data.Set as Set import qualified Data.Text as T import qualified Data.Text.Lazy as LT import qualified Data.Vector as V-import Data.Aeson.Functions  -- | The result of running a 'Parser'. data Result a = Error String@@ -457,7 +458,7 @@     {-# INLINE parseJSON #-}  instance ToJSON B.ByteString where-    toJSON = String . decodeUtf8+    toJSON = String . decode     {-# INLINE toJSON #-}  instance FromJSON B.ByteString where@@ -466,11 +467,11 @@     {-# INLINE parseJSON #-}  instance ToJSON LB.ByteString where-    toJSON = toJSON . B.concat . LB.toChunks+    toJSON = toJSON . strict     {-# INLINE toJSON #-}  instance FromJSON LB.ByteString where-    parseJSON (String t) = pure . LB.fromChunks . (:[]) . encodeUtf8 $ t+    parseJSON (String t) = pure . lazy $ t     parseJSON _          = empty     {-# INLINE parseJSON #-} @@ -479,7 +480,7 @@     {-# INLINE toJSON #-}      instance (FromJSON a) => FromJSON [a] where-    parseJSON (Array a) = mapA parseJSON (V.toList a)+    parseJSON (Array a) = mapM parseJSON (V.toList a)     parseJSON _         = empty     {-# INLINE parseJSON #-} @@ -488,7 +489,7 @@     {-# INLINE toJSON #-}      instance (FromJSON a) => FromJSON (Vector a) where-    parseJSON (Array a) = V.fromList <$> mapA parseJSON (V.toList a)+    parseJSON (Array a) = V.mapM parseJSON a     parseJSON _         = empty     {-# INLINE parseJSON #-} @@ -513,10 +514,8 @@     {-# INLINE toJSON #-}  instance (FromJSON v) => FromJSON (M.Map Text v) where-    parseJSON (Object o) = M.fromAscList <$> go (M.toAscList o)-      where-        go ((k,v):kvs)  = ((:) . (,) k) <$> parseJSON v <*> go kvs-        go _            = pure []+    parseJSON (Object o) = M.fromAscList <$> mapM go (M.toAscList o)+      where go (k,v)     = ((,) k) <$> parseJSON v     parseJSON _          = empty  instance (ToJSON v) => ToJSON (M.Map LT.Text v) where@@ -531,6 +530,51 @@ instance (FromJSON v) => FromJSON (M.Map String v) where     parseJSON = fmap (M.mapKeysMonotonic unpack) . parseJSON +instance (ToJSON v) => ToJSON (M.Map B.ByteString v) where+    toJSON = Object . transformMap decode toJSON++instance (FromJSON v) => FromJSON (M.Map B.ByteString v) where+    parseJSON = fmap (M.mapKeysMonotonic encodeUtf8) . parseJSON++instance (ToJSON v) => ToJSON (M.Map LB.ByteString v) where+    toJSON = Object . transformMap strict toJSON++instance (FromJSON v) => FromJSON (M.Map LB.ByteString v) where+    parseJSON = fmap (M.mapKeysMonotonic lazy) . parseJSON++instance (ToJSON v) => ToJSON (H.HashMap Text v) where+    toJSON = Object . hashMap id toJSON+    {-# INLINE toJSON #-}++instance (FromJSON v) => FromJSON (H.HashMap Text v) where+    parseJSON (Object o) = H.fromList <$> mapM go (M.toList o)+      where go (k,v)     = ((,) k) <$> parseJSON v+    parseJSON _          = empty++instance (ToJSON v) => ToJSON (H.HashMap LT.Text v) where+    toJSON = Object . M.fromList . H.foldrWithKey (\k v -> ((LT.toStrict k,toJSON v) :)) []++instance (FromJSON v) => FromJSON (H.HashMap LT.Text v) where+    parseJSON = fmap (mapHash LT.fromStrict) . parseJSON++instance (ToJSON v) => ToJSON (H.HashMap String v) where+    toJSON = Object . hashMap pack toJSON++instance (FromJSON v) => FromJSON (H.HashMap String v) where+    parseJSON = fmap (mapHash unpack) . parseJSON++instance (ToJSON v) => ToJSON (H.HashMap B.ByteString v) where+    toJSON = Object . hashMap decode toJSON++instance (FromJSON v) => FromJSON (H.HashMap B.ByteString v) where+    parseJSON = fmap (mapHash encodeUtf8) . parseJSON++instance (ToJSON v) => ToJSON (H.HashMap LB.ByteString v) where+    toJSON = Object . hashMap strict toJSON++instance (FromJSON v) => FromJSON (H.HashMap LB.ByteString v) where+    parseJSON = fmap (mapHash lazy) . parseJSON+ instance ToJSON Value where     toJSON a = a     {-# INLINE toJSON #-}@@ -541,8 +585,9 @@  -- | A newtype wrapper for 'UTCTime' that uses the same non-standard -- serialization format as Microsoft .NET.-newtype DotNetTime = DotNetTime UTCTime-    deriving (Eq, Ord, Read, Show, Typeable, FormatTime)+newtype DotNetTime = DotNetTime {+      fromDotNetTime :: UTCTime+    } deriving (Eq, Ord, Read, Show, Typeable, FormatTime)  instance ToJSON DotNetTime where     toJSON (DotNetTime t) =@@ -603,9 +648,3 @@ instance FromJSON a => FromJSON (Last a) where     parseJSON = fmap Last . parseJSON     {-# INLINE parseJSON #-}--mapA :: (Alternative m) => (t -> m a) -> [t] -> m [a]-mapA f = go-  where-    go (a:as) = (:) <$> f a <*> go as-    go _      = pure []
aeson.cabal view
@@ -1,5 +1,5 @@ name:            aeson-version:         0.2.0.0+version:         0.3.0.0 license:         BSD3 license-file:    LICENSE category:        Text, Web, JSON@@ -90,13 +90,16 @@     base == 4.*,     blaze-builder >= 0.2.1.4,     bytestring,+    bytestring-show,     containers,     deepseq,+    hashable,     monads-fd,     old-locale,     syb,     text >= 0.11.0.2,     time,+    unordered-containers >= 0.1.2.0,     vector >= 0.7    if flag(developer)