packages feed

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 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