{-# LANGUAGE DeriveGeneric, StandaloneDeriving, GeneralizedNewtypeDeriving
, DeriveFunctor, MultiParamTypeClasses #-}
module Main where
import System.IO
import System.Environment (getArgs)
import qualified Streamly as S
import qualified Streamly.Prelude as S
import Control.DeepSeq
import GHC.Generics
import qualified Data.Csv as Csv
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as BSL
import qualified Data.Vector as V
import Control.Monad.Error.Class
import Control.Monad.Catch
import Control.Monad.IO.Class
import Streamly.Csv
import qualified Streaming as ST
import qualified Streaming.With as ST
import qualified Streaming.Prelude as ST
import qualified Streaming.Cassava as CsvST
import qualified Data.ByteString.Streaming as BSS
deriving instance Generic CsvParseException
instance NFData CsvParseException
main :: IO ()
main = do
(mode:testfile:_) <- getArgs
case mode of
"streamly" ->
copyAllStreamly testfile $ "out_"<>testfile
"cassava" ->
copyAllCassava testfile $ "out_"<>testfile
"streaming" -> do
recs <- readAllStreaming testfile
print $ length (force recs)
_ -> error "First argument should be 'streamly', 'streaming', or 'cassava'"
readAllStreamly :: FilePath -> IO [V.Vector BS.ByteString]
readAllStreamly filename = do
h <- openFile filename ReadMode
let chunks = chunkStream h (64*1024)
recs = decode Csv.HasHeader chunks
S.toList recs
readAllCassava :: FilePath -> IO (V.Vector (V.Vector BS.ByteString))
readAllCassava filename = do
contents <- BSL.readFile filename
either (error . show) return $
Csv.decode Csv.HasHeader contents
copyAllCassava :: FilePath -> FilePath -> IO ()
copyAllCassava fIn fOut = do
contents <- BSL.readFile fIn
recs <- either (error . show) return $
Csv.decode Csv.HasHeader contents :: IO (V.Vector (V.Vector BS.ByteString))
BSL.writeFile fOut $ Csv.encode $ V.toList recs
copyAllStreamly :: FilePath -> FilePath -> IO ()
copyAllStreamly fIn fOut = do
h <- openFile fIn ReadMode
let chunks = chunkStream h (64*1024)
recs = decode Csv.HasHeader chunks :: S.SerialT IO (V.Vector BS.ByteString)
withFile fOut WriteMode $ \ho ->
S.mapM_ (BS.hPut ho) $ encode Nothing recs
newtype StupidMonad a = StupidMonad {runStupid :: IO a}
deriving (Functor, Applicative, Monad, MonadIO, MonadMask
, MonadCatch, MonadThrow)
instance MonadError CsvST.CsvParseException StupidMonad where
throwError e = StupidMonad (throwM e)
catchError (StupidMonad a) f = StupidMonad $ catch a (runStupid . f)
readAllStreaming :: FilePath -> IO [V.Vector BS.ByteString]
readAllStreaming filename = ST.withBinaryFileContents filename go
where
go :: BSS.ByteString IO () -> IO [V.Vector BS.ByteString]
go contents =
let recs :: ST.Stream (ST.Of (V.Vector BS.ByteString)) StupidMonad ()
recs = CsvST.decode HasHeader (ST.hoist StupidMonad contents)
in runStupid $ ST.toList_ recs