proto-lens 0.5.0.1 → 0.5.1.0
raw patch · 4 files changed
+67/−14 lines, 4 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Data.ProtoLens.Encoding: decodeMessageDelimitedH :: Message msg => Handle -> IO (Either String msg)
+ Data.ProtoLens.Encoding.Bytes: getVarIntH :: Handle -> ExceptT String IO Word64
Files
- Changelog.md +4/−0
- proto-lens.cabal +6/−5
- src/Data/ProtoLens/Encoding.hs +12/−0
- src/Data/ProtoLens/Encoding/Bytes.hs +45/−9
Changelog.md view
@@ -1,5 +1,9 @@ # Changelog for `proto-lens` +## v0.5.1.0+- Add `decodeMessageDelimitedH` to decode delimited messages from a file handle+ (#61).+ ## v0.5.0.1 - Bump the upper bound on `profunctors` to allow 5.4. - Bump the upper bound on `primitive` to allow 0.7.
proto-lens.cabal view
@@ -1,11 +1,13 @@--- This file has been generated from package.yaml by hpack version 0.28.2.+cabal-version: 1.12++-- This file has been generated from package.yaml by hpack version 0.31.1. -- -- see: https://github.com/sol/hpack ----- hash: 29ea431ef6a13fa63ce37199c52c0b46df4db87cdfa86c0241034a9d9c5aaa12+-- hash: 383bc147ec1afaa52a971f87eb6ac95d25c572f183ae0ace7d63ea570da72c44 name: proto-lens-version: 0.5.0.1+version: 0.5.1.0 synopsis: A lens-based implementation of protocol buffers in Haskell. description: The proto-lens library provides an API for protocol buffers using modern Haskell language and library patterns. Specifically, it provides: .@@ -23,12 +25,11 @@ license: BSD3 license-file: LICENSE build-type: Simple-cabal-version: >= 1.10 extra-source-files: Changelog.md data-files:- proto-lens-imports/google/protobuf/compiler/plugin.proto proto-lens-imports/google/protobuf/descriptor.proto+ proto-lens-imports/google/protobuf/compiler/plugin.proto source-repository head type: git
src/Data/ProtoLens/Encoding.hs view
@@ -7,12 +7,17 @@ -- ** 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 import Data.Semigroup ((<>)) @@ -47,3 +52,10 @@ 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
src/Data/ProtoLens/Encoding/Bytes.hs view
@@ -9,6 +9,7 @@ {-# LANGUAGE GeneralizedNewtypeDeriving #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-}+{-# LANGUAGE LambdaCase #-} -- | Utility functions for parsing and encoding individual types. module Data.ProtoLens.Encoding.Bytes(@@ -23,6 +24,7 @@ putBytes, -- * Integral types getVarInt,+ getVarIntH, putVarInt, getFixed32, getFixed64,@@ -45,6 +47,8 @@ foldMapBuilder, ) where +import Control.Monad.IO.Class (liftIO)+import Control.Monad.Trans.Except (throwE, ExceptT) import Data.Bits import Data.ByteString (ByteString) import Data.ByteString.Lazy.Builder as Builder@@ -53,13 +57,16 @@ import Data.Int (Int32, Int64) import Data.Monoid ((<>)) import qualified Data.Vector.Generic as V-import Data.Word (Word32, Word64)+import Data.Word (Word8, Word32, Word64)+import Foreign.Marshal (malloc, free)+import Foreign.Storable (peek)+import System.IO (Handle, hGetBuf) #if MIN_VERSION_base(4,11,0) import qualified GHC.Float as Float #else import Foreign.Ptr (castPtr) import Foreign.Marshal.Alloc (alloca)-import Foreign.Storable (Storable, peek, poke)+import Foreign.Storable (Storable, poke) import System.IO.Unsafe (unsafePerformIO) #endif @@ -76,14 +83,43 @@ -- VarInts are inherently unsigned; there are different ways of encoding -- negative numbers for int32/64 and sint32/64. getVarInt :: Parser Word64-getVarInt = loop 1 0+getVarInt = loopStart 0 1 where- loop !s !n = do- b <- getWord8- let n' = n + s * fromIntegral (b .&. 127)- if (b .&. 128) == 0- then return $! n'- else loop (128*s) n'+ loopStart !n !s = getWord8 >>= getVarIntLoopFinish loopStart n s++-- Same as getVarInt but reads from a Handle+getVarIntH :: Handle -> ExceptT String IO Word64+getVarIntH h = do+ buf <- liftIO malloc+ let loopStart !n !s =+ (liftIO $ hGetBuf h buf 1) >>=+ \case+ 1 -> (liftIO $ peek buf) >>=+ getVarIntLoopFinish loopStart n s+ _ -> throwE "Unexpected end of file"+ res <- loopStart 0 1+ liftIO $ free buf+ return res++getVarIntLoopFinish+ :: (Monad m)+ => (Word64 -> Word64 -> m Word64) -- "loop start" callback+ -> Word64+ -> Word64+ -> Word8+ -> m Word64+getVarIntLoopFinish ls !n !s !b = do+ let n' = decodeVarIntStep n s b+ if testMsb b+ then ls n' (128*s)+ else return $! n'++-- n -- result of previous step; s -- 128^{step index}; b -- step byte+decodeVarIntStep :: Word64 -> Word64 -> Word8 -> Word64+decodeVarIntStep n s b = n + s * fromIntegral (b .&. 127)++testMsb :: Word8 -> Bool+testMsb b = (b .&. 128) /= 0 putVarInt :: Word64 -> Builder putVarInt n