From 13295d61d5c8aad8761b7ea54f741e498ffdf872 Mon Sep 17 00:00:00 2001 From: Joey Hess Date: Tue, 26 Jul 2016 21:43:05 -0400 Subject: avoid using Strings for JSON output; keep it ByteString throughout --- Messages/JSON.hs | 10 ++++++---- Utility/JSONStream.hs | 42 +++++++++++++++++++++++++----------------- 2 files changed, 31 insertions(+), 21 deletions(-) diff --git a/Messages/JSON.hs b/Messages/JSON.hs index 70de0739a..2a83da3a7 100644 --- a/Messages/JSON.hs +++ b/Messages/JSON.hs @@ -22,12 +22,14 @@ import Data.Aeson import Control.Applicative import qualified Data.Map as M import qualified Data.Text as T +import qualified Data.ByteString.Lazy as B +import System.IO import qualified Utility.JSONStream as Stream import Types.Key start :: String -> Maybe FilePath -> Maybe Key -> IO () -start command file key = putStr $ Stream.start $ Stream.AesonObject o +start command file key = B.hPut stdout $ Stream.start $ Stream.AesonObject o where Object o = toJSON $ JSONActionItem { itemCommand = Just command @@ -37,16 +39,16 @@ start command file key = putStr $ Stream.start $ Stream.AesonObject o } end :: Bool -> IO () -end b = putStr $ Stream.add (Stream.JSONChunk [("success", b)]) ++ Stream.end +end b = B.hPut stdout $ Stream.add (Stream.JSONChunk [("success", b)]) `B.append` Stream.end note :: String -> IO () note s = add (Stream.JSONChunk [("note", s)]) add :: Stream.JSONChunk a -> IO () -add = putStr . Stream.add +add = B.hPut stdout . Stream.add complete :: Stream.JSONChunk a -> IO () -complete v = putStr $ Stream.start v ++ Stream.end +complete v = B.hPut stdout $ Stream.start v `B.append` Stream.end -- A value that can be displayed either normally, or as JSON. data DualDisp = DualDisp diff --git a/Utility/JSONStream.hs b/Utility/JSONStream.hs index af321b2f9..c5d4e1c8d 100644 --- a/Utility/JSONStream.hs +++ b/Utility/JSONStream.hs @@ -16,7 +16,9 @@ module Utility.JSONStream ( import Data.Aeson import qualified Data.Text as T -import qualified Data.ByteString.Lazy.UTF8 as B +import qualified Data.ByteString.Lazy as B +import Data.Char +import Data.Word data JSONChunk v where JSONChunk :: ToJSON v => [(String, v)] -> JSONChunk [(String, v)] @@ -32,29 +34,35 @@ encodeJSONChunk (AesonObject o) = encode o - with streaming output. To support streaming, a hack: - The final "}" is left off the JSON, allowing more chunks to be added - to later. -} -start :: JSONChunk a -> String +start :: JSONChunk a -> B.ByteString start a - | last s == endchar = init s - | otherwise = bad s + | not (B.null b) && B.last b == endchar = B.init b + | otherwise = bad b where - s = B.toString $ encodeJSONChunk a + b = encodeJSONChunk a -add :: JSONChunk a -> String +add :: JSONChunk a -> B.ByteString add a - | head s == startchar = ',' : drop 1 s - | otherwise = bad s + | not (B.null b) && B.head b == startchar = B.cons addchar (B.drop 1 b) + | otherwise = bad b where - s = start a + b = start a -end :: String -end = [endchar, '\n'] +end :: B.ByteString +end = endchar `B.cons` sepchar `B.cons` B.empty -startchar :: Char -startchar = '{' +startchar :: Word8 +startchar = fromIntegral (ord '{') -endchar :: Char -endchar = '}' +endchar :: Word8 +endchar = fromIntegral (ord '}') -bad :: String -> a -bad s = error $ "JSON encoder generated unexpected value: " ++ s +addchar :: Word8 +addchar = fromIntegral (ord ',') + +sepchar :: Word8 +sepchar = fromIntegral (ord '\n') + +bad :: B.ByteString -> a +bad b = error $ "JSON encoder generated unexpected value: " ++ show b -- cgit v1.2.3