{-# LANGUAGE CPP #-} module Data.ProtoLens.Encoding ( encodeMessage, buildMessage, decodeMessage, parseMessage, decodeMessageOrDie, -- ** Delimited messages 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 -- | Decode a message from its wire format. Returns 'Left' if the decoding -- fails. decodeMessage :: Message msg => B.ByteString -> Either String msg decodeMessage = Bytes.runParser parseMessage -- | Decode a message from its wire format. Throws an error if the decoding -- fails. decodeMessageOrDie :: Message msg => B.ByteString -> msg decodeMessageOrDie bs = case decodeMessage bs of Left e -> error $ "decodeMessageOrDie: " ++ e Right x -> x -- | Encode a message to the wire format as a strict 'ByteString'. encodeMessage :: Message msg => msg -> B.ByteString encodeMessage = Bytes.runBuilder . buildMessage -- | Encode a message to the wire format, prefixed by its size as a VarInt, -- as part of a 'Builder'. -- -- This can be used to build up streams of messages in the size-delimited -- format expected by some protocols. 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 -- | Same as @decodeMessage@ but for delimited messages read through a Handle decodeMessageDelimitedH :: Message msg => Handle -> IO (Either String msg) decodeMessageDelimitedH h = runExceptT $ Bytes.getVarIntH h >>= liftIO . B.hGet h . fromIntegral >>= ExceptT . return . decodeMessage