machines-bytestring (empty) → 0.1.0.0
raw patch · 5 files changed
+224/−0 lines, 5 filesdep +basedep +bytestringdep +machinessetup-changed
Dependencies added: base, bytestring, machines
Files
- ChangeLog.md +5/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- machines-bytestring.cabal +25/−0
- src/Data/Machine/ByteString.hs +162/−0
+ ChangeLog.md view
@@ -0,0 +1,5 @@+# Revision history for machines-bitestring++## 0.1.0.0++* initial release
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2017, Claudio Zanasi++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 Claudio Zanasi 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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ machines-bytestring.cabal view
@@ -0,0 +1,25 @@+name: machines-bytestring+version: 0.1.0.0+cabal-version: >=1.10+build-type: Simple+synopsis: ByteString support for machines+description: @machines@ utilities to work with @ByteString@+license: BSD3+license-file: LICENSE+author: Claudio Zanasi+maintainer: claudio.zan@outlook.com+copyright: 2017 Claudio Zanasi+category: Control, Machines+extra-source-files: ChangeLog.md+Source-Repository head+ Type: git+ Location: https://github.com/zclod/machines-bytestring++library+ exposed-modules: Data.Machine.ByteString+ hs-source-dirs: src+ default-language: Haskell2010+ GHC-Options: -Wall -O2+ build-depends: base >= 4 && < 5,+ bytestring >= 0.10 && < 0.11,+ machines >= 0.6 && < 0.7
+ src/Data/Machine/ByteString.hs view
@@ -0,0 +1,162 @@+{-# LANGUAGE Rank2Types #-}+module Data.Machine.ByteString (+ -- * Sources+ fromLazy,+ fromStrict,+ fromHandle,+ hGet,+ hGetSome,+ hGetNonBlocking,+ -- * Sinks+ stdin,+ stdout,+ stderr,+ toHandle,+ interact,+ -- * Processes+ mapping,+ filtered,+ taking,+ takingWhile,+ scan,+ -- Stream Transformation+ pack,+ unpack+ ) where++import Data.Word (Word8)+import Data.Machine hiding (filtered, mapping, taking, takingWhile, scan)+import Data.ByteString (ByteString)+import qualified Data.ByteString as B+import Data.ByteString.Unsafe (unsafeTake)+import Data.ByteString.Lazy.Builder.Extras (defaultChunkSize)+import qualified Data.ByteString.Lazy as BL+import qualified System.IO as IO+import Control.Monad.IO.Class (MonadIO(..))+import Prelude hiding (interact)++-- | Transform a lazy ByteString into a 'Source' of strict 'ByteString'.+fromLazy :: BL.ByteString -> Source ByteString+fromLazy bs = construct $ BL.foldrChunks (\e a -> yield e >> a) (pure ()) bs++-- | Use a strict ByteString as Source+fromStrict :: ByteString -> Source ByteString+fromStrict bs = construct $ yield bs++-- | Use an 'Handle' to create a 'Source' of strict 'ByteString'.+fromHandle :: MonadIO m => IO.Handle -> SourceT m ByteString+fromHandle = hGetSome defaultChunkSize++-- | Read chunks of strict 'ByteString' of fixed size.+hGet :: MonadIO m => Int -> IO.Handle -> SourceT m ByteString+hGet size h = repeatedly $ do+ bs <- liftIO (B.hGet h size)+ if B.null bs+ then pure ()+ else yield bs++-- | Like 'hGet' but may be returned smaller chunks if there are not enough+-- data immediately available.+hGetSome :: MonadIO m => Int -> IO.Handle -> SourceT m ByteString+hGetSome size h = repeatedly $ do+ bs <- liftIO (B.hGetSome h size)+ if B.null bs+ then pure ()+ else yield bs++-- | Similar to 'hGet' but it will never block waiting for data.+hGetNonBlocking :: MonadIO m => Int -> IO.Handle -> SourceT m ByteString+hGetNonBlocking size h = repeatedly $ do+ eof <- liftIO (IO.hIsEOF h)+ if eof+ then pure ()+ else liftIO (B.hGetNonBlocking h size)>>= yield++-- | Source that stream bytes from 'stdin'+stdin :: MonadIO m => SourceT m ByteString+stdin = fromHandle IO.stdin++-- | Create a 'Machine' that stream its input to the given 'Handle'+toHandle :: MonadIO m => IO.Handle -> MachineT m (Is ByteString) ()+toHandle h = autoM (liftIO . B.hPut h)++-- | Stream data to 'stdout'+stdout :: MonadIO m => MachineT m (Is ByteString) ()+stdout = toHandle IO.stdout++-- | Stream data to 'stderr'+stderr :: MonadIO m => MachineT m (Is ByteString) ()+stderr = toHandle IO.stderr++-- | Use a @Process ByteString ByteString@ to transform the input from+-- 'stdin' and output to 'stdout'+interact :: Process ByteString ByteString -> IO ()+interact p = runT_ $ stdin ~> p ~> stdout++-- | Transform every byte of a 'ByteString'+mapping :: (Word8 -> Word8) -> Process ByteString ByteString+mapping f = auto $ B.map f++-- | Allow to pass only the bytes that satisfy the predicate+filtered :: (Word8 -> Bool) -> Process ByteString ByteString+filtered p = auto $ B.filter p++-- | Stream only the first n bytes+taking :: Integral n => n -> Process ByteString ByteString+taking n0 = construct $ go n0+ where+ go n+ | n <= 0 = pure ()+ | otherwise = do+ bs <- await+ let len = fromIntegral (B.length bs)+ if len > n+ then yield (unsafeTake (fromIntegral n) bs)+ else yield bs >> go (n - len)++-- | Stream bytes until they fail the predicate+takingWhile :: (Word8 -> Bool) -> Process ByteString ByteString+takingWhile p = construct go+ where+ go = do+ bs <- await+ let (prefix, suffix) = B.span p bs+ if B.null suffix+ then yield bs >> go+ else yield prefix++-- Drop the first n bytes+-- dropping :: Integral n => n -> Process ByteString ByteString+-- dropping n = loop n+-- where+-- loop cnt+-- | cnt <= 0 = echo+-- | otherwise = do+-- bs <- await+-- let l = B.length bs+-- if l <= cnt+-- then loop (cnt - l)+-- else pure . B.drop l >>= yield >> loop (cnt - l)+++-- | Strict left scan over the bytes+scan :: (Word8 -> Word8 -> Word8) -> Word8 -> Process ByteString ByteString+scan step begin = construct $ do+ yield (B.singleton begin)+ go begin+ where+ go w8 = do+ bs <- await+ let bs' = B.scanl step w8 bs+ w8' = B.last bs'+ yield (B.tail bs')+ go w8'++-- | Convert a stream of strict 'ByteString' into a stream of Bytes+unpack :: Process ByteString Word8+unpack = auto B.unpack ~> asParts++-- | Convert a stream of Bytes into a stream of strict 'ByteString' of+-- size equal to 'defaultChunkSize'+pack :: Process Word8 ByteString+pack = buffered defaultChunkSize ~> auto B.pack