packages feed

streamly-examples-0.1.0: examples/CoreUtilsHandle.hs

-- This is same as the examples in CoreUtils but uses the Handle API instead of
-- the FilePath based APIs.

import Data.Function ((&))
import System.Environment (getArgs)
import System.IO (IOMode(..), stdin, stdout, Handle, openFile)

import qualified Streamly.Data.Fold as Fold
import qualified Streamly.FileSystem.Handle as Handle
import qualified Streamly.Prelude as Stream
import qualified Streamly.Unicode.Stream as Unicode

import qualified Streamly.Internal.Data.Array.Stream.Foreign as ArrayStream (splitOn)

-- | Read the contents of a file to stdout.
--
-- Handle.read reads the file in 32KB chunks and converts the chunks into a byte
-- stream. FH.write takes the byte stream as input, converts it into chunks of
-- 32KB and writes those chunks to stdout.
--
catBytes :: Handle -> IO ()
catBytes src =
      Stream.unfold Handle.read src     -- SerialT IO Word8
    & Stream.fold (Handle.write stdout) -- IO ()

-- | Chunked version, more efficient than the byte stream version above. Reads
-- the file in 256KB chunks and writes those chunks to stdout.
cat :: Handle -> IO ()
cat src =
      Stream.unfold Handle.readChunksWithBufferOf (256*1024, src) -- SerialT IO (Array Word8)
    & Stream.fold (Handle.writeChunks stdout) -- IO ()

-- | Read from standard input write to standard output
echo :: IO ()
echo =
      Stream.unfold Handle.readChunks stdin   -- SerialT IO (Array Word8)
    & Stream.fold (Handle.writeChunks stdout) -- IO ()

-- | Copy a source file to a destination file.
--
-- Handle.read reads the file in 32KB chunks and converts the chunks into a byte
-- stream. FH.write takes the byte stream as input, converts it into chunks of
-- 32KB and writes those chunks to the destination file.
cpBytes :: Handle -> Handle -> IO ()
cpBytes src dst =
      Stream.unfold Handle.read src  -- SerialT IO Word8
    & Stream.fold (Handle.write dst) -- IO ()

-- | Chunked version, more efficient than the byte stream version above. Reads
-- the file in 256KB chunks and writes those chunks to stdout.
cp :: Handle -> Handle -> IO ()
cp src dst =
      Stream.fold (Handle.writeChunks dst)
    $ Stream.unfold Handle.readChunksWithBufferOf (256*1024, src)

-- | Count lines like wc -l.
--
-- Char stream version. Reads the input as a byte stream, splits it into lines
-- and counts the lines..
wclChar :: Handle -> IO Int
wclChar src =
      Stream.unfold Handle.read src             -- SerialT IO Word8
    & Unicode.decodeLatin1                      -- SerialT IO Char
    & Stream.splitOnSuffix (== '\n') Fold.drain -- SerialT IO ()
    & Stream.length                             -- IO ()

-- | More efficient chunked version. Reads chunks from the input handles and
-- splits the chunks directly instead of converting them into byte stream
-- first.
wcl :: Handle -> IO Int
wcl src =
      Stream.unfold Handle.readChunks src -- SerialT IO (Array Word8)
    & ArrayStream.splitOn 10              -- SerialT IO (Array Word8)
    & Stream.length                       -- IO ()

main :: IO ()
main = do
    cmd <- fmap head getArgs
    src <- openFile "input.txt" ReadMode
    dst <- openFile "output.txt" WriteMode

    case cmd of
        "cat" -> putStrLn "cat" >> cat src
        "catBytes" -> putStrLn "catBytes" >> catBytes src
        "echo" -> putStrLn "echo" >> echo
        "cp" -> putStrLn "cp" >> cp src dst
        "cpBytes" -> putStrLn "cpBytes" >> cpBytes src dst
        "wcl" -> putStrLn "wcl" >> (wcl src >>= print)
        "wclChar" -> putStrLn "wclChar" >> (wclChar src >>= print)
        _ -> putStrLn $ "Unknown command: " ++ cmd