{-# LANGUAGE OverloadedStrings #-} {-| Efficient build ByteString from `Json` with escaped string. /For example - use in YESOD:/ @ import Yesod import Data.JSON2 as JSON import Data.JSON2.Blaze as JSON import Blaze.ByteString.Builder (toLazyByteString) -- toRepJson :: ToJson a => a -> RepJson toRepJson = RepJson . toContent . toLazyByteString . (JSON.blazeJson) . (JSON.toJson) @ -} module Data.JSON2.Blaze (blazeJson) where import Data.JSON2.Types import Data.ByteString.Char8 () import Blaze.ByteString.Builder import Blaze.ByteString.Builder.Internal (getPoke, boundedWrite) import Blaze.ByteString.Builder.Char.Utf8 (writeChar, fromChar, fromString, fromShow) import Data.Ratio (denominator, numerator) import Data.Monoid (mempty, mappend, mconcat) import Data.Map as Map blazeJson :: Json -> Builder blazeJson JNull = fromByteString "null" blazeJson (JBool True) = fromByteString "true" blazeJson (JBool False) = fromByteString "false" blazeJson (JString xs) = escQuoted xs blazeJson (JNumber x) | denominator x == 1 = fromShow (numerator x) | otherwise = fromShow (fromRational x :: Double) blazeJson (JArray []) = fromByteString "[]" blazeJson (JArray (x:xs)) = mconcat [fromChar '[', blazeJson x, go xs, fromChar ']' ] where go xs = mconcat [fromChar ',' `mappend` blazeJson x | x <- xs] blazeJson (JObject x) = goo (Map.toList x) where goo [] = fromByteString "{}" goo (p:ps) = mconcat [fromChar '{', buildPair p, goo' ps, fromChar '}' ] goo' vs = mconcat [fromChar ',' `mappend` buildPair w | w <- vs] buildPair (k,v) = mconcat[escQuoted k, fromChar ':', blazeJson v] escQuoted :: String -> Builder escQuoted xs = mconcat [fromChar '\"', (fromWriteList writeJsonEscChar xs), fromChar '\"'] writeJsonEscChar :: Char -> Write writeJsonEscChar x = boundedWrite 2 (wc x) where wc '\"' = getPoke $ writeByteString "\\\"" wc '\\' = getPoke $ writeByteString "\\\\" wc '/' = getPoke $ writeByteString "\\/" wc '\b' = getPoke $ writeByteString "\\b" wc '\f' = getPoke $ writeByteString "\\f" wc '\n' = getPoke $ writeByteString "\\n" wc '\r' = getPoke $ writeByteString "\\r" wc '\t' = getPoke $ writeByteString "\\t" wc c = getPoke $ writeChar c