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