{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE EmptyDataDecls #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
module Data.Aeson.Encoding.Internal
(
Encoding' (..)
, Encoding
, encodingToLazyByteString
, unsafeToEncoding
, retagEncoding
, Series (..)
, pairs
, pair
, pairStr
, pair'
, nullEncoding
, emptyArray_
, emptyObject_
, wrapObject
, wrapArray
, null_
, bool
, text
, lazyText
, string
, list
, dict
, tuple
, (>*<)
, InArray
, empty
, (><)
, econcat
, int8, int16, int32, int64, int
, word8, word16, word32, word64, word
, integer, float, double, scientific
, int8Text, int16Text, int32Text, int64Text, intText
, word8Text, word16Text, word32Text, word64Text, wordText
, integerText, floatText, doubleText, scientificText
, day
, localTime
, utcTime
, timeOfDay
, zonedTime
, value
, comma, colon, openBracket, closeBracket, openCurly, closeCurly
) where
import Prelude.Compat
import Data.Aeson.Types.Internal (Value)
import Data.ByteString.Builder (Builder, char7, toLazyByteString)
import Data.Int
import Data.Scientific (Scientific)
import Data.Text (Text)
import Data.Time (Day, LocalTime, TimeOfDay, UTCTime, ZonedTime)
import Data.Typeable (Typeable)
import Data.Word
import qualified Data.Aeson.Encoding.Builder as EB
import qualified Data.ByteString.Builder as B
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Text.Lazy as LT
newtype Encoding' tag = Encoding {
fromEncoding :: Builder
} deriving (Typeable)
type Encoding = Encoding' Value
unsafeToEncoding :: Builder -> Encoding' a
unsafeToEncoding = Encoding
encodingToLazyByteString :: Encoding' a -> BSL.ByteString
encodingToLazyByteString = toLazyByteString . fromEncoding
{-# INLINE encodingToLazyByteString #-}
retagEncoding :: Encoding' a -> Encoding' b
retagEncoding = Encoding . fromEncoding
instance Show (Encoding' a) where
show (Encoding e) = show (toLazyByteString e)
instance Eq (Encoding' a) where
Encoding a == Encoding b = toLazyByteString a == toLazyByteString b
instance Ord (Encoding' a) where
compare (Encoding a) (Encoding b) =
compare (toLazyByteString a) (toLazyByteString b)
data Series = Empty
| Value (Encoding' Series)
deriving (Typeable)
pair :: Text -> Encoding -> Series
pair name val = pair' (text name) val
{-# INLINE pair #-}
pairStr :: String -> Encoding -> Series
pairStr name val = pair' (string name) val
{-# INLINE pairStr #-}
pair' :: Encoding' Text -> Encoding -> Series
pair' name val = Value $ retagEncoding $ retagEncoding name >< colon >< val
instance Semigroup Series where
Empty <> a = a
a <> Empty = a
Value a <> Value b = Value (a >< comma >< b)
instance Monoid Series where
mempty = Empty
mappend = (<>)
nullEncoding :: Encoding' a -> Bool
nullEncoding = BSL.null . toLazyByteString . fromEncoding
emptyArray_ :: Encoding
emptyArray_ = Encoding EB.emptyArray_
emptyObject_ :: Encoding
emptyObject_ = Encoding EB.emptyObject_
wrapArray :: Encoding' a -> Encoding
wrapArray e = retagEncoding $ openBracket >< e >< closeBracket
wrapObject :: Encoding' a -> Encoding
wrapObject e = retagEncoding $ openCurly >< e >< closeCurly
null_ :: Encoding
null_ = Encoding EB.null_
bool :: Bool -> Encoding
bool True = Encoding "true"
bool False = Encoding "false"
pairs :: Series -> Encoding
pairs (Value v) = openCurly >< retagEncoding v >< closeCurly
pairs Empty = emptyObject_
{-# INLINE pairs #-}
list :: (a -> Encoding) -> [a] -> Encoding
list _ [] = emptyArray_
list to' (x:xs) = openBracket >< to' x >< commas xs >< closeBracket
where
commas = foldr (\v vs -> comma >< to' v >< vs) empty
{-# INLINE list #-}
dict
:: (k -> Encoding' Text)
-> (v -> Encoding)
-> (forall a. (k -> v -> a -> a) -> a -> m -> a)
-> m
-> Encoding
dict encodeKey encodeVal foldrWithKey = pairs . foldrWithKey go mempty
where
go k v c = Value (encodeKV k v) <> c
encodeKV k v = retagEncoding (encodeKey k) >< colon >< retagEncoding (encodeVal v)
{-# INLINE dict #-}
data InArray
infixr 6 >*<
(>*<) :: Encoding' a -> Encoding' b -> Encoding' InArray
a >*< b = retagEncoding a >< comma >< retagEncoding b
{-# INLINE (>*<) #-}
empty :: Encoding' a
empty = Encoding mempty
econcat :: [Encoding' a] -> Encoding' a
econcat = foldr (><) empty
infixr 6 ><
(><) :: Encoding' a -> Encoding' a -> Encoding' a
Encoding a >< Encoding b = Encoding (a <> b)
{-# INLINE (><) #-}
tuple :: Encoding' InArray -> Encoding
tuple b = retagEncoding $ openBracket >< b >< closeBracket
{-# INLINE tuple #-}
text :: Text -> Encoding' a
text = Encoding . EB.text
lazyText :: LT.Text -> Encoding' a
lazyText t = Encoding $
B.char7 '"' <>
LT.foldrChunks (\x xs -> EB.unquoted x <> xs) (B.char7 '"') t
string :: String -> Encoding' a
string = Encoding . EB.string
comma, colon, openBracket, closeBracket, openCurly, closeCurly :: Encoding' a
comma = Encoding $ char7 ','
colon = Encoding $ char7 ':'
openBracket = Encoding $ char7 '['
closeBracket = Encoding $ char7 ']'
openCurly = Encoding $ char7 '{'
closeCurly = Encoding $ char7 '}'
int8 :: Int8 -> Encoding
int8 = Encoding . B.int8Dec
int16 :: Int16 -> Encoding
int16 = Encoding . B.int16Dec
int32 :: Int32 -> Encoding
int32 = Encoding . B.int32Dec
int64 :: Int64 -> Encoding
int64 = Encoding . B.int64Dec
int :: Int -> Encoding
int = Encoding . B.intDec
word8 :: Word8 -> Encoding
word8 = Encoding . B.word8Dec
word16 :: Word16 -> Encoding
word16 = Encoding . B.word16Dec
word32 :: Word32 -> Encoding
word32 = Encoding . B.word32Dec
word64 :: Word64 -> Encoding
word64 = Encoding . B.word64Dec
word :: Word -> Encoding
word = Encoding . B.wordDec
integer :: Integer -> Encoding
integer = Encoding . B.integerDec
float :: Float -> Encoding
float = realFloatToEncoding $ Encoding . B.floatDec
double :: Double -> Encoding
double = realFloatToEncoding $ Encoding . B.doubleDec
scientific :: Scientific -> Encoding
scientific = Encoding . EB.scientific
realFloatToEncoding :: RealFloat a => (a -> Encoding) -> a -> Encoding
realFloatToEncoding e d
| isNaN d || isInfinite d = null_
| otherwise = e d
{-# INLINE realFloatToEncoding #-}
int8Text :: Int8 -> Encoding' a
int8Text = Encoding . EB.quote . B.int8Dec
int16Text :: Int16 -> Encoding' a
int16Text = Encoding . EB.quote . B.int16Dec
int32Text :: Int32 -> Encoding' a
int32Text = Encoding . EB.quote . B.int32Dec
int64Text :: Int64 -> Encoding' a
int64Text = Encoding . EB.quote . B.int64Dec
intText :: Int -> Encoding' a
intText = Encoding . EB.quote . B.intDec
word8Text :: Word8 -> Encoding' a
word8Text = Encoding . EB.quote . B.word8Dec
word16Text :: Word16 -> Encoding' a
word16Text = Encoding . EB.quote . B.word16Dec
word32Text :: Word32 -> Encoding' a
word32Text = Encoding . EB.quote . B.word32Dec
word64Text :: Word64 -> Encoding' a
word64Text = Encoding . EB.quote . B.word64Dec
wordText :: Word -> Encoding' a
wordText = Encoding . EB.quote . B.wordDec
integerText :: Integer -> Encoding' a
integerText = Encoding . EB.quote . B.integerDec
floatText :: Float -> Encoding' a
floatText = Encoding . EB.quote . B.floatDec
doubleText :: Double -> Encoding' a
doubleText = Encoding . EB.quote . B.doubleDec
scientificText :: Scientific -> Encoding' a
scientificText = Encoding . EB.quote . EB.scientific
day :: Day -> Encoding' a
day = Encoding . EB.quote . EB.day
localTime :: LocalTime -> Encoding' a
localTime = Encoding . EB.quote . EB.localTime
utcTime :: UTCTime -> Encoding' a
utcTime = Encoding . EB.quote . EB.utcTime
timeOfDay :: TimeOfDay -> Encoding' a
timeOfDay = Encoding . EB.quote . EB.timeOfDay
zonedTime :: ZonedTime -> Encoding' a
zonedTime = Encoding . EB.quote . EB.zonedTime
value :: Value -> Encoding
value = Encoding . EB.encodeToBuilder