pipes-binary (empty) → 0.1.0.0
raw patch · 8 files changed
+266/−0 lines, 8 filesdep +basedep +binarydep +bytestringsetup-changed
Dependencies added: base, binary, bytestring, pipes, pipes-parse
Files
- LICENSE +30/−0
- NEWS +3/−0
- PEOPLE +5/−0
- README.md +13/−0
- Setup.hs +2/−0
- pipes-binary.cabal +36/−0
- src/Control/Proxy/Binary.hs +122/−0
- src/Control/Proxy/Binary/Internal.hs +55/−0
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2013, Renzo Carbonara++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Renzo Carbonara nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ NEWS view
@@ -0,0 +1,3 @@+# Version 0.1.0.0++* Initial version.
+ PEOPLE view
@@ -0,0 +1,5 @@+The following people have participated in creating this library, either+by directly contributing code or by providing thoughtful input in+discussions about the library design.++Renzo Carbonara
+ README.md view
@@ -0,0 +1,13 @@+# pipes-binary++Utilities to encode and decode binary streams using the **pipes** and+**binary** libraries.++Check the source or rendered Haddocks for extensive documentation.++This code is licensed under the terms of the so called **3-clause BSD+license**. Read the file named ``LICENSE`` found in this same directory+for details.++See the ``PEOPLE`` file to learn about the people involved in this+effort.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ pipes-binary.cabal view
@@ -0,0 +1,36 @@+name: pipes-binary+version: 0.1.0.0+license: BSD3+license-file: LICENSE+copyright: Copyright (c) Renzo Carbonara 2013+author: Renzo Carbonara+maintainer: renzocarbonaraλgmail.com+stability: Experimental+tested-with: GHC == 7.4.1+homepage: https://github.com/k0001/pipes-binary+bug-reports: https://github.com/k0001/pipes-binary/issues+category: Pipes+build-type: Simple+synopsis: Encode and decode binary streams using the pipes and binary libraries.+cabal-version: >=1.8+extra-source-files: README.md PEOPLE NEWS+description:+ Encode and decode binary streams using the @Pipes@ and @binary@ libraries.+ .+ See the @NEWS@ file in the source distribution to learn about any+ important changes between version.++source-repository head+ type: git+ location: git://github.com/k0001/pipes-binary.git++library+ hs-source-dirs: src+ build-depends: base (==4.*)+ , binary (>=0.7 && <0.8)+ , bytestring (>=0.9.2.1)+ , pipes (>=3.3 && <3.4)+ , pipes-parse (>=1.0 && <1.1)+ exposed-modules: Control.Proxy.Binary+ other-modules: Control.Proxy.Binary.Internal+ ghc-options: -Wall -O2
+ src/Control/Proxy/Binary.hs view
@@ -0,0 +1,122 @@+-- | This module exports facilities that allows you to encode and decode+-- streams of 'Bin.Binary' values using the @pipes@ and @pipes-parse@ libraries.++module Control.Proxy.Binary+ ( -- * Decoding+ -- $decoding+ decode+ , decodeD+ -- * Encoding+ -- $encoding+ , encode+ , encodeD+ -- * Types+ , I.DecodingError(..)+ ) where++-------------------------------------------------------------------------------++import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy.Internal as BLI+import Control.Monad (unless)+import qualified Control.Proxy as P+import qualified Control.Proxy.Binary.Internal as I+import qualified Control.Proxy.Parse as Pa+import qualified Control.Proxy.Trans.Either as P+import qualified Control.Proxy.Trans.State as P+import qualified Data.Binary as Bin+import Data.Foldable (mapM_)+import Data.Function (fix)+import Prelude hiding (mapM_)++--------------------------------------------------------------------------------+-- $decoding+--+-- There are two different 'Bin.Binary' decoding facilities exported by this+-- module, and choosing between them is easy: If you need to interleave decoding+-- with other stream effects you must use 'decode', otherwise you may use the+-- simpler 'decodeD'.++-- | Decodes one 'Bin.Binary' instance flowing downstream.+--+-- * In case of decoding errors, a 'I.DecodingError' exception is thrown in the+-- 'Pe.EitherP' proxy transformer.+--+-- * Requests more input from upstream using 'Pa.draw' when needed.+--+-- * /Do not/ use this proxy if 'Control.Proxy.ByteString.isEndOfBytes' returns+-- 'True', otherwise you may get unexpected decoding errors.+decode+ :: (P.Proxy p, Monad m, Bin.Binary r)+ => P.EitherP I.DecodingError (P.StateP [BS.ByteString] p)+ () (Maybe BS.ByteString) y' y m r+decode = do+ (er, mlo) <- P.liftP (I.parseWith Pa.draw Bin.get)+ P.liftP (mapM_ Pa.unDraw mlo)+ either P.throw return er+{-# INLINABLE decode #-}+++-- | Decodes 'Bin.Binary' instances flowing downstream until end of input.+--+-- * In case of decoding errors, a 'I.DecodingError' exception is thrown in the+-- 'Pe.EitherP' proxy transformer.+--+-- * Requests more input from upstream using 'Pa.draw', when needed.+--+-- * Empty input chunks flowing downstream will be discarded.+decodeD+ :: (P.Proxy p, Monad m, Bin.Binary b)+ => ()+ -> P.Pipe (P.EitherP I.DecodingError (P.StateP [BS.ByteString] p))+ (Maybe BS.ByteString) b m ()+decodeD = \() -> loop where+ loop = do+ eof <- P.liftP isEndOfBytes+ unless eof $ decode >>= P.respond >> loop+{-# INLINABLE decodeD #-}++--------------------------------------------------------------------------------+-- $encoding+--+-- There are two different 'Bin.Binary' encoding facilities exported by this+-- module, and choosing between them is easy: If you need to interleave encoding+-- with other stream effects you must use 'encode', otherwise you may use the+-- simpler 'encodeD'.++-- | Encodes the given 'Bin.Binary' instance and sends it downstream in+-- 'BS.ByteString' chunks.+encode+ :: (P.Proxy p, Monad m, Bin.Binary x)+ => x -> p x' x () BS.ByteString m ()+encode = \x -> P.runIdentityP $ do+ BLI.foldrChunks (\e a -> P.respond e >> a) (return ()) (Bin.encode x)+{-# INLINABLE encode #-}+++-- | Encodes 'Bin.Binary' instances flowing downstream, each in possibly more+-- than one 'BS.ByteString' chunk.+encodeD+ :: (P.Proxy p, Monad m, Bin.Binary a)+ => () -> P.Pipe p a BS.ByteString m r+encodeD = P.pull P./>/ encode+{-# INLINABLE encodeD #-}+++--------------------------------------------------------------------------------+-- XXX: this function is here until pipes-bytestring exports it++-- | Like 'Pa.isEndOfInput', except it also consumes and discards leading+-- empty 'BS.ByteString' chunks.+isEndOfBytes+ :: (Monad m, P.Proxy p)+ => P.StateP [BS.ByteString] p () (Maybe BS.ByteString) y' y m Bool+isEndOfBytes = fix $ \loop -> do+ ma <- Pa.draw+ case ma of+ Just a+ | BS.null a -> loop+ | otherwise -> Pa.unDraw a >> return False+ Nothing -> return True+{-# INLINABLE isEndOfBytes #-}+
+ src/Control/Proxy/Binary/Internal.hs view
@@ -0,0 +1,55 @@+{-# LANGUAGE DeriveDataTypeable #-}++-- | This module provides low-level integration with the @binary@ package and is+-- likely to be modified in backwards-incompatible ways in the future.+--+-- Use the "Control.Proxy.Binary" module instead.++module Control.Proxy.Binary.Internal+ ( DecodingError(..)+ , parseWith+ ) where++-------------------------------------------------------------------------------++import qualified Data.ByteString as BS+import qualified Data.Binary as Bin+import qualified Data.Binary.Get as Bin+import Control.Exception (Exception)+import Data.Data (Data, Typeable)++-------------------------------------------------------------------------------++data DecodingError = DecodingError+ { peConsumed :: Bin.ByteOffset -- ^Number of bytes consumed before the error.+ , peMessage :: String -- ^Error message.+ } deriving (Show, Eq, Data, Typeable)++instance Exception DecodingError++-------------------------------------------------------------------------------++-- | Run a parser drawing input from the given monadic action as needed.+parseWith+ :: (Monad m, Bin.Binary r)+ => m (Maybe BS.ByteString)+ -- ^An action that will be executed to provide the parser with more input+ -- as needed. If the action returns 'Nothing', then it's assumed no more+ -- input is available.+ -> Bin.Get r+ -- ^Parser to run on the given input.+ -> m (Either DecodingError r, Maybe BS.ByteString)+ -- ^Either a parser error or a parsed result, together with any leftover.+parseWith refill g = step $ Bin.runGetIncremental g+ where+ step (Bin.Partial k) = step . k =<< refill+ step (Bin.Done lo _ r) = return (Right r, mayInput lo)+ step (Bin.Fail lo n m) = return (Left (DecodingError n m), mayInput lo)+{-# INLINABLE parseWith #-}++-- | Wrap @a@ in 'Just' if not-null. Otherwise, 'Nothing'.+mayInput :: BS.ByteString -> Maybe BS.ByteString+mayInput x | BS.null x = Nothing+ | otherwise = Just x+{-# INLINE mayInput #-}+