{-# LANGUAGE CPP #-}
module Data.ProtoLens.Encoding (
encodeMessage,
buildMessage,
decodeMessage,
parseMessage,
decodeMessageOrDie,
buildMessageDelimited,
parseMessageDelimited,
decodeMessageDelimitedH,
) where
import System.IO (Handle)
import Data.ProtoLens.Message (Message(..))
import Data.ProtoLens.Encoding.Bytes (Parser, Builder)
import qualified Data.ProtoLens.Encoding.Bytes as Bytes
import Control.Monad.IO.Class (liftIO)
import Control.Monad.Trans.Except (runExceptT, ExceptT(..))
import qualified Data.ByteString as B
#if !MIN_VERSION_base(4,11,0)
import Data.Semigroup ((<>))
#endif
decodeMessage :: Message msg => B.ByteString -> Either String msg
decodeMessage = Bytes.runParser parseMessage
decodeMessageOrDie :: Message msg => B.ByteString -> msg
decodeMessageOrDie bs = case decodeMessage bs of
Left e -> error $ "decodeMessageOrDie: " ++ e
Right x -> x
encodeMessage :: Message msg => msg -> B.ByteString
encodeMessage = Bytes.runBuilder . buildMessage
buildMessageDelimited :: Message msg => msg -> Builder
buildMessageDelimited msg =
let b = encodeMessage msg
in Bytes.putVarInt (fromIntegral $ B.length b) <> Bytes.putBytes b
parseMessageDelimited :: Message msg => Parser msg
parseMessageDelimited = do
len <- Bytes.getVarInt
bytes <- Bytes.getBytes $ fromIntegral len
either fail return $ decodeMessage bytes
decodeMessageDelimitedH :: Message msg => Handle -> IO (Either String msg)
decodeMessageDelimitedH h = runExceptT $
Bytes.getVarIntH h >>=
liftIO . B.hGet h . fromIntegral >>=
ExceptT . return . decodeMessage