{-# LANGUAGE GeneralizedNewtypeDeriving, FlexibleInstances, FlexibleContexts #-}
{-# LANGUAGE OverloadedStrings, MagicHash, BangPatterns, UndecidableInstances #-}

{-|
A library for efficiently building up a valid JSON document.

The difference between "Data.BufferBuilder.Json" and the excellent
"Data.Aeson" is that Aeson represents the JSON document as an
in-memory tree structure before encoding it into bytes.  This module,
on the other hand, represents each value as an action that writes its
representation directly into the output buffer.  At the cost of
reduced flexibility, this results in significantly improved encoding
performance.  At the time of this writing, encoding a custom record
type into JSON using this module was almost 5x faster than using
Aeson.

This module is built on top of "Data.Utf8Builder".
-}
module Data.BufferBuilder.Json
    (
    -- * Encoding Values
      Value
    , ToJson (..)
    , encodeJson

    -- * Encoding Strings
    , JsonString
    , ToJsonString (..)

    -- * Objects
    , ObjectBuilder
    , emptyObject
    , (.=)
    , (.=#)
    , row

    -- * Arrays
    , array

    -- * Null
    , nullValue

    -- * Unsafe
    , unsafeValueUtf8Builder
    , unsafeStringUtf8Builder

    -- * Deprecated
    , unsafeAppendUtf8Builder
    , unsafeAppendBS
    ) where

import GHC.Base
import Foreign.Storable
import Control.Monad (when, forM_)
import Data.BufferBuilder.Utf8 (Utf8Builder)
import qualified Data.BufferBuilder.Utf8 as UB
import Data.ByteString (ByteString)
import Data.Monoid hiding ((<>))
import Data.Semigroup
import Data.Text (Text)
import Data.Foldable (Foldable, foldMap)
import qualified Data.Vector as Vector
import qualified Data.Vector.Generic as GVector
import qualified Data.Vector.Primitive as VP
import qualified Data.Vector.Storable as VS
import qualified Data.Vector.Unboxed as VU
import qualified Data.HashMap.Strict as HashMap

-- | Represents a JSON value.
--
-- 'Value's are built up from either 'ToJson' instances or
-- from primitives like 'emptyObject', 'array', and 'null'.
--
-- In special cases, or when performance is of utmost importance, the
-- unsafe functions 'unsafeAppendUtf8Builder' are
-- available.
--
-- Internally, Value encodes an action or sequence of actions that append
-- JSON-encoded text to the underlying 'Utf8Builder'.
newtype Value = Value { Value -> Utf8Builder ()
utf8Builder :: Utf8Builder () }

-- | The class of types that can be converted to JSON values.  See
-- 'ObjectBuilder' for an example of writing a 'ToJson' instance for a
-- custom data type.
--
-- 'ToJson' instances are provided for many common types.  For
-- example, to create a JSON array, call 'toJson' on a list or 'Vector.Vector'.
-- To create a JSON object, call 'toJson' on a 'HashMap.HashMap'.
class ToJson a where
    toJson :: a -> Value

---- General JSON value support

-- | Encode a value into a 'ByteString' containing valid UTF-8-encoded JSON.
-- The argument value must have a corresponding 'ToJson' instance.
--
-- __WARNING__: There are three cases where the resulting 'ByteString' may not contain
-- legal JSON:
--
-- * An unsafe function was used to encode a JSON value.
-- * The root value is not an object or array, as the JSON specification requires.
-- * An object has multiple keys with the same value.  For maximum efficiency,
--   'ObjectBuilder' does not check key names for uniqueness, so it's possible to
--   construct objects with duplicate keys.
encodeJson :: ToJson a => a -> ByteString
encodeJson :: a -> ByteString
encodeJson = Utf8Builder () -> ByteString
UB.runUtf8Builder (Utf8Builder () -> ByteString)
-> (a -> Utf8Builder ()) -> a -> ByteString
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> Utf8Builder ()
utf8Builder (Value -> Utf8Builder ()) -> (a -> Value) -> a -> Utf8Builder ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Value
forall a. ToJson a => a -> Value
toJson
{-# INLINE encodeJson #-}

---- String

-- | Represents a JSON string.
newtype JsonString = JsonString { JsonString -> Utf8Builder ()
unJsonString :: Utf8Builder () }

-- | The class of types that can be converted to JSON strings.  Any
-- type that provides ToJsonString also provides ToJson, and thus can
-- be used as JSON values.
class ToJson a => ToJsonString a where
    toJsonString :: a -> JsonString

---- Objects

-- | Builds a JSON object.
--
-- An 'ObjectBuilder' builds one or more key-value pairs of a JSON object.  They are constructed with the '.=' operator and
-- combined with 'Data.Monoid.<>'.
--
-- To turn an 'ObjectBuilder' into a 'Value', use its 'ToJson' class instance.
--
-- @
--     data Friend = Friend
--         { fId :: !Int
--         , fName :: !Text
--         } deriving (Eq, Show)
--
--     instance ToJson Friend where
--         toJson friend = toJson $
--                    "id"   .= fId friend
--                 <> "name" .= fName friend
-- @
--
-- __WARNING__: 'ObjectBuilder' does not check uniqueness of object
-- keys.  If two keys with the same value are inserted, then the
-- resulting JSON document will be illegal.
data ObjectBuilder = NoPair | Pair !(Utf8Builder ())

instance Semigroup ObjectBuilder where
    {-# INLINE (<>) #-}
    ObjectBuilder
NoPair <> :: ObjectBuilder -> ObjectBuilder -> ObjectBuilder
<> ObjectBuilder
a = ObjectBuilder
a
    ObjectBuilder
a <> ObjectBuilder
NoPair = ObjectBuilder
a
    (Pair Utf8Builder ()
a) <> (Pair Utf8Builder ()
b) = Utf8Builder () -> ObjectBuilder
Pair (Utf8Builder () -> ObjectBuilder)
-> Utf8Builder () -> ObjectBuilder
forall a b. (a -> b) -> a -> b
$ do
        Utf8Builder ()
a
        Char -> Utf8Builder ()
UB.appendChar7 Char
','
        Utf8Builder ()
b

instance Monoid ObjectBuilder where
    {-# INLINE mempty #-}
    mempty :: ObjectBuilder
mempty = ObjectBuilder
NoPair

    {-# INLINE mappend #-}
    mappend :: ObjectBuilder -> ObjectBuilder -> ObjectBuilder
mappend = ObjectBuilder -> ObjectBuilder -> ObjectBuilder
forall a. Semigroup a => a -> a -> a
(<>)

instance ToJson ObjectBuilder where
    {-# INLINE toJson #-}
    toJson :: ObjectBuilder -> Value
toJson ObjectBuilder
NoPair = Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ do
        Char -> Utf8Builder ()
UB.appendChar7 Char
'{'
        Char -> Utf8Builder ()
UB.appendChar7 Char
'}'

    toJson (Pair Utf8Builder ()
a) = Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ do
        Char -> Utf8Builder ()
UB.appendChar7 Char
'{'
        Utf8Builder ()
a
        Char -> Utf8Builder ()
UB.appendChar7 Char
'}'

-- | A 'Value' that produces the empty object.
emptyObject :: Value
emptyObject :: Value
emptyObject = ObjectBuilder -> Value
forall a. ToJson a => a -> Value
toJson ObjectBuilder
NoPair
{-# INLINE emptyObject #-}

-- | Create an ObjectBuilder from an arbitrary key and value.  The key can be any
-- type with a 'ToJsonString' instance.
row :: (ToJsonString k, ToJson v) => k -> v -> ObjectBuilder
row :: k -> v -> ObjectBuilder
row k
k v
v = Utf8Builder () -> ObjectBuilder
Pair (Utf8Builder () -> ObjectBuilder)
-> Utf8Builder () -> ObjectBuilder
forall a b. (a -> b) -> a -> b
$ do
    JsonString -> Utf8Builder ()
unJsonString (JsonString -> Utf8Builder ()) -> JsonString -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ k -> JsonString
forall a. ToJsonString a => a -> JsonString
toJsonString k
k
    Char -> Utf8Builder ()
UB.appendChar7 Char
':'
    Value -> Utf8Builder ()
utf8Builder (Value -> Utf8Builder ()) -> Value -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ v -> Value
forall a. ToJson a => a -> Value
toJson v
v
infixr 8 `row`
{-# INLINE row #-}

-- | Create an 'ObjectBuilder' from a key and a value.
(.=) :: ToJson a => Text -> a -> ObjectBuilder
Text
a .= :: Text -> a -> ObjectBuilder
.= a
b = Utf8Builder () -> ObjectBuilder
Pair (Utf8Builder () -> ObjectBuilder)
-> Utf8Builder () -> ObjectBuilder
forall a b. (a -> b) -> a -> b
$ do
    Text -> Utf8Builder ()
UB.appendEscapedJsonText Text
a
    Char -> Utf8Builder ()
UB.appendChar7 Char
':'
    Value -> Utf8Builder ()
utf8Builder (Value -> Utf8Builder ()) -> Value -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ a -> Value
forall a. ToJson a => a -> Value
toJson a
b
infixr 8 .=
{-# INLINE (.=) #-}

-- | Create an 'ObjectBuilder' from a key and a value.  The key is an
-- ASCII-7, unescaped, zero-terminated 'Addr#'.
--
-- __WARNING__: This function is unsafe.  If the key is NOT
-- zero-terminated, then an access violation might result.  If the key
-- is not a sequence of unescaped ASCII characters, the resulting JSON
-- document will be illegal.
--
-- This function is provided for maximum performance in the common
-- case that object keys are ASCII-7.  It achieves performance by
-- avoiding the CAF for a Text literal and avoiding the need to
-- transcode UTF-16 to UTF-8 and escape.
--
-- To use this function, the calling source file must have the
-- MagicHash extension enabled.
--
-- @
--     data Friend = Friend
--         { fId :: !Int
--         , fName :: !Text
--         } deriving (Eq, Show)
--
--     instance ToJson Friend where
--         toJson friend = toJson $
--                    "id"\#   .=\# fId friend
--                 <> "name"\# .=\# fName friend
-- @
(.=#) :: ToJson a => Addr# -> a -> ObjectBuilder
Addr#
a .=# :: Addr# -> a -> ObjectBuilder
.=# a
b = Utf8Builder () -> ObjectBuilder
Pair (Utf8Builder () -> ObjectBuilder)
-> Utf8Builder () -> ObjectBuilder
forall a b. (a -> b) -> a -> b
$ do
    Addr# -> Utf8Builder ()
UB.appendEscapedJsonLiteral Addr#
a
    Char -> Utf8Builder ()
UB.appendChar7 Char
':'
    Value -> Utf8Builder ()
utf8Builder (Value -> Utf8Builder ()) -> Value -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ a -> Value
forall a. ToJson a => a -> Value
toJson a
b
infixr 8 .=#
{-# INLINE (.=#) #-}


{-# INLINE writePair #-}
writePair :: (ToJsonString k, ToJson v) => (k, v) -> Utf8Builder ()
writePair :: (k, v) -> Utf8Builder ()
writePair (k
key, v
value) = do
    JsonString -> Utf8Builder ()
unJsonString (JsonString -> Utf8Builder ()) -> JsonString -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ k -> JsonString
forall a. ToJsonString a => a -> JsonString
toJsonString k
key
    Char -> Utf8Builder ()
UB.appendChar7 Char
':'
    Value -> Utf8Builder ()
utf8Builder (Value -> Utf8Builder ()) -> Value -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ v -> Value
forall a. ToJson a => a -> Value
toJson v
value

instance (ToJsonString k, ToJson v) => ToJson (HashMap.HashMap k v) where
    {-# INLINABLE toJson #-}
    toJson :: HashMap k v -> Value
toJson HashMap k v
hm = Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ do
        Char -> Utf8Builder ()
UB.appendChar7 Char
'{'
        case HashMap k v -> [(k, v)]
forall k v. HashMap k v -> [(k, v)]
HashMap.toList HashMap k v
hm of
            [] -> Char -> Utf8Builder ()
UB.appendChar7 Char
'}'
            ((k, v)
x:[(k, v)]
xs) -> do
                (k, v) -> Utf8Builder ()
forall k v. (ToJsonString k, ToJson v) => (k, v) -> Utf8Builder ()
writePair (k, v)
x
                [(k, v)] -> ((k, v) -> Utf8Builder ()) -> Utf8Builder ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [(k, v)]
xs (((k, v) -> Utf8Builder ()) -> Utf8Builder ())
-> ((k, v) -> Utf8Builder ()) -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ \(k, v)
p -> do
                    Char -> Utf8Builder ()
UB.appendChar7 Char
','
                    (k, v) -> Utf8Builder ()
forall k v. (ToJsonString k, ToJson v) => (k, v) -> Utf8Builder ()
writePair (k, v)
p
                Char -> Utf8Builder ()
UB.appendChar7 Char
'}'

---- Arrays

-- | Serialize any 'Foldable' as a JSON array.  This is generally
-- slower than directly calling 'toJson' on a list or 'Vector.Vector',
-- but it will convert any 'Foldable' type into an array.
array :: (Foldable t, ToJson a) => t a -> Value
array :: t a -> Value
array t a
collection = Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ do
    Char -> Utf8Builder ()
UB.appendChar7 Char
'['
    -- HACK: ObjectBuilder is not "type correct" but it has exactly the behaviour we want for this function.
    case (a -> ObjectBuilder) -> t a -> ObjectBuilder
forall (t :: * -> *) m a.
(Foldable t, Monoid m) =>
(a -> m) -> t a -> m
foldMap (Utf8Builder () -> ObjectBuilder
Pair (Utf8Builder () -> ObjectBuilder)
-> (a -> Utf8Builder ()) -> a -> ObjectBuilder
forall b c a. (b -> c) -> (a -> b) -> a -> c
. Value -> Utf8Builder ()
utf8Builder (Value -> Utf8Builder ()) -> (a -> Value) -> a -> Utf8Builder ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> Value
forall a. ToJson a => a -> Value
toJson) t a
collection of
        ObjectBuilder
NoPair -> () -> Utf8Builder ()
forall (m :: * -> *) a. Monad m => a -> m a
return ()
        (Pair Utf8Builder ()
b) -> Utf8Builder ()
b
    Char -> Utf8Builder ()
UB.appendChar7 Char
']'
{-# INLINABLE array #-}

instance ToJson a => ToJson [a] where
    {-# INLINABLE toJson #-}
    toJson :: [a] -> Value
toJson ![a]
ls = Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ do
        Char -> Utf8Builder ()
UB.appendChar7 Char
'['
        case [a]
ls of
            [] -> Char -> Utf8Builder ()
UB.appendChar7 Char
']'
            a
x:[a]
xs -> do
                Value -> Utf8Builder ()
utf8Builder (Value -> Utf8Builder ()) -> Value -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ a -> Value
forall a. ToJson a => a -> Value
toJson a
x
                [a] -> (a -> Utf8Builder ()) -> Utf8Builder ()
forall (t :: * -> *) (m :: * -> *) a b.
(Foldable t, Monad m) =>
t a -> (a -> m b) -> m ()
forM_ [a]
xs ((a -> Utf8Builder ()) -> Utf8Builder ())
-> (a -> Utf8Builder ()) -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ \(!a
e) -> do
                    Char -> Utf8Builder ()
UB.appendChar7 Char
','
                    Value -> Utf8Builder ()
utf8Builder (Value -> Utf8Builder ()) -> Value -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ a -> Value
forall a. ToJson a => a -> Value
toJson a
e
                Char -> Utf8Builder ()
UB.appendChar7 Char
']'

instance ToJson a => ToJson (Vector.Vector a) where
    {-# INLINABLE toJson #-}
    toJson :: Vector a -> Value
toJson = Vector a -> Value
forall (v :: * -> *) a. (Vector v a, ToJson a) => v a -> Value
vector

instance (Storable a, ToJson a) => ToJson (VS.Vector a) where
    {-# INLINABLE toJson #-}
    toJson :: Vector a -> Value
toJson = Vector a -> Value
forall (v :: * -> *) a. (Vector v a, ToJson a) => v a -> Value
vector

instance (VP.Prim a, ToJson a) => ToJson (VP.Vector a) where
    {-# INLINABLE toJson #-}
    toJson :: Vector a -> Value
toJson = Vector a -> Value
forall (v :: * -> *) a. (Vector v a, ToJson a) => v a -> Value
vector

instance (GVector.Vector VU.Vector a, ToJson a) => ToJson (VU.Vector a) where
    {-# INLINABLE toJson #-}
    toJson :: Vector a -> Value
toJson = Vector a -> Value
forall (v :: * -> *) a. (Vector v a, ToJson a) => v a -> Value
vector

{-# INLINABLE vector #-}
vector :: (GVector.Vector v a, ToJson a) => v a -> Value
vector :: v a -> Value
vector !v a
vec = Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ do
    Char -> Utf8Builder ()
UB.appendChar7 Char
'['
    let len :: Int
len = v a -> Int
forall (v :: * -> *) a. Vector v a => v a -> Int
GVector.length v a
vec
    Bool -> Utf8Builder () -> Utf8Builder ()
forall (f :: * -> *). Applicative f => Bool -> f () -> f ()
when (Int
len Int -> Int -> Bool
forall a. Eq a => a -> a -> Bool
/= Int
0) (Utf8Builder () -> Utf8Builder ())
-> Utf8Builder () -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ do
        Value -> Utf8Builder ()
utf8Builder (Value -> Utf8Builder ()) -> Value -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ a -> Value
forall a. ToJson a => a -> Value
toJson (v a
vec v a -> Int -> a
forall (v :: * -> *) a. Vector v a => v a -> Int -> a
`GVector.unsafeIndex` Int
0)
        v a -> (a -> Utf8Builder ()) -> Utf8Builder ()
forall (m :: * -> *) (v :: * -> *) a b.
(Monad m, Vector v a) =>
v a -> (a -> m b) -> m ()
GVector.forM_ (v a -> v a
forall (v :: * -> *) a. Vector v a => v a -> v a
GVector.tail v a
vec) ((a -> Utf8Builder ()) -> Utf8Builder ())
-> (a -> Utf8Builder ()) -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ \a
e -> do
            Char -> Utf8Builder ()
UB.appendChar7 Char
','
            Value -> Utf8Builder ()
utf8Builder (Value -> Utf8Builder ()) -> Value -> Utf8Builder ()
forall a b. (a -> b) -> a -> b
$ a -> Value
forall a. ToJson a => a -> Value
toJson a
e
    Char -> Utf8Builder ()
UB.appendChar7 Char
']'


----

-- | Represents a JSON "null".
nullValue :: Value
nullValue :: Value
nullValue = Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ Int -> Addr# -> Utf8Builder ()
UB.unsafeAppendLiteralN Int
4 Addr#
"null"#
{-# INLINE nullValue #-}

---- Common JSON instances

instance ToJson Value where
    {-# INLINE toJson #-}
    toJson :: Value -> Value
toJson = Value -> Value
forall a. a -> a
id

instance ToJson Bool where
    {-# INLINE toJson #-}
    toJson :: Bool -> Value
toJson Bool
True = Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ Int -> Addr# -> Utf8Builder ()
UB.unsafeAppendLiteralN Int
4 Addr#
"true"#
    toJson Bool
False = Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ Int -> Addr# -> Utf8Builder ()
UB.unsafeAppendLiteralN Int
5 Addr#
"false"#

instance ToJson a => ToJson (Maybe a) where
    {-# INLINE toJson #-}
    toJson :: Maybe a -> Value
toJson Maybe a
m = case Maybe a
m of
        Maybe a
Nothing -> Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ Int -> Addr# -> Utf8Builder ()
UB.unsafeAppendLiteralN Int
4 Addr#
"null"#
        Just a
a -> a -> Value
forall a. ToJson a => a -> Value
toJson a
a

instance ToJson Text where
    {-# INLINE toJson #-}
    toJson :: Text -> Value
toJson Text
text = Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ Text -> Utf8Builder ()
UB.appendEscapedJsonText Text
text

instance ToJson Double where
    {-# INLINE toJson #-}
    toJson :: Double -> Value
toJson Double
a = Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ Double -> Utf8Builder ()
UB.appendDecimalDouble Double
a

instance ToJson Int where
    {-# INLINE toJson #-}
    toJson :: Int -> Value
toJson Int
a = Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ Int -> Utf8Builder ()
UB.appendDecimalSignedInt Int
a

instance ToJsonString JsonString where
    toJsonString :: JsonString -> JsonString
toJsonString = JsonString -> JsonString
forall a. a -> a
id

instance ToJson JsonString where
    toJson :: JsonString -> Value
toJson = Utf8Builder () -> Value
Value (Utf8Builder () -> Value)
-> (JsonString -> Utf8Builder ()) -> JsonString -> Value
forall b c a. (b -> c) -> (a -> b) -> a -> c
. JsonString -> Utf8Builder ()
unJsonString

instance ToJsonString Text where
    {-# INLINE toJsonString #-}
    toJsonString :: Text -> JsonString
toJsonString Text
text = Utf8Builder () -> JsonString
JsonString (Utf8Builder () -> JsonString) -> Utf8Builder () -> JsonString
forall a b. (a -> b) -> a -> b
$ Text -> Utf8Builder ()
UB.appendEscapedJsonText Text
text


---- Unsafe functions

-- | Unsafely convert a 'Utf8Builder' into a JSON value.
-- This function does not escape, quote, or decorate the string in any way.
-- This function is /unsafe/ because you can trivially use it to generate illegal JSON.
unsafeValueUtf8Builder :: Utf8Builder () -> Value
unsafeValueUtf8Builder :: Utf8Builder () -> Value
unsafeValueUtf8Builder = Utf8Builder () -> Value
Value

-- | Unsafely convert a 'Utf8Builder' into a JSON string.
-- This function does not escape, quote, or decorate the string in any way.
-- This function is /unsafe/ because you can trivially use it to generate illegal JSON.
unsafeStringUtf8Builder :: Utf8Builder () -> JsonString
unsafeStringUtf8Builder :: Utf8Builder () -> JsonString
unsafeStringUtf8Builder = Utf8Builder () -> JsonString
JsonString


---- Deprecated

{-# DEPRECATED unsafeAppendBS "Use unsafeValueUtf8Builder or unsafeStringUtf8Builder instead" #-}
unsafeAppendBS :: ByteString -> Value
unsafeAppendBS :: ByteString -> Value
unsafeAppendBS ByteString
bs = Utf8Builder () -> Value
Value (Utf8Builder () -> Value) -> Utf8Builder () -> Value
forall a b. (a -> b) -> a -> b
$ ByteString -> Utf8Builder ()
UB.unsafeAppendBS ByteString
bs

{-# DEPRECATED unsafeAppendUtf8Builder "Use unsafeValueUtf8Builder or unsafeStringUtf8Builder instead" #-}
unsafeAppendUtf8Builder :: Utf8Builder () -> Value
unsafeAppendUtf8Builder :: Utf8Builder () -> Value
unsafeAppendUtf8Builder = Utf8Builder () -> Value
unsafeValueUtf8Builder