on master help sign in
Don't use Builder in ToJSON.hs
commit5788284b8073625d6baca37a9ebc2bcff8538c96 authorOleg Grenrus <oleg.grenrus@iki.fi> dateWed 8 Jun 2016, 11:44 (10 years ago) parent052b997
3 files changed+96−58
Data/Aeson/Encoding.hs+13 Data/Aeson/Encoding/Internal.hs+54−1 Data/Aeson/Types/ToJSON.hs+29−57
Data/Aeson/Encoding.hs+13
@@ -6,12 +6,15 @@ module Data.Aeson.Encoding
66 , unsafeToEncoding
77 , Series
88 , pairs
9+ , pair
910 -- * Predicates
1011 , nullEncoding
1112 -- * Encoding constructors
1213 , emptyArray_
1314 , emptyObject_
1415 , text
16+ , lazyText
17+ , string
1518 , list
1619 , dict
1720 , null_
@@ -25,6 +28,16 @@ module Data.Aeson.Encoding
2528 , int8Text, int16Text, int32Text, int64Text, intText
2629 , word8Text, word16Text, word32Text, word64Text, wordText
2730 , integerText, floatText, doubleText, scientificText
31+
32+ -- ** Time
33+ , day
34+ , localTime
35+ , utcTime
36+ , timeOfDay
37+ , zonedTime
38+
39+ -- ** value
40+ , value
2841 ) where
2942
3043import Data.Aeson.Encoding.Internal
Data/Aeson/Encoding/Internal.hs+54−1
@@ -1,7 +1,7 @@
11{-# LANGUAGE DeriveDataTypeable #-}
22{-# LANGUAGE GeneralizedNewtypeDeriving #-}
3−{-# LANGUAGE RankNTypes #-}
43{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE RankNTypes #-}
55module Data.Aeson.Encoding.Internal
66 (
77 -- * Encoding
@@ -9,6 +9,7 @@ module Data.Aeson.Encoding.Internal
99 , unsafeToEncoding
1010 , Series (..) -- TODO: don't export constructor
1111 , pairs
12+ , pair
1213 -- * Predicates
1314 , nullEncoding
1415 -- * Encoding constructors
@@ -19,6 +20,8 @@ module Data.Aeson.Encoding.Internal
1920 , null_
2021 , bool
2122 , text
23+ , lazyText
24+ , string
2225 , list
2326 , dict
2427 , tuple
@@ -31,6 +34,14 @@ module Data.Aeson.Encoding.Internal
3134 , int8Text, int16Text, int32Text, int64Text, intText
3235 , word8Text, word16Text, word32Text, word64Text, wordText
3336 , integerText, floatText, doubleText, scientificText
37+ -- ** Time
38+ , day
39+ , localTime
40+ , utcTime
41+ , timeOfDay
42+ , zonedTime
43+ -- ** value
44+ , value
3445 -- ** JSON tokens
3546 , comma, colon, openBracket, closeBracket, openCurly, closeCurly
3647 ) where
@@ -44,12 +55,17 @@ import Data.Int
4455import Data.Scientific (Scientific)
4556import Data.Semigroup (Semigroup ((<>)))
4657import Data.Text (Text)
58+import Data.Time (Day, LocalTime, TimeOfDay, UTCTime,
59+ ZonedTime)
4760import Data.Typeable (Typeable)
4861import Data.Word
4962
63+import Data.Aeson.Types.Internal (Value)
64+
5065import qualified Data.Aeson.Encode.Builder as EB
5166import qualified Data.ByteString.Builder as B
5267import qualified Data.ByteString.Lazy as BSL
68+import qualified Data.Text.Lazy as LT
5369
5470-- | An encoding of a JSON value.
5571newtype Encoding = Encoding {
@@ -89,6 +105,9 @@ data Series = Empty
89105 | Value Encoding
90106 deriving (Typeable)
91107
108+pair :: Text -> Encoding -> Series
109+pair name val = Value $ text name <> colon <> val
110+
92111instance Semigroup Series where
93112 Empty <> a = a
94113 Value a <> b =
@@ -174,6 +193,14 @@ tuple b = Encoding (char7 '[' <> fromEncoding b <> char7 ']')
174193text :: Text -> Encoding
175194text = Encoding . EB.text
176195
196+lazyText :: LT.Text -> Encoding
197+lazyText t = Encoding $
198+ B.char7 '"' <>
199+ LT.foldrChunks (\x xs -> EB.unquoted x <> xs) (B.char7 '"') t
200+
201+string :: String -> Encoding
202+string = Encoding . EB.string
203+
177204-------------------------------------------------------------------------------
178205-- chars
179206-------------------------------------------------------------------------------
@@ -284,3 +311,29 @@ doubleText = Encoding . EB.quote . B.doubleDec
284311
285312scientificText :: Scientific -> Encoding
286313scientificText = Encoding . EB.quote . EB.scientific
314+
315+-------------------------------------------------------------------------------
316+-- time
317+-------------------------------------------------------------------------------
318+
319+day :: Day -> Encoding
320+day = Encoding . EB.quote . EB.day
321+
322+localTime :: LocalTime -> Encoding
323+localTime = Encoding . EB.quote . EB.localTime
324+
325+utcTime :: UTCTime -> Encoding
326+utcTime = Encoding . EB.quote . EB.utcTime
327+
328+timeOfDay :: TimeOfDay -> Encoding
329+timeOfDay = Encoding . EB.quote . EB.timeOfDay
330+
331+zonedTime :: ZonedTime -> Encoding
332+zonedTime = Encoding . EB.quote . EB.zonedTime
333+
334+-------------------------------------------------------------------------------
335+-- Value
336+-------------------------------------------------------------------------------
337+
338+value :: Value -> Encoding
339+value = Encoding . EB.encodeToBuilder
Data/Aeson/Types/ToJSON.hs+29−57
@@ -61,7 +61,7 @@ import Data.Aeson.Functions (mapHashKeyVal, mapKeyVal)
6161import Data.Aeson.Types.Generic
6262import Data.Aeson.Types.Internal
6363
64−import qualified Data.Aeson.Encode.Builder as EB
64+-- We need internal here for generic deriving
6565import qualified Data.Aeson.Encoding.Internal as E
6666
6767import Control.Applicative (Const (..))
@@ -92,7 +92,7 @@ import Foreign.Storable (Storable)
9292import GHC.Generics
9393import Numeric.Natural (Natural)
9494
95−import qualified Data.ByteString.Builder as B
95+import qualified Data.ByteString.Builder as B (toLazyByteString)
9696import qualified Data.ByteString.Lazy as L
9797import qualified Data.DList as DList
9898import qualified Data.HashMap.Strict as H
@@ -115,9 +115,6 @@ import qualified Data.Vector.Primitive as VP
115115import qualified Data.Vector.Storable as VS
116116import qualified Data.Vector.Unboxed as VU
117117
118−builder :: ToJSON a => a -> B.Builder
119−builder = fromEncoding . toEncoding
120−
121118toJSONPair :: (a -> Value) -> (b -> Value) -> (a, b) -> Value
122119toJSONPair keySerialiser valSerializer (a, b) = Array $ V.create $ do
123120 mv <- VM.unsafeNew 2
@@ -278,7 +275,7 @@ class ToJSON a where
278275 -- @
279276
280277 toEncoding :: a -> Encoding
281− toEncoding = E.Encoding . EB.encodeToBuilder . toJSON
278+ toEncoding = E.value . toJSON
282279 {-# INLINE toEncoding #-}
283280
284281 toJSONList :: [a] -> Value
@@ -299,7 +296,7 @@ class KeyValue kv where
299296 infixr 8 .=
300297
301298instance KeyValue Series where
302− name .= value = E.Value $ E.text name <> E.colon <> toEncoding value
299+ name .= value = E.pair name (toEncoding value)
303300 {-# INLINE (.=) #-}
304301
305302instance KeyValue Pair where
@@ -1081,7 +1078,7 @@ instance ToJSON1 Maybe where
10811078 {-# INLINE liftToJSON #-}
10821079
10831080 liftToEncoding t _ (Just a) = t a
1084− liftToEncoding _ _ Nothing = Encoding EB.null_
1081+ liftToEncoding _ _ Nothing = E.null_
10851082 {-# INLINE liftToEncoding #-}
10861083
10871084instance (ToJSON a) => ToJSON (Maybe a) where
@@ -1097,15 +1094,9 @@ instance ToJSON2 Either where
10971094 liftToJSON2 _toA _ toB _ (Right b) = Object $ H.singleton right (toB b)
10981095 {-# INLINE liftToJSON2 #-}
10991096
1100− liftToEncoding2 toA _ _toB _ (Left a) =
1101− Encoding (B.shortByteString "{\"Left\":")
1102− <> toA a
1103− <> Encoding (B.char7 '}')
1097+ liftToEncoding2 toA _ _toB _ (Left a) = E.pairs $ E.pair "Left" $ toA a
11041098
1105− liftToEncoding2 _toA _ toB _ (Right b) =
1106− Encoding (B.shortByteString "{\"Right\":")
1107− <> toB b
1108− <> Encoding (B.char7 '}')
1099+ liftToEncoding2 _toA _ toB _ (Right b) = E.pairs $ E.pair "Right" $ toB b
11091100 {-# INLINE liftToEncoding2 #-}
11101101
11111102instance (ToJSON a) => ToJSON1 (Either a) where
@@ -1166,10 +1157,10 @@ instance ToJSON Char where
11661157 toJSONList = String . T.pack
11671158 {-# INLINE toJSONList #-}
11681159
1169− toEncoding = Encoding . EB.string . (:[])
1160+ toEncoding = E.string . (:[])
11701161 {-# INLINE toEncoding #-}
11711162
1172− toEncodingList = Encoding . EB.string
1163+ toEncodingList = E.string
11731164 {-# INLINE toEncodingList #-}
11741165
11751166
@@ -1390,9 +1381,7 @@ instance ToJSON LT.Text where
13901381 toJSON = String . LT.toStrict
13911382 {-# INLINE toJSON #-}
13921383
1393− toEncoding t = Encoding $
1394− B.char7 '"' <>
1395− LT.foldrChunks (\x xs -> EB.unquoted x <> xs) (B.char7 '"') t
1384+ toEncoding = E.lazyText
13961385 {-# INLINE toEncoding #-}
13971386
13981387instance ToJSON Version where
@@ -1402,7 +1391,6 @@ instance ToJSON Version where
14021391 toEncoding = toEncoding . showVersion
14031392 {-# INLINE toEncoding #-}
14041393
1405−
14061394-------------------------------------------------------------------------------
14071395-- semigroups NonEmpty
14081396-------------------------------------------------------------------------------
@@ -1575,13 +1563,7 @@ instance ToJSON1 Vector where
15751563 liftToJSON t _ = Array . V.map t
15761564 {-# INLINE liftToJSON #-}
15771565
1578− liftToEncoding t _ xs
1579− | V.null xs = emptyArray_
1580− | otherwise = Encoding $
1581− B.char7 '[' <> fromEncoding (t (V.unsafeHead xs)) <>
1582− V.foldr go (B.char7 ']') (V.unsafeTail xs)
1583− where
1584− go v b = B.char7 ',' <> fromEncoding (t v) <> b
1566+ liftToEncoding t _ = listEncoding t . V.toList
15851567 {-# INLINE liftToEncoding #-}
15861568
15871569instance (ToJSON a) => ToJSON (Vector a) where
@@ -1592,12 +1574,7 @@ instance (ToJSON a) => ToJSON (Vector a) where
15921574 {-# INLINE toEncoding #-}
15931575
15941576encodeVector :: (ToJSON a, VG.Vector v a) => v a -> Encoding
1595−encodeVector xs
1596− | VG.null xs = emptyArray_
1597− | otherwise = Encoding $
1598− B.char7 '[' <> builder (VG.unsafeHead xs) <>
1599− VG.foldr go (B.char7 ']') (VG.unsafeTail xs)
1600− where go v b = B.char7 ',' <> builder v <> b
1577+encodeVector = listEncoding toEncoding . VG.toList
16011578{-# INLINE encodeVector #-}
16021579
16031580vectorToJSON :: (VG.Vector v a, ToJSON a) => v a -> Value
@@ -1676,7 +1653,7 @@ instance ToJSON Value where
16761653 toJSON a = a
16771654 {-# INLINE toJSON #-}
16781655
1679− toEncoding = Encoding . EB.encodeToBuilder
1656+ toEncoding = E.value
16801657 {-# INLINE toEncoding #-}
16811658
16821659instance ToJSON DotNetTime where
@@ -1688,55 +1665,50 @@ dotNetTime :: DotNetTime -> String
16881665dotNetTime (DotNetTime t) = secs ++ formatMillis t ++ ")/"
16891666 where secs = formatTime defaultTimeLocale "/Date(%s" t
16901667
1668+formatMillis :: (FormatTime t) => t -> String
1669+formatMillis = take 3 . formatTime defaultTimeLocale "%q"
1670+
16911671-------------------------------------------------------------------------------
16921672-- time
16931673-------------------------------------------------------------------------------
16941674
16951675instance ToJSON Day where
1696− toJSON = stringEncoding
1697− toEncoding z = Encoding (EB.quote $ EB.day z)
1676+ toJSON = stringEncoding . E.day
1677+ toEncoding = E.day
16981678
16991679
17001680instance ToJSON TimeOfDay where
1701− toJSON = stringEncoding
1702− toEncoding z = Encoding (EB.quote $ EB.timeOfDay z)
1681+ toJSON = stringEncoding . E.timeOfDay
1682+ toEncoding = E.timeOfDay
17031683
17041684
17051685instance ToJSON LocalTime where
1706− toJSON = stringEncoding
1707− toEncoding z = Encoding (EB.quote $ EB.localTime z)
1686+ toJSON = stringEncoding . E.localTime
1687+ toEncoding = E.localTime
17081688
17091689instance ToJSON ZonedTime where
1710− toJSON = stringEncoding
1711−
1712− toEncoding z = Encoding (EB.quote $ EB.zonedTime z)
1713−
1714−formatMillis :: (FormatTime t) => t -> String
1715−formatMillis = take 3 . formatTime defaultTimeLocale "%q"
1690+ toJSON = stringEncoding . E.zonedTime
1691+ toEncoding = E.zonedTime
17161692
17171693instance ToJSON UTCTime where
1718− toJSON = stringEncoding
1719−
1720− toEncoding t = Encoding (EB.quote $ EB.utcTime t)
1694+ toJSON = stringEncoding . E.utcTime
1695+ toEncoding = E.utcTime
17211696
17221697-- | Encode something t a JSON string.
1723−--
1724−-- TODO: remove me, this is a hack
1725−stringEncoding :: (ToJSON a) => a -> Value
1698+stringEncoding :: Encoding -> Value
17261699stringEncoding = String
17271700 . T.dropAround (== '"')
17281701 . T.decodeLatin1
17291702 . L.toStrict
17301703 . B.toLazyByteString
17311704 . fromEncoding
1732− . toEncoding
17331705{-# INLINE stringEncoding #-}
17341706
17351707instance ToJSON NominalDiffTime where
17361708 toJSON = Number . realToFrac
17371709 {-# INLINE toJSON #-}
17381710
1739− toEncoding = Encoding . EB.scientific . realToFrac
1711+ toEncoding = E.scientific . realToFrac
17401712 {-# INLINE toEncoding #-}
17411713
17421714-------------------------------------------------------------------------------
@@ -1795,7 +1767,7 @@ instance ToJSON (Proxy a) where
17951767 toJSON _ = Null
17961768 {-# INLINE toJSON #-}
17971769
1798− toEncoding _ = Encoding EB.null_
1770+ toEncoding _ = E.null_
17991771 {-# INLINE toEncoding #-}
18001772
18011773