on master help sign in
Let there be type safety for direct encoding!
commit10a76ea8077d167ce2c4e5f43da7bc2b6fbfdaf5 authorBryan O'Sullivan <bos@serpentine.com> dateTue 26 May 2015, 16:44 (11 years ago) parente8fbbe9
7 files changed+246−217
Data/Aeson.hs+2 Data/Aeson/Encode/ByteString.hs+10−9 Data/Aeson/Types.hs+1 Data/Aeson/Types/Generic.hs+24−22 Data/Aeson/Types/Instances.hs+202−181 Data/Aeson/Types/Internal.hs+6−4 benchmarks/Typed/Manual.hs+1−1
Data/Aeson.hs+2
@@ -45,6 +45,8 @@ module Data.Aeson
4545 , eitherDecodeStrict'
4646 -- * Core JSON types
4747 , Value(..)
48+ , Encoding
49+ , fromEncoding
4850 , Array
4951 , Object
5052 -- * Convenience types
Data/Aeson/Encode/ByteString.hs+10−9
@@ -34,7 +34,7 @@ module Data.Aeson.Encode.ByteString
3434 ) where
3535
3636import Data.Aeson.Types.Class (ToJSON(..))
37−import Data.Aeson.Types.Internal (Value(..), Series(..))
37+import Data.Aeson.Types.Internal (Encoding(..), Series(..), Value(..))
3838import Data.ByteString.Builder as B
3939import Data.ByteString.Builder.Prim as BP
4040import Data.ByteString.Builder.Scientific (scientificBuilder)
@@ -128,18 +128,19 @@ number s
128128 where
129129 e = base10Exponent s
130130
131−foldable :: (Foldable t, ToJSON a) => t a -> Builder
131+foldable :: (Foldable t, ToJSON a) => t a -> Encoding
132132foldable = series '[' ']' . foldMap (Value . toEncoding)
133133
134−series :: Char -> Char -> Series -> Builder
135−series begin end (Value v) = B.char7 begin <> v <> B.char7 end
136−series begin end Empty = BP.primBounded (ascii2 (begin,end)) ()
134+series :: Char -> Char -> Series -> Encoding
135+series begin end (Value v) = Encoding $
136+ B.char7 begin <> fromEncoding v <> B.char7 end
137+series begin end Empty = Encoding (BP.primBounded (ascii2 (begin,end)) ())
137138
138−emptyArray_ :: Builder
139−emptyArray_ = BP.primBounded (ascii2 ('[',']')) ()
139+emptyArray_ :: Encoding
140+emptyArray_ = Encoding (BP.primBounded (ascii2 ('[',']')) ())
140141
141−emptyObject_ :: Builder
142−emptyObject_ = BP.primBounded (ascii2 ('{','}')) ()
142+emptyObject_ :: Encoding
143+emptyObject_ = Encoding (BP.primBounded (ascii2 ('{','}')) ())
143144
144145ascii2 :: (Char, Char) -> BP.BoundedPrim a
145146ascii2 cs = BP.liftFixedToBounded $ (const cs) BP.>$< BP.char7 >*< BP.char7
Data/Aeson/Types.hs+1
@@ -14,6 +14,7 @@ module Data.Aeson.Types
1414 -- * Core JSON types
1515 Value(..)
1616 , Encoding
17+ , fromEncoding
1718 , Array
1819 , emptyArray
1920 , Pair
Data/Aeson/Types/Generic.hs+24−22
@@ -69,7 +69,7 @@ instance (ConsToJSON a) => GToJSON (C1 c a) where
6969 gToJSON opts = consToJSON opts . unM1
7070 {-# INLINE gToJSON #-}
7171
72− gToEncoding opts = consToEncoding opts . unM1
72+ gToEncoding opts = Encoding . consToEncoding opts . unM1
7373 {-# INLINE gToEncoding #-}
7474
7575instance ( WriteProduct a, WriteProduct b
@@ -87,7 +87,8 @@ instance ( WriteProduct a, WriteProduct b
8787 productSize
8888 {-# INLINE gToJSON #-}
8989
90− gToEncoding opts p = B.char7 '[' <> encodeProduct opts p <> B.char7 ']'
90+ gToEncoding opts p = Encoding $
91+ B.char7 '[' <> encodeProduct opts p <> B.char7 ']'
9192
9293instance ( AllNullary (a :+: b) allNullary
9394 , SumToJSON (a :+: b) allNullary ) => GToJSON (a :+: b) where
@@ -98,8 +99,9 @@ instance ( AllNullary (a :+: b) allNullary
9899 . sumToJSON opts
99100 {-# INLINE gToJSON #-}
100101
101− gToEncoding opts = (unTagged :: Tagged allNullary B.Builder -> B.Builder)
102− . sumToEncoding opts
102+ gToEncoding opts = Encoding .
103+ (unTagged :: Tagged allNullary B.Builder -> B.Builder) .
104+ sumToEncoding opts
103105 {-# INLINE gToEncoding #-}
104106
105107--------------------------------------------------------------------------------
@@ -119,7 +121,7 @@ instance ( GetConName f
119121 {-# INLINE sumToJSON #-}
120122
121123 sumToEncoding opts
122− | allNullaryToStringTag opts = Tagged . toEncoding .
124+ | allNullaryToStringTag opts = Tagged . builder .
123125 constructorTagModifier opts . getConName
124126 | otherwise = Tagged . nonAllNullarySumToEncoding opts
125127 {-# INLINE sumToEncoding #-}
@@ -188,9 +190,9 @@ instance ( IsRecord a isRecord
188190
189191 taggedObjectEnc opts tagFieldName contentsFieldName v =
190192 B.char7 '{' <>
191− (toEncoding tagFieldName <>
193+ (builder tagFieldName <>
192194 B.char7 ':' <>
193− toEncoding (constructorTagModifier opts (conName (undefined :: t c a p)))) <>
195+ builder (constructorTagModifier opts (conName (undefined :: t c a p)))) <>
194196 B.char7 ',' <>
195197 ((unTagged :: Tagged isRecord B.Builder -> B.Builder) .
196198 taggedObjectEnc' opts contentsFieldName . unM1 $ v) <>
@@ -214,8 +216,8 @@ instance (GToJSON f) => TaggedObject' f False where
214216 {-# INLINE taggedObjectPairs' #-}
215217
216218 taggedObjectEnc' opts contentsFieldName =
217− Tagged . (\z -> toEncoding contentsFieldName <> B.char7 ':' <> z) .
218− gToEncoding opts
219+ Tagged . (\z -> builder contentsFieldName <> B.char7 ':' <> z) .
220+ gbuilder opts
219221 {-# INLINE taggedObjectEnc' #-}
220222
221223--------------------------------------------------------------------------------
@@ -258,12 +260,9 @@ instance ( GToJSON a, ConsToJSON a
258260 return mv
259261 {-# INLINE twoElemArrayObj #-}
260262
261− twoElemArrayEnc opts x =
262− B.char7 '[' <>
263− toEncoding (constructorTagModifier opts (conName (undefined :: t c a p))) <>
264− B.char7 ',' <>
265− gToEncoding opts x <>
266− B.char7 ']'
263+ twoElemArrayEnc opts x = fromEncoding . tuple $
264+ builder (constructorTagModifier opts (conName (undefined :: t c a p))) >*<
265+ gbuilder opts x
267266 {-# INLINE twoElemArrayEnc #-}
268267
269268--------------------------------------------------------------------------------
@@ -299,7 +298,7 @@ instance (RecordTo f) => ConsToJSON' f True where
299298instance GToJSON f => ConsToJSON' f False where
300299 consToJSON' opts = Tagged . gToJSON opts
301300 {-# INLINE consToJSON' #-}
302− consToEncoding' opts = Tagged . gToEncoding opts
301+ consToEncoding' opts = Tagged . gbuilder opts
303302 {-# INLINE consToEncoding' #-}
304303
305304--------------------------------------------------------------------------------
@@ -344,9 +343,9 @@ fieldToPair opts m1 = pure ( pack $ fieldLabelModifier opts $ selName m1
344343
345344fieldToEncoding :: (Selector s, GToJSON a) => Options -> S1 s a p -> B.Builder
346345fieldToEncoding opts m1 =
347− toEncoding (fieldLabelModifier opts $ selName m1) <>
346+ builder (fieldLabelModifier opts $ selName m1) <>
348347 B.char7 ':' <>
349− gToEncoding opts (unM1 m1)
348+ gbuilder opts (unM1 m1)
350349{-# INLINE fieldToEncoding #-}
351350
352351--------------------------------------------------------------------------------
@@ -380,7 +379,7 @@ instance (GToJSON a) => WriteProduct a where
380379 writeProduct opts mv ix _ = VM.unsafeWrite mv ix . gToJSON opts
381380 {-# INLINE writeProduct #-}
382381
383− encodeProduct opts = gToEncoding opts
382+ encodeProduct opts = gbuilder opts
384383 {-# INLINE encodeProduct #-}
385384
386385--------------------------------------------------------------------------------
@@ -409,13 +408,16 @@ instance ( GToJSON a, ConsToJSON a
409408
410409 objectWithSingleFieldEnc opts v =
411410 B.char7 '{' <>
412− toEncoding (constructorTagModifier opts
413− (conName (undefined :: t c a p))) <>
411+ builder (constructorTagModifier opts
412+ (conName (undefined :: t c a p))) <>
414413 B.char7 ':' <>
415− gToEncoding opts v <>
414+ gbuilder opts v <>
416415 B.char7 '}'
417416 {-# INLINE objectWithSingleFieldEnc #-}
418417
418+gbuilder :: GToJSON f => Options -> f a -> Builder
419+gbuilder opts = fromEncoding . gToEncoding opts
420+
419421--------------------------------------------------------------------------------
420422-- Generic parseJSON
421423
Data/Aeson/Types/Instances.hs+202−181
@@ -47,14 +47,16 @@ module Data.Aeson.Types.Instances
4747 , (.:)
4848 , (.:?)
4949 , (.!=)
50+ , builder
5051 , series
52+ , tuple
53+ , (>*<)
5154 , typeMismatch
5255 ) where
5356
5457import Control.Applicative ((<$>), (<*>), (<|>), pure, empty)
5558import qualified Data.Aeson.Encode.ByteString as E
5659import qualified Data.ByteString.Builder as B
57−import qualified Data.ByteString.Builder.Prim as BP
5860import Data.Aeson.Functions
5961import Data.Monoid ((<>), mempty)
6062import Data.Aeson.Types.Class
@@ -122,7 +124,7 @@ instance (ToJSON a) => ToJSON (Maybe a) where
122124 {-# INLINE toJSON #-}
123125
124126 toEncoding (Just a) = toEncoding a
125− toEncoding Nothing = E.null_
127+ toEncoding Nothing = Encoding E.null_
126128
127129instance (FromJSON a) => FromJSON (Maybe a) where
128130 parseJSON Null = pure Nothing
@@ -134,10 +136,14 @@ instance (ToJSON a, ToJSON b) => ToJSON (Either a b) where
134136 toJSON (Right b) = object [right .= b]
135137 {-# INLINE toJSON #-}
136138
137− toEncoding (Left a) =
138− B.shortByteString "{\"left\":" <> toEncoding a <> B.char7 '}'
139− toEncoding (Right a) =
140− B.shortByteString "{\"right\":" <> toEncoding a <> B.char7 '}'
139+ toEncoding (Left a) = Encoding $
140+ B.shortByteString "{\"left\":" <> builder a <> B.char7 '}'
141+ toEncoding (Right a) = Encoding $
142+ B.shortByteString "{\"right\":" <> builder a <> B.char7 '}'
143+
144+builder :: ToJSON a => a -> B.Builder
145+builder = fromEncoding . toEncoding
146+{-# INLINE builder #-}
141147
142148instance (FromJSON a, FromJSON b) => FromJSON (Either a b) where
143149 parseJSON (Object (H.toList -> [(key, value)]))
@@ -157,7 +163,7 @@ instance ToJSON Bool where
157163 toJSON = Bool
158164 {-# INLINE toJSON #-}
159165
160− toEncoding v = E.bool v
166+ toEncoding = Encoding . E.bool
161167
162168instance FromJSON Bool where
163169 parseJSON = withBool "Bool" pure
@@ -180,7 +186,7 @@ instance ToJSON [Char] where
180186 toJSON = String . T.pack
181187 {-# INLINE toJSON #-}
182188
183− toEncoding = E.text . T.pack
189+ toEncoding = Encoding . E.text . T.pack
184190
185191instance FromJSON [Char] where
186192 parseJSON = withText "String" $ pure . T.unpack
@@ -190,7 +196,7 @@ instance ToJSON Char where
190196 toJSON = String . T.singleton
191197 {-# INLINE toJSON #-}
192198
193− toEncoding = E.text . T.singleton
199+ toEncoding = Encoding . E.text . T.singleton
194200
195201instance FromJSON Char where
196202 parseJSON = withText "Char" $ \t ->
@@ -203,7 +209,7 @@ instance ToJSON Scientific where
203209 toJSON = Number
204210 {-# INLINE toJSON #-}
205211
206− toEncoding v = E.number v
212+ toEncoding = Encoding . E.number
207213 {-# INLINE toEncoding #-}
208214
209215instance FromJSON Scientific where
@@ -252,9 +258,9 @@ instance ToJSON (Ratio Integer) where
252258 , "denominator" .= denominator r
253259 ]
254260
255− toEncoding r =
256− B.shortByteString "{\"numerator\":" <> toEncoding (numerator r) <>
257− B.shortByteString ",\"denominator\":" <> toEncoding (denominator r) <>
261+ toEncoding r = Encoding $
262+ B.shortByteString "{\"numerator\":" <> builder (numerator r) <>
263+ B.shortByteString ",\"denominator\":" <> builder (denominator r) <>
258264 B.char7 '}'
259265
260266instance FromJSON (Ratio Integer) where
@@ -267,7 +273,7 @@ instance HasResolution a => ToJSON (Fixed a) where
267273 toJSON = Number . realToFrac
268274 {-# INLINE toJSON #-}
269275
270− toEncoding = E.number . realToFrac
276+ toEncoding = Encoding . E.number . realToFrac
271277
272278-- | /WARNING:/ Only parse fixed-precision numbers from trusted input
273279-- since an attacker could easily fill up the memory of the target
@@ -281,7 +287,7 @@ instance ToJSON Int where
281287 toJSON = Number . fromIntegral
282288 {-# INLINE toJSON #-}
283289
284− toEncoding = B.intDec
290+ toEncoding = Encoding . B.intDec
285291 {-# INLINE toEncoding #-}
286292
287293instance FromJSON Int where
@@ -292,7 +298,7 @@ instance ToJSON Integer where
292298 toJSON = Number . fromInteger
293299 {-# INLINE toJSON #-}
294300
295− toEncoding = B.integerDec
301+ toEncoding = Encoding . B.integerDec
296302
297303-- | /WARNING:/ Only parse Integers from trusted input since an
298304-- attacker could easily fill up the memory of the target system by
@@ -306,7 +312,7 @@ instance ToJSON Int8 where
306312 toJSON = Number . fromIntegral
307313 {-# INLINE toJSON #-}
308314
309− toEncoding = B.int8Dec
315+ toEncoding = Encoding . B.int8Dec
310316
311317instance FromJSON Int8 where
312318 parseJSON = parseIntegral "Int8"
@@ -316,7 +322,7 @@ instance ToJSON Int16 where
316322 toJSON = Number . fromIntegral
317323 {-# INLINE toJSON #-}
318324
319− toEncoding = B.int16Dec
325+ toEncoding = Encoding . B.int16Dec
320326
321327instance FromJSON Int16 where
322328 parseJSON = parseIntegral "Int16"
@@ -326,7 +332,7 @@ instance ToJSON Int32 where
326332 toJSON = Number . fromIntegral
327333 {-# INLINE toJSON #-}
328334
329− toEncoding = B.int32Dec
335+ toEncoding = Encoding . B.int32Dec
330336
331337instance FromJSON Int32 where
332338 parseJSON = parseIntegral "Int32"
@@ -336,7 +342,7 @@ instance ToJSON Int64 where
336342 toJSON = Number . fromIntegral
337343 {-# INLINE toJSON #-}
338344
339− toEncoding = B.int64Dec
345+ toEncoding = Encoding . B.int64Dec
340346
341347instance FromJSON Int64 where
342348 parseJSON = parseIntegral "Int64"
@@ -346,7 +352,7 @@ instance ToJSON Word where
346352 toJSON = Number . fromIntegral
347353 {-# INLINE toJSON #-}
348354
349− toEncoding = B.wordDec
355+ toEncoding = Encoding . B.wordDec
350356
351357instance FromJSON Word where
352358 parseJSON = parseIntegral "Word"
@@ -356,7 +362,7 @@ instance ToJSON Word8 where
356362 toJSON = Number . fromIntegral
357363 {-# INLINE toJSON #-}
358364
359− toEncoding = B.word8Dec
365+ toEncoding = Encoding . B.word8Dec
360366
361367instance FromJSON Word8 where
362368 parseJSON = parseIntegral "Word8"
@@ -366,7 +372,7 @@ instance ToJSON Word16 where
366372 toJSON = Number . fromIntegral
367373 {-# INLINE toJSON #-}
368374
369− toEncoding = B.word16Dec
375+ toEncoding = Encoding . B.word16Dec
370376
371377instance FromJSON Word16 where
372378 parseJSON = parseIntegral "Word16"
@@ -376,7 +382,7 @@ instance ToJSON Word32 where
376382 toJSON = Number . fromIntegral
377383 {-# INLINE toJSON #-}
378384
379− toEncoding = B.word32Dec
385+ toEncoding = Encoding . B.word32Dec
380386
381387instance FromJSON Word32 where
382388 parseJSON = parseIntegral "Word32"
@@ -386,7 +392,7 @@ instance ToJSON Word64 where
386392 toJSON = Number . fromIntegral
387393 {-# INLINE toJSON #-}
388394
389− toEncoding = B.word64Dec
395+ toEncoding = Encoding . B.word64Dec
390396
391397instance FromJSON Word64 where
392398 parseJSON = parseIntegral "Word64"
@@ -396,7 +402,7 @@ instance ToJSON Text where
396402 toJSON = String
397403 {-# INLINE toJSON #-}
398404
399− toEncoding = E.text
405+ toEncoding = Encoding . E.text
400406
401407instance FromJSON Text where
402408 parseJSON = withText "Text" pure
@@ -406,7 +412,7 @@ instance ToJSON LT.Text where
406412 toJSON = String . LT.toStrict
407413 {-# INLINE toJSON #-}
408414
409− toEncoding t =
415+ toEncoding t = Encoding $
410416 B.char7 '"' <>
411417 LT.foldrChunks (\x xs -> E.unquoted x <> xs) mempty t <>
412418 B.char7 '"'
@@ -420,11 +426,13 @@ instance (ToJSON a) => ToJSON [a] where
420426 {-# INLINE toJSON #-}
421427
422428 toEncoding [] = E.emptyArray_
423− toEncoding (x:xs) = B.char7 '[' <> toEncoding x <> commas xs <> B.char7 ']'
424− where commas = P.foldr (\v vs -> B.char7 ',' <> toEncoding v <> vs) mempty
429+ toEncoding (x:xs) = Encoding $
430+ B.char7 '[' <> builder x <> commas xs <> B.char7 ']'
431+ where commas = P.foldr (\v vs -> B.char7 ',' <> builder v <> vs) mempty
425432
426433instance (FromJSON a) => FromJSON [a] where
427− parseJSON = withArray "[a]" $ Tr.sequence . zipWith parseIndexedJSON [0..] . V.toList
434+ parseJSON = withArray "[a]" $ Tr.sequence .
435+ zipWith parseIndexedJSON [0..] . V.toList
428436 {-# INLINE parseJSON #-}
429437
430438instance (Foldable t, ToJSON a) => ToJSON (t a) where
@@ -443,16 +451,18 @@ instance (ToJSON a) => ToJSON (Vector a) where
443451
444452 toEncoding = encodeVector
445453
446−encodeVector :: (ToJSON a, VG.Vector v a) => v a -> B.Builder
454+encodeVector :: (ToJSON a, VG.Vector v a) => v a -> Encoding
447455encodeVector xs
448456 | VG.null xs = E.emptyArray_
449− | otherwise = B.char7 '[' <> toEncoding (VG.unsafeHead xs) <>
457+ | otherwise = Encoding $
458+ B.char7 '[' <> builder (VG.unsafeHead xs) <>
450459 VG.foldr go mempty (VG.unsafeTail xs) <>
451460 B.char7 ']'
452− where go v b = B.char7 ',' <> toEncoding v <> b
461+ where go v b = B.char7 ',' <> builder v <> b
453462
454463instance (FromJSON a) => FromJSON (Vector a) where
455− parseJSON = withArray "Vector a" $ V.mapM (uncurry parseIndexedJSON) . V.indexed
464+ parseJSON = withArray "Vector a" $ V.mapM (uncurry parseIndexedJSON) .
465+ V.indexed
456466 {-# INLINE parseJSON #-}
457467
458468vectorToJSON :: (VG.Vector v a, ToJSON a) => v a -> Value
@@ -516,14 +526,15 @@ instance ToJSON IntSet.IntSet where
516526encodeSet :: (ToJSON a) =>
517527 (s -> Maybe (a, s))
518528 -> ((a -> B.Builder -> B.Builder) -> B.Builder -> s -> B.Builder)
519− -> s -> B.Builder
529+ -> s -> Encoding
520530encodeSet minView foldr xs =
521531 case minView xs of
522532 Nothing -> E.emptyArray_
523− Just (m,ys) -> B.char7 '[' <> toEncoding m <>
533+ Just (m,ys) -> Encoding $
534+ B.char7 '[' <> builder m <>
524535 foldr go mempty ys <>
525536 B.char7 ']'
526− where go v b = B.char7 ',' <> toEncoding v <> b
537+ where go v b = B.char7 ',' <> builder v <> b
527538
528539instance FromJSON IntSet.IntSet where
529540 parseJSON = fmap IntSet.fromList . parseJSON
@@ -548,22 +559,23 @@ instance (ToJSON v) => ToJSON (M.Map Text v) where
548559encodeMap :: (ToJSON k, ToJSON v) =>
549560 (m -> Maybe ((k,v), m))
550561 -> ((k -> v -> B.Builder -> B.Builder) -> B.Builder -> m -> B.Builder)
551− -> m -> B.Builder
562+ -> m -> Encoding
552563encodeMap minViewWithKey foldrWithKey xs =
553564 case minViewWithKey xs of
554− Nothing -> BP.primBounded (E.ascii2 ('{','}')) ()
555− Just ((k,v),ys) -> B.char7 '{' <> encodePair k v <>
565+ Nothing -> E.emptyObject_
566+ Just ((k,v),ys) -> Encoding $
567+ B.char7 '{' <> encodePair k v <>
556568 foldrWithKey go mempty ys <> B.char7 '}'
557569 where go k v b = B.char7 ',' <> encodePair k v <> b
558570
559571encodeWithKey :: (ToJSON k, ToJSON v) =>
560572 ((k -> v -> Series -> Series) -> Series -> m -> Series)
561− -> m -> B.Builder
562−encodeWithKey foldrWithKey xs = E.series '{' '}' . foldrWithKey go mempty $ xs
563− where go k v c = Value (encodePair k v) <> c
573+ -> m -> Encoding
574+encodeWithKey foldrWithKey = E.series '{' '}' . foldrWithKey go mempty
575+ where go k v c = Value (Encoding $ encodePair k v) <> c
564576
565577encodePair :: (ToJSON k, ToJSON v) => k -> v -> B.Builder
566−encodePair k v = toEncoding k <> B.char7 ':' <> toEncoding v
578+encodePair k v = builder k <> B.char7 ':' <> builder v
567579
568580instance (FromJSON v) => FromJSON (M.Map Text v) where
569581 parseJSON = withObject "Map Text a" $
@@ -622,7 +634,7 @@ instance ToJSON Value where
622634 toJSON a = a
623635 {-# INLINE toJSON #-}
624636
625− toEncoding = E.encodeToBuilder
637+ toEncoding = Encoding . E.encodeToBuilder
626638
627639instance FromJSON Value where
628640 parseJSON a = pure a
@@ -718,6 +730,15 @@ instance FromJSON UTCTime where
718730parseJSONElemAtIndex :: FromJSON a => Int -> Vector Value -> Parser a
719731parseJSONElemAtIndex idx ary = parseJSON (V.unsafeIndex ary idx) <?> Index idx
720732
733+tuple :: B.Builder -> Encoding
734+tuple b = Encoding (B.char7 '[' <> b <> B.char7 ']')
735+{-# INLINE tuple #-}
736+
737+(>*<) :: B.Builder -> B.Builder -> B.Builder
738+a >*< b = a <> B.char7 ',' <> b
739+{-# INLINE (>*<) #-}
740+infixr 6 >*<
741+
721742instance (ToJSON a, ToJSON b) => ToJSON (a,b) where
722743 toJSON (a,b) = Array $ V.create $ do
723744 mv <- VM.unsafeNew 2
@@ -726,9 +747,8 @@ instance (ToJSON a, ToJSON b) => ToJSON (a,b) where
726747 return mv
727748 {-# INLINE toJSON #-}
728749
729− toEncoding (a,b) = B.char7 '[' <>
730− toEncoding a <> B.char7 ',' <>
731− toEncoding b <> B.char7 ']'
750+ toEncoding (a,b) = tuple $
751+ builder a >*< builder b
732752
733753instance (FromJSON a, FromJSON b) => FromJSON (a,b) where
734754 parseJSON = withArray "(a,b)" $ \ab ->
@@ -749,10 +769,10 @@ instance (ToJSON a, ToJSON b, ToJSON c) => ToJSON (a,b,c) where
749769 return mv
750770 {-# INLINE toJSON #-}
751771
752− toEncoding (a,b,c) = B.char7 '[' <>
753− toEncoding a <> B.char7 ',' <>
754− toEncoding b <> B.char7 ',' <>
755− toEncoding c <> B.char7 ']'
772+ toEncoding (a,b,c) = tuple $
773+ builder a >*<
774+ builder b >*<
775+ builder c
756776
757777instance (FromJSON a, FromJSON b, FromJSON c) => FromJSON (a,b,c) where
758778 parseJSON = withArray "(a,b,c)" $ \abc ->
@@ -775,11 +795,11 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d) => ToJSON (a,b,c,d) where
775795 return mv
776796 {-# INLINE toJSON #-}
777797
778− toEncoding (a,b,c,d) = B.char7 '[' <>
779− toEncoding a <> B.char7 ',' <>
780− toEncoding b <> B.char7 ',' <>
781− toEncoding c <> B.char7 ',' <>
782− toEncoding d <> B.char7 ']'
798+ toEncoding (a,b,c,d) = tuple $
799+ builder a >*<
800+ builder b >*<
801+ builder c >*<
802+ builder d
783803
784804instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d) =>
785805 FromJSON (a,b,c,d) where
@@ -806,12 +826,12 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e) =>
806826 return mv
807827 {-# INLINE toJSON #-}
808828
809− toEncoding (a,b,c,d,e) = B.char7 '[' <>
810− toEncoding a <> B.char7 ',' <>
811− toEncoding b <> B.char7 ',' <>
812− toEncoding c <> B.char7 ',' <>
813− toEncoding d <> B.char7 ',' <>
814− toEncoding e <> B.char7 ']'
829+ toEncoding (a,b,c,d,e) = tuple $
830+ builder a >*<
831+ builder b >*<
832+ builder c >*<
833+ builder d >*<
834+ builder e
815835
816836instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e) =>
817837 FromJSON (a,b,c,d,e) where
@@ -840,13 +860,13 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f) =>
840860 return mv
841861 {-# INLINE toJSON #-}
842862
843− toEncoding (a,b,c,d,e,f) = B.char7 '[' <>
844− toEncoding a <> B.char7 ',' <>
845− toEncoding b <> B.char7 ',' <>
846− toEncoding c <> B.char7 ',' <>
847− toEncoding d <> B.char7 ',' <>
848− toEncoding e <> B.char7 ',' <>
849− toEncoding f <> B.char7 ']'
863+ toEncoding (a,b,c,d,e,f) = tuple $
864+ builder a >*<
865+ builder b >*<
866+ builder c >*<
867+ builder d >*<
868+ builder e >*<
869+ builder f
850870
851871instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e,
852872 FromJSON f) => FromJSON (a,b,c,d,e,f) where
@@ -877,14 +897,14 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,
877897 return mv
878898 {-# INLINE toJSON #-}
879899
880− toEncoding (a,b,c,d,e,f,g) = B.char7 '[' <>
881− toEncoding a <> B.char7 ',' <>
882− toEncoding b <> B.char7 ',' <>
883− toEncoding c <> B.char7 ',' <>
884− toEncoding d <> B.char7 ',' <>
885− toEncoding e <> B.char7 ',' <>
886− toEncoding f <> B.char7 ',' <>
887− toEncoding g <> B.char7 ']'
900+ toEncoding (a,b,c,d,e,f,g) = tuple $
901+ builder a >*<
902+ builder b >*<
903+ builder c >*<
904+ builder d >*<
905+ builder e >*<
906+ builder f >*<
907+ builder g
888908
889909instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e,
890910 FromJSON f, FromJSON g) => FromJSON (a,b,c,d,e,f,g) where
@@ -917,15 +937,15 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,
917937 return mv
918938 {-# INLINE toJSON #-}
919939
920− toEncoding (a,b,c,d,e,f,g,h) = B.char7 '[' <>
921− toEncoding a <> B.char7 ',' <>
922− toEncoding b <> B.char7 ',' <>
923− toEncoding c <> B.char7 ',' <>
924− toEncoding d <> B.char7 ',' <>
925− toEncoding e <> B.char7 ',' <>
926− toEncoding f <> B.char7 ',' <>
927− toEncoding g <> B.char7 ',' <>
928− toEncoding h <> B.char7 ']'
940+ toEncoding (a,b,c,d,e,f,g,h) = tuple $
941+ builder a >*<
942+ builder b >*<
943+ builder c >*<
944+ builder d >*<
945+ builder e >*<
946+ builder f >*<
947+ builder g >*<
948+ builder h
929949
930950instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e,
931951 FromJSON f, FromJSON g, FromJSON h) =>
@@ -962,16 +982,16 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,
962982 return mv
963983 {-# INLINE toJSON #-}
964984
965− toEncoding (a,b,c,d,e,f,g,h,i) = B.char7 '[' <>
966− toEncoding a <> B.char7 ',' <>
967− toEncoding b <> B.char7 ',' <>
968− toEncoding c <> B.char7 ',' <>
969− toEncoding d <> B.char7 ',' <>
970− toEncoding e <> B.char7 ',' <>
971− toEncoding f <> B.char7 ',' <>
972− toEncoding g <> B.char7 ',' <>
973− toEncoding h <> B.char7 ',' <>
974− toEncoding i <> B.char7 ']'
985+ toEncoding (a,b,c,d,e,f,g,h,i) = tuple $
986+ builder a >*<
987+ builder b >*<
988+ builder c >*<
989+ builder d >*<
990+ builder e >*<
991+ builder f >*<
992+ builder g >*<
993+ builder h >*<
994+ builder i
975995
976996instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e,
977997 FromJSON f, FromJSON g, FromJSON h, FromJSON i) =>
@@ -1011,17 +1031,17 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,
10111031 return mv
10121032 {-# INLINE toJSON #-}
10131033
1014− toEncoding (a,b,c,d,e,f,g,h,i,j) = B.char7 '[' <>
1015− toEncoding a <> B.char7 ',' <>
1016− toEncoding b <> B.char7 ',' <>
1017− toEncoding c <> B.char7 ',' <>
1018− toEncoding d <> B.char7 ',' <>
1019− toEncoding e <> B.char7 ',' <>
1020− toEncoding f <> B.char7 ',' <>
1021− toEncoding g <> B.char7 ',' <>
1022− toEncoding h <> B.char7 ',' <>
1023− toEncoding i <> B.char7 ',' <>
1024− toEncoding j <> B.char7 ']'
1034+ toEncoding (a,b,c,d,e,f,g,h,i,j) = tuple $
1035+ builder a >*<
1036+ builder b >*<
1037+ builder c >*<
1038+ builder d >*<
1039+ builder e >*<
1040+ builder f >*<
1041+ builder g >*<
1042+ builder h >*<
1043+ builder i >*<
1044+ builder j
10251045
10261046instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e,
10271047 FromJSON f, FromJSON g, FromJSON h, FromJSON i, FromJSON j) =>
@@ -1063,18 +1083,18 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,
10631083 return mv
10641084 {-# INLINE toJSON #-}
10651085
1066− toEncoding (a,b,c,d,e,f,g,h,i,j,k) = B.char7 '[' <>
1067− toEncoding a <> B.char7 ',' <>
1068− toEncoding b <> B.char7 ',' <>
1069− toEncoding c <> B.char7 ',' <>
1070− toEncoding d <> B.char7 ',' <>
1071− toEncoding e <> B.char7 ',' <>
1072− toEncoding f <> B.char7 ',' <>
1073− toEncoding g <> B.char7 ',' <>
1074− toEncoding h <> B.char7 ',' <>
1075− toEncoding i <> B.char7 ',' <>
1076− toEncoding j <> B.char7 ',' <>
1077− toEncoding k <> B.char7 ']'
1086+ toEncoding (a,b,c,d,e,f,g,h,i,j,k) = tuple $
1087+ builder a >*<
1088+ builder b >*<
1089+ builder c >*<
1090+ builder d >*<
1091+ builder e >*<
1092+ builder f >*<
1093+ builder g >*<
1094+ builder h >*<
1095+ builder i >*<
1096+ builder j >*<
1097+ builder k
10781098
10791099instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e,
10801100 FromJSON f, FromJSON g, FromJSON h, FromJSON i, FromJSON j,
@@ -1119,19 +1139,19 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,
11191139 return mv
11201140 {-# INLINE toJSON #-}
11211141
1122− toEncoding (a,b,c,d,e,f,g,h,i,j,k,l) = B.char7 '[' <>
1123− toEncoding a <> B.char7 ',' <>
1124− toEncoding b <> B.char7 ',' <>
1125− toEncoding c <> B.char7 ',' <>
1126− toEncoding d <> B.char7 ',' <>
1127− toEncoding e <> B.char7 ',' <>
1128− toEncoding f <> B.char7 ',' <>
1129− toEncoding g <> B.char7 ',' <>
1130− toEncoding h <> B.char7 ',' <>
1131− toEncoding i <> B.char7 ',' <>
1132− toEncoding j <> B.char7 ',' <>
1133− toEncoding k <> B.char7 ',' <>
1134− toEncoding l <> B.char7 ']'
1142+ toEncoding (a,b,c,d,e,f,g,h,i,j,k,l) = tuple $
1143+ builder a >*<
1144+ builder b >*<
1145+ builder c >*<
1146+ builder d >*<
1147+ builder e >*<
1148+ builder f >*<
1149+ builder g >*<
1150+ builder h >*<
1151+ builder i >*<
1152+ builder j >*<
1153+ builder k >*<
1154+ builder l
11351155
11361156instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e,
11371157 FromJSON f, FromJSON g, FromJSON h, FromJSON i, FromJSON j,
@@ -1179,20 +1199,20 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,
11791199 return mv
11801200 {-# INLINE toJSON #-}
11811201
1182− toEncoding (a,b,c,d,e,f,g,h,i,j,k,l,m) = B.char7 '[' <>
1183− toEncoding a <> B.char7 ',' <>
1184− toEncoding b <> B.char7 ',' <>
1185− toEncoding c <> B.char7 ',' <>
1186− toEncoding d <> B.char7 ',' <>
1187− toEncoding e <> B.char7 ',' <>
1188− toEncoding f <> B.char7 ',' <>
1189− toEncoding g <> B.char7 ',' <>
1190− toEncoding h <> B.char7 ',' <>
1191− toEncoding i <> B.char7 ',' <>
1192− toEncoding j <> B.char7 ',' <>
1193− toEncoding k <> B.char7 ',' <>
1194− toEncoding l <> B.char7 ',' <>
1195− toEncoding m <> B.char7 ']'
1202+ toEncoding (a,b,c,d,e,f,g,h,i,j,k,l,m) = tuple $
1203+ builder a >*<
1204+ builder b >*<
1205+ builder c >*<
1206+ builder d >*<
1207+ builder e >*<
1208+ builder f >*<
1209+ builder g >*<
1210+ builder h >*<
1211+ builder i >*<
1212+ builder j >*<
1213+ builder k >*<
1214+ builder l >*<
1215+ builder m
11961216
11971217instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e,
11981218 FromJSON f, FromJSON g, FromJSON h, FromJSON i, FromJSON j,
@@ -1242,21 +1262,21 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,
12421262 return mv
12431263 {-# INLINE toJSON #-}
12441264
1245− toEncoding (a,b,c,d,e,f,g,h,i,j,k,l,m,n) = B.char7 '[' <>
1246− toEncoding a <> B.char7 ',' <>
1247− toEncoding b <> B.char7 ',' <>
1248− toEncoding c <> B.char7 ',' <>
1249− toEncoding d <> B.char7 ',' <>
1250− toEncoding e <> B.char7 ',' <>
1251− toEncoding f <> B.char7 ',' <>
1252− toEncoding g <> B.char7 ',' <>
1253− toEncoding h <> B.char7 ',' <>
1254− toEncoding i <> B.char7 ',' <>
1255− toEncoding j <> B.char7 ',' <>
1256− toEncoding k <> B.char7 ',' <>
1257− toEncoding l <> B.char7 ',' <>
1258− toEncoding m <> B.char7 ',' <>
1259− toEncoding n <> B.char7 ']'
1265+ toEncoding (a,b,c,d,e,f,g,h,i,j,k,l,m,n) = tuple $
1266+ builder a >*<
1267+ builder b >*<
1268+ builder c >*<
1269+ builder d >*<
1270+ builder e >*<
1271+ builder f >*<
1272+ builder g >*<
1273+ builder h >*<
1274+ builder i >*<
1275+ builder j >*<
1276+ builder k >*<
1277+ builder l >*<
1278+ builder m >*<
1279+ builder n
12601280
12611281instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e,
12621282 FromJSON f, FromJSON g, FromJSON h, FromJSON i, FromJSON j,
@@ -1308,22 +1328,22 @@ instance (ToJSON a, ToJSON b, ToJSON c, ToJSON d, ToJSON e, ToJSON f,
13081328 return mv
13091329 {-# INLINE toJSON #-}
13101330
1311− toEncoding (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) = B.char7 '[' <>
1312− toEncoding a <> B.char7 ',' <>
1313− toEncoding b <> B.char7 ',' <>
1314− toEncoding c <> B.char7 ',' <>
1315− toEncoding d <> B.char7 ',' <>
1316− toEncoding e <> B.char7 ',' <>
1317− toEncoding f <> B.char7 ',' <>
1318− toEncoding g <> B.char7 ',' <>
1319− toEncoding h <> B.char7 ',' <>
1320− toEncoding i <> B.char7 ',' <>
1321− toEncoding j <> B.char7 ',' <>
1322− toEncoding k <> B.char7 ',' <>
1323− toEncoding l <> B.char7 ',' <>
1324− toEncoding m <> B.char7 ',' <>
1325− toEncoding n <> B.char7 ',' <>
1326− toEncoding o <> B.char7 ']'
1331+ toEncoding (a,b,c,d,e,f,g,h,i,j,k,l,m,n,o) = tuple $
1332+ builder a >*<
1333+ builder b >*<
1334+ builder c >*<
1335+ builder d >*<
1336+ builder e >*<
1337+ builder f >*<
1338+ builder g >*<
1339+ builder h >*<
1340+ builder i >*<
1341+ builder j >*<
1342+ builder k >*<
1343+ builder l >*<
1344+ builder m >*<
1345+ builder n >*<
1346+ builder o
13271347
13281348instance (FromJSON a, FromJSON b, FromJSON c, FromJSON d, FromJSON e,
13291349 FromJSON f, FromJSON g, FromJSON h, FromJSON i, FromJSON j,
@@ -1429,10 +1449,11 @@ instance KeyValue Pair where
14291449 {-# INLINE (.=) #-}
14301450
14311451instance KeyValue Series where
1432− name .= value = Value (E.text name <> B.char7 ':' <> toEncoding value)
1452+ name .= value = Value . Encoding $
1453+ E.text name <> B.char7 ':' <> builder value
14331454 {-# INLINE (.=) #-}
14341455
1435−series :: Series -> B.Builder
1456+series :: Series -> Encoding
14361457series Empty = mempty
14371458series (Value v) = v
14381459
@@ -1509,7 +1530,7 @@ realFloatToJSON d
15091530
15101531realFloatToEncoding :: RealFloat a => a -> Encoding
15111532realFloatToEncoding d
1512− | isNaN d || isInfinite d = E.null_
1533+ | isNaN d || isInfinite d = Encoding E.null_
15131534 | otherwise = toEncoding (Scientific.fromFloatDigits d)
15141535{-# INLINE realFloatToEncoding #-}
15151536
Data/Aeson/Types/Internal.hs+6−4
@@ -15,7 +15,7 @@ module Data.Aeson.Types.Internal
1515 (
1616 -- * Core JSON types
1717 Value(..)
18− , Encoding
18+ , Encoding(..)
1919 , Series(..)
2020 , Array
2121 , emptyArray, isEmptyArray
@@ -205,10 +205,12 @@ data Value = Object !Object
205205 deriving (Eq, Read, Show, Typeable, Data)
206206
207207-- | An encoding of a JSON value.
208−type Encoding = Builder
208+newtype Encoding = Encoding {
209+ fromEncoding :: Builder
210+ } deriving (Monoid)
209211
210212data Series = Empty
211− | Value Builder
213+ | Value Encoding
212214 deriving (Typeable)
213215
214216instance Monoid Series where
@@ -218,7 +220,7 @@ instance Monoid Series where
218220 Value $
219221 a <> case b of
220222 Empty -> mempty
221− Value c -> char7 ',' <> c
223+ Value c -> Encoding (char7 ',') <> c
222224
223225-- | A newtype wrapper for 'UTCTime' that uses the same non-standard
224226-- serialization format as Microsoft .NET, whose @System.DateTime@
benchmarks/Typed/Manual.hs+1−1
@@ -10,7 +10,7 @@ import Data.ByteString.Lazy as L
1010import Data.ByteString.Builder as B
1111
1212encodeDirect :: Result -> L.ByteString
13−encodeDirect = B.toLazyByteString . toEncoding
13+encodeDirect = B.toLazyByteString . fromEncoding . toEncoding
1414
1515encodeViaValue :: Result -> L.ByteString
1616encodeViaValue = encode