packages feed

pinch 0.4.3.0 → 0.5.0.0

raw patch · 6 files changed

+75/−58 lines, 6 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Pinch.Internal.Builder: unsafeRunBuilder :: Builder -> Ptr Word8 -> IO ()
- Pinch.Transport: cGetSome :: Connection c => c -> Int -> IO ByteString
+ Pinch.Transport: cGetSome :: Connection c => c -> IO ByteString
- Pinch.Transport: cPut :: Connection c => c -> ByteString -> IO ()
+ Pinch.Transport: cPut :: Connection c => c -> Builder -> IO ()

Files

CHANGES.md view
@@ -1,3 +1,18 @@+0.5.0.0 (2023-08-07)+=====================++- (**Breaking**) Transport:+  `cGetSome` no longer takes an int parameter.+  Implementations should return all available bytes (blocking if necessary)+  or an empty string for EOF. (#54)+- (**Breaking**) Transport:+  `cPut` accepts a `Builder `instead of a `ByteString`.+  Implementations should use `runBuilder` to turn it into a `ByteString`+  if needed. (#55)+- Add a `Pinch.Transport.Builder` module exporting the `Builder` type;+  a length-aware `ByteString` builder. (#55)++ 0.4.3.0 (2023-04-27) ===================== 
pinch.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           pinch-version:        0.4.3.0+version:        0.5.0.0 synopsis:       An alternative implementation of Thrift for Haskell. description:    This library provides machinery for types to specify how they can be                 serialized and deserialized into/from Thrift payloads. It makes no@@ -63,6 +63,7 @@       Pinch.Protocol.Compact       Pinch.Server       Pinch.Transport+      Pinch.Transport.Builder   other-modules:       Pinch.Internal.Bits       Pinch.Internal.Pinchable.Parser
src/Pinch/Internal/Builder.hs view
@@ -13,6 +13,7 @@ module Pinch.Internal.Builder     ( Builder     , runBuilder+    , unsafeRunBuilder      , append     , int8@@ -47,6 +48,12 @@ runBuilder :: Builder -> ByteString runBuilder (B size fill) = BI.unsafeCreate size fill {-# INLINE runBuilder #-}++-- | Fill a buffer with the bytes of a builder. The buffer is assumed+-- to be big enough to hold the contents of the entire builder.+unsafeRunBuilder :: Builder -> Ptr Word8 -> IO ()+unsafeRunBuilder (B _size fill) = fill+{-# INLINE unsafeRunBuilder #-}  -- | Append two Builders into one. append :: Builder -> Builder -> Builder
src/Pinch/Transport.hs view
@@ -19,18 +19,18 @@ import qualified Pinch.Internal.Builder as B  class Connection c where-  -- | Gets up to n bytes. Returns an empty bytestring if EOF is reached.-  cGetSome :: c -> Int -> IO BS.ByteString-  -- | Writes the given bytestring.-  cPut :: c -> BS.ByteString -> IO ()+  -- | Returns available bytes, or an empty bytestring if EOF was reached.+  cGetSome :: c -> IO BS.ByteString+  -- | Writes the given builder.+  cPut :: c -> B.Builder -> IO ()  instance Connection Handle where-  cPut = BS.hPut-  cGetSome = BS.hGetSome+  cPut c b = BS.hPut c (B.runBuilder b)+  cGetSome h = BS.hGetSome h 1024  instance Connection Socket where-  cPut = sendAll-  cGetSome s n = recv s (min n 4096)+  cPut c b = sendAll c (B.runBuilder b)+  cGetSome s = recv s 4096  data ReadResult a   = RRSuccess a@@ -47,28 +47,21 @@  -- | Creates a thrift framed transport. See also <https://github.com/apache/thrift/blob/master/doc/specs/thrift-rpc.md#framed-vs-unframed-transport>. framedTransport :: Connection c => c -> IO Transport-framedTransport c = pure $ Transport writeMsg readMsg where+framedTransport c = do+  readBuffer <- newIORef mempty+  pure $ Transport writeMsg (readMsg readBuffer) where   writeMsg msg = do-    cPut c $ B.runBuilder $ B.int32BE (fromIntegral $ B.getSize msg)-    cPut c $ B.runBuilder msg--  readMsg p = do-    szBs <- getExactly c 4-    if BS.length szBs < 4-      then-        pure $ RREOF-      else do-        let sz = fromIntegral <$> G.runGet G.getInt32be szBs-        case sz of-          Right x -> do-            msgBs <- getExactly c x-            pure $ if BS.length msgBs < x-              then-                -- less data has been returned than expected. This means we have reached EOF.-                RREOF-              else-                either RRFailure RRSuccess $ G.runGet p msgBs-          Left s -> pure $ RRFailure $ "Invalid frame size: " ++ show s+    cPut c $ B.int32BE (fromIntegral $ B.getSize msg) <> msg+  readMsg readBuffer parser = do+    let +      frameParser = do +        size <- G.getInt32be+        G.isolate (fromIntegral size) parser+    +    initial <- readIORef readBuffer+    (leftovers, r) <- runGetWith (cGetSome c) frameParser initial+    writeIORef readBuffer $! leftovers+    pure r  -- | Creates a thrift unframed transport. See also <https://github.com/apache/thrift/blob/master/doc/specs/thrift-rpc.md#framed-vs-unframed-transport>. unframedTransport :: Connection c => c -> IO Transport@@ -80,15 +73,13 @@   readBuffer <- newIORef mempty   pure $ Transport writeMsg (readMsg readBuffer)   where-    writeMsg msg = cPut c $ B.runBuilder msg+    writeMsg = cPut c      readMsg buf p = do-      bs <- readIORef buf-      bs' <- if BS.null bs then getSome else pure bs-      (leftOvers, r) <- runGetWith getSome p bs'-      writeIORef buf leftOvers-      pure $ r-    getSome = cGetSome c 1024+      initial <- readIORef buf+      (leftovers, r) <- runGetWith (cGetSome c) p initial+      writeIORef buf $! leftovers+      pure r  -- | Runs a Get parser incrementally, reading more input as necessary until a successful parse -- has been achieved.@@ -108,17 +99,3 @@             pure (bs, RREOF)           else             go $ cont bs-  --- | Gets exactly n bytes. If EOF is reached, an empty string is returned.-getExactly :: Connection c => c -> Int -> IO BS.ByteString-getExactly c sz = B.runBuilder <$> go sz mempty-  where-    go :: Int -> B.Builder -> IO B.Builder-    go n b = do-      bs <- cGetSome c n-      let b' = b <> B.byteString bs-      case BS.length bs of-        -- EOF, return what data we might have gotten so far-        0 -> pure mempty-        n' | n' < n -> go (n - n') b'-        _  | otherwise -> pure b'
+ src/Pinch/Transport/Builder.hs view
@@ -0,0 +1,17 @@+-- |+-- Module      :  Pinch.Transport.Builder+-- Copyright   :  (c) Abhinav Gupta 2023+-- License     :  BSD3+--+-- Maintainer  :  Abhinav Gupta <mail@abhinavg.net>+-- Stability   :  experimental+--+-- This module implements a ByteString builder very similar to+-- 'Data.ByteString.Builder' except that it keeps track of its final serialized+-- length. This allows it to allocate the target ByteString in one @malloc@ and+-- simply write the bytes to it.+module Pinch.Transport.Builder +    ( module B+    ) where++import Pinch.Internal.Builder as B
tests/Pinch/TransportSpec.hs view
@@ -29,13 +29,13 @@ mGetContents = readIORef . contents  instance Connection MemoryConnection where-  cGetSome (MemoryConnection ref ch) n = do+  cGetSome (MemoryConnection ref ch) = do     bytes <- readIORef ref-    let (left, right) = BS.splitAt (min ch n) bytes+    let (left, right) = BS.splitAt ch bytes     writeIORef ref right     return left-  cPut (MemoryConnection ref _) newBytes = do-    modifyIORef ref (<> newBytes)+  cPut (MemoryConnection ref _) builder = do+    modifyIORef ref (<> B.runBuilder builder)  transportSpec :: (forall c . Connection c => c -> IO Transport) -> Spec transportSpec t = do@@ -63,8 +63,8 @@       let payload = BS.pack [0x01, 0x05, 0x01, 0x08, 0xFF]       buf <- newMemoryConnection 1       transp <- framedTransport buf-      cPut buf $ BS.pack [0x00, 0x00, 0x00, 0x05]-      cPut buf payload+      cPut buf $ B.byteString (BS.pack [0x00, 0x00, 0x00, 0x05])+      cPut buf $ B.byteString payload       r <- readMessage transp (G.getBytes $ BS.length payload)       r `shouldBe` RRSuccess payload @@ -84,7 +84,7 @@       ioProperty $ do         buf <- newMemoryConnection 1         transp <- unframedTransport buf-        cPut buf payload+        cPut buf $ B.byteString payload         r <- readMessage transp (G.getBytes $ BS.length payload)         pure $ r === RRSuccess payload