module Data.Machine.ByteString (
fromLazy,
fromStrict,
fromHandle,
hGet,
hGetSome,
hGetNonBlocking,
stdin,
stdout,
stderr,
toHandle,
interact,
mapping,
filtered,
taking,
takingWhile,
scan,
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)
fromLazy :: BL.ByteString -> Source ByteString
fromLazy bs = construct $ BL.foldrChunks (\e a -> yield e >> a) (pure ()) bs
fromStrict :: ByteString -> Source ByteString
fromStrict bs = construct $ yield bs
fromHandle :: MonadIO m => IO.Handle -> SourceT m ByteString
fromHandle = hGetSome defaultChunkSize
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
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
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
stdin :: MonadIO m => SourceT m ByteString
stdin = fromHandle IO.stdin
toHandle :: MonadIO m => IO.Handle -> MachineT m (Is ByteString) ()
toHandle h = autoM (liftIO . B.hPut h)
stdout :: MonadIO m => MachineT m (Is ByteString) ()
stdout = toHandle IO.stdout
stderr :: MonadIO m => MachineT m (Is ByteString) ()
stderr = toHandle IO.stderr
interact :: Process ByteString ByteString -> IO ()
interact p = runT_ $ stdin ~> p ~> stdout
mapping :: (Word8 -> Word8) -> Process ByteString ByteString
mapping f = auto $ B.map f
filtered :: (Word8 -> Bool) -> Process ByteString ByteString
filtered p = auto $ B.filter p
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)
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
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'
unpack :: Process ByteString Word8
unpack = auto B.unpack ~> asParts
pack :: Process Word8 ByteString
pack = buffered defaultChunkSize ~> auto B.pack