Frames-streamly-0.3.1.0: src/Frames/Streamly/Streaming/Streamly.hs
{-# LANGUAGE BangPatterns #-}
{-# LANGUAGE CPP #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE InstanceSigs #-}
module Frames.Streamly.Streaming.Streamly
(
StreamlyStream(..)
-- * re-exports
#if MIN_VERSION_streamly(0,9,0)
, Stream
#else
, SerialT
, IsStream
#endif
)
where
import Frames.Streamly.Streaming.Class
import qualified Frames.Streamly.Streaming.Common as Common
import Frames.Streamly.Internal.CSV (FramesCSVException(..))
import Control.Monad.Catch ( MonadThrow(..), MonadCatch)
import Control.Foldl (PrimMonad)
import Control.Exception (try)
import qualified Control.Monad.Trans.Control as MC
import qualified Data.Text as T
import qualified Data.Text.Encoding as Text
import Data.Word8 (_lf)
#if MIN_VERSION_streamly(0,9,0)
import qualified Streamly.Data.Fold as Streamly.Fold
import Streamly.Data.Stream (Stream)
import qualified Streamly.Data.Stream as Streamly
import qualified Streamly.Data.StreamK as StreamK
import qualified Streamly.FileSystem.File as Streamly.File
import qualified Streamly.Unicode.Stream as Unicode
import qualified Streamly.Data.Unfold as Streamly.Unfold
import qualified Streamly.FileSystem.Handle as Streamly.Handle
import qualified Streamly.Internal.Data.Stream.Chunked as Array.Stream
import qualified Streamly.External.ByteString as Streamly.BS
#elif MIN_VERSION_streamly(0,8,0)
import qualified Streamly.Prelude as Streamly
import qualified Streamly.Data.Fold as Streamly.Fold
import qualified Streamly.Internal.FileSystem.File as Streamly.File
import qualified Streamly.Internal.FileSystem.Handle as Streamly.Handle
import qualified Streamly.Internal.Data.Unfold as Streamly.Unfold
import qualified Streamly.External.ByteString as Streamly.BS
import Streamly.Prelude (IsStream, SerialT)
import qualified Streamly.Unicode.Stream as Unicode
import qualified Streamly.Internal.Data.Array.Stream.Foreign as Array.Stream
import qualified Streamly.Internal.Data.Stream.StreamD.Generate as StreamD
import qualified Streamly.Internal.Data.Stream.StreamD.Type as StreamD
import qualified Streamly.Internal.Data.Stream.StreamD.Transform as StreamD
#else
import qualified Streamly as Streamly
import Streamly ( IsStream, SerialT )
import qualified Streamly.Data.Unicode.Stream as Streamly.Unicode
import qualified Streamly.Internal.Data.Fold as Streamly.Fold
#endif
import qualified Data.Text.IO as Text
import qualified System.IO as IO
import GHC.IO.Exception (IOException)
newtype StreamlyStream (t :: (Type -> Type) -> Type -> Type) m a = StreamlyStream { stream :: t m a }
#if MIN_VERSION_streamly(0,9,0)
instance (Monad m) => StreamFunctions (StreamlyStream Streamly.Stream) m where
type FoldType (StreamlyStream Streamly.Stream) = Streamly.Fold.Fold
sThrowIfEmpty = streamlyThrowIfEmpty . stream
sLength = Streamly.fold Streamly.Fold.length . stream
sCons a = StreamlyStream . Streamly.cons a . stream
sUncons = streamlyStreamUncons
sHead = Streamly.fold Streamly.Fold.one . stream
sMap f = StreamlyStream . fmap f . stream
sMapMaybe f = StreamlyStream . Streamly.mapMaybe f . stream
sScanM step start = StreamlyStream . Streamly.scan (Streamly.Fold.foldlM' step start) . stream
sDrop :: Monad m => Int -> StreamlyStream Streamly.Stream m a -> StreamlyStream Streamly.Stream m a
sDrop n = StreamlyStream . Streamly.drop n . stream
sTake n = StreamlyStream . Streamly.take n . stream
sFolder step start = streamlyFolder step start . stream
sBuildFold = streamlyBuildFold
sBuildFoldM = streamlyBuildFoldM
sMapFoldM = Streamly.Fold.rmapM
sLMapFoldM = Streamly.Fold.lmapM
sFoldMaybe = Streamly.Fold.catMaybes
sFold fld = Streamly.fold fld . stream
sToList = Streamly.toList . stream -- this might be bad (not lazy) compared to streamly
sFromFoldable = StreamlyStream . StreamK.toStream . StreamK.fromFoldable
#else
instance (IsStream t, Monad m) => StreamFunctions (StreamlyStream t) m where
type FoldType (StreamlyStream t) = Streamly.Fold.Fold
sThrowIfEmpty = streamlyThrowIfEmpty . stream
sLength = Streamly.length . Streamly.adapt . stream
sCons a = StreamlyStream . Streamly.cons a . stream
sUncons = streamlyStreamUncons
sHead = Streamly.head . Streamly.adapt . stream
sMap f = StreamlyStream . Streamly.map f . stream
sMapMaybe f = StreamlyStream . Streamly.mapMaybe f . stream
sScanM step start = StreamlyStream . Streamly.scanlM' step start . stream
sDrop n = StreamlyStream . Streamly.drop n . stream
sTake n = StreamlyStream . Streamly.take n . stream
sFolder step start = streamlyFolder step start . stream
sBuildFold = streamlyBuildFold
sBuildFoldM = streamlyBuildFoldM
sMapFoldM = Streamly.Fold.rmapM
sLMapFoldM = Streamly.Fold.lmapM
sFoldMaybe = Streamly.Fold.catMaybes
sFold fld = Streamly.fold fld . Streamly.adapt . stream
sToList = Streamly.toList . Streamly.adapt . stream -- this might be bad (not lazy) compared to streamly
sFromFoldable = StreamlyStream . Streamly.fromFoldable
#endif
{-# INLINEABLE sThrowIfEmpty #-}
{-# INLINEABLE sLength #-}
{-# INLINEABLE sCons #-}
{-# INLINEABLE sUncons #-}
{-# INLINEABLE sHead #-}
{-# INLINEABLE sMap #-}
{-# INLINEABLE sMapMaybe #-}
{-# INLINEABLE sScanM #-}
{-# INLINEABLE sDrop #-}
{-# INLINEABLE sTake #-}
{-# INLINEABLE sFolder #-}
{-# INLINEABLE sBuildFold #-}
{-# INLINEABLE sBuildFoldM #-}
{-# INLINEABLE sMapFoldM #-}
{-# INLINEABLE sLMapFoldM #-}
{-# INLINEABLE sFoldMaybe #-}
{-# INLINEABLE sFold #-}
{-# INLINEABLE sToList #-}
{-# INLINEABLE sFromFoldable #-}
#if MIN_VERSION_streamly(0,9,0)
instance (MonadCatch m, MonadIO m, PrimMonad m, MC.MonadBaseControl IO m) => StreamFunctionsIO (StreamlyStream Streamly.Stream) m where
type IOSafe (StreamlyStream Streamly.Stream) m = m
runSafe = id
sReadTextLines = StreamlyStream . streamlyReadTextLines linesUsingSplitOn
sTokenized sep qm = StreamlyStream . streamlyReadTextLines (tokenized sep qm)
sReadScanMAndFold = streamlyReadScanMAndFold
sWriteTextLines fp = streamlyWriteTextLines fp . stream
#else
instance (IsStream t, Streamly.MonadAsync m, MonadCatch m, PrimMonad m) => StreamFunctionsIO (StreamlyStream t) m where
type IOSafe (StreamlyStream t) m = m
runSafe = id
sReadTextLines = StreamlyStream . streamlyReadTextLines linesUsingSplitOn
sTokenized sep qm = StreamlyStream . streamlyReadTextLines (tokenized sep qm)
sReadScanMAndFold = streamlyReadScanMAndFold
sWriteTextLines fp = streamlyWriteTextLines fp . stream
#endif
{-# INLINEABLE runSafe #-}
{-# INLINEABLE sReadTextLines #-}
{-# INLINEABLE sTokenized #-}
{-# INLINEABLE sReadScanMAndFold #-}
{-# INLINEABLE sWriteTextLines #-}
#if MIN_VERSION_streamly(0,9,0)
streamlyStreamUncons :: Monad m => StreamlyStream Streamly.Stream m a -> m (Maybe (a, StreamlyStream Streamly.Stream m a))
streamlyStreamUncons s = do
unc <- Streamly.uncons (stream s)
case unc of
Nothing -> return Nothing
Just (a, s') -> return $ Just (a, StreamlyStream s')
#else
streamlyStreamUncons :: (IsStream t, Monad m) => StreamlyStream t m a -> m (Maybe (a, StreamlyStream t m a))
streamlyStreamUncons s = do
unc <- Streamly.uncons (Streamly.adapt $ stream s)
case unc of
Nothing -> return Nothing
Just (a, s') -> return $ Just (a, StreamlyStream s')
#endif
{-# INLINABLE streamlyStreamUncons #-}
streamlyBuildFold :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Streamly.Fold.Fold m a b
#if MIN_VERSION_streamly(0,8,0)
streamlyBuildFold step start extract = fmap extract $ Streamly.Fold.foldl' step start
#else
streamlyBuildFold step start extract = Streamly.Fold.mkPure step start extract
#endif
streamlyBuildFoldM :: Monad m => (x -> a -> m x) -> m x -> (x -> m b) -> Streamly.Fold.Fold m a b
#if MIN_VERSION_streamly(0,8,0)
streamlyBuildFoldM step start extract = Streamly.Fold.rmapM extract $ Streamly.Fold.foldlM' step start
#else
streamlyBuildFoldM step start extract = Streamly.Fold.mkFold step start extract
#endif
#if MIN_VERSION_streamly(0,9,0)
streamlyWriteTextLines :: (MonadCatch m, MonadIO m) => FilePath -> Streamly.Stream m Text -> m ()
#else
streamlyWriteTextLines :: (IsStream s, Streamly.MonadAsync m, MonadCatch m) => FilePath -> s m Text -> m ()
#endif
streamlyWriteTextLines fp s = do
#if MIN_VERSION_streamly(0,8,0)
let unfoldMany = Streamly.unfoldMany
#else
let unfoldMany = Streamly.concatUnfold
#endif
Streamly.fold (Streamly.File.write fp)
$ Unicode.encodeUtf8
#if MIN_VERSION_streamly(0,9,0)
$ unfoldMany Streamly.Unfold.fromList
$ fmap T.unpack
#else
$ Streamly.adapt
$ unfoldMany Streamly.Unfold.fromList
$ Streamly.map T.unpack
#endif
$ Streamly.intersperse "\n" s
{-# INLINEABLE streamlyWriteTextLines #-}
-- Use Text to read a line at a time
streamlyUnfoldTextLn :: MonadIO m => Streamly.Unfold.Unfold m IO.Handle Text
streamlyUnfoldTextLn = Streamly.Unfold.unfoldrM f where
getOne :: IO.Handle -> IO (Either IOException Text)
getOne h = try (Text.hGetLine h)
f h = do
tE <- liftIO $ getOne h
case tE of
Left _ -> return Nothing
Right t -> return $ Just (t, h)
{-# INLINEABLE streamlyUnfoldTextLn #-}
#if MIN_VERSION_streamly(0,9,0)
streamlyReadTextLines :: (MonadCatch m, MonadIO m)
=> (IO.Handle -> Streamly.Stream m a) -> FilePath -> Streamly.Stream m a
streamlyReadTextLines f fp = Streamly.bracketIO (liftIO $ IO.openFile fp IO.ReadMode) (liftIO . IO.hClose) f
#else
streamlyReadTextLines :: (Streamly.IsStream t, Streamly.MonadAsync m, MonadCatch m)
=> (IO.Handle -> t m a) -> FilePath -> t m a
streamlyReadTextLines f fp = Streamly.bracket (liftIO $ IO.openFile fp IO.ReadMode) (liftIO . IO.hClose) f
#endif
{-# INLINEABLE streamlyReadTextLines #-}
withFileLifted :: MC.MonadBaseControl IO m => FilePath -> IOMode -> (Handle -> m a) -> m a
withFileLifted file mode action = MC.liftBaseWith (\runInBase -> withFile file mode (runInBase . action)) >>= MC.restoreM
{-# INLINEABLE withFileLifted #-}
#if MIN_VERSION_streamly(0,9,0)
streamlyReadScanMAndFold :: (MC.MonadBaseControl IO m, MonadIO m) => FilePath -> (x -> Text -> m x) -> m x -> Streamly.Fold.Fold m x b -> m b
streamlyReadScanMAndFold fp scanStep scanStart fld = withFileLifted fp IO.ReadMode
$ Streamly.fold fld . Streamly.scan (Streamly.Fold.foldlM' scanStep scanStart) . Streamly.unfold streamlyUnfoldTextLn
#else
streamlyReadScanMAndFold :: Streamly.MonadAsync m => FilePath -> (x -> Text -> m x) -> m x -> Streamly.Fold.Fold m x b -> m b
streamlyReadScanMAndFold fp scanStep scanStart fld = withFileLifted fp IO.ReadMode
$ StreamD.fold fld . StreamD.scanlM' scanStep scanStart . StreamD.unfold streamlyUnfoldTextLn
#endif
{-# INLINEABLE streamlyReadScanMAndFold #-}
#if MIN_VERSION_streamly(0,9,0)
streamlyThrowIfEmpty :: (MonadThrow m) => Streamly.Stream m a -> m ()
streamlyThrowIfEmpty s = Streamly.fold Streamly.Fold.null s >>= flip when (throwM EmptyStreamException)
#else
streamlyThrowIfEmpty :: (IsStream t, MonadThrow m) => t m a -> m ()
streamlyThrowIfEmpty s = Streamly.null (Streamly.adapt s) >>= flip when (throwM EmptyStreamException)
#endif
{-# INLINEABLE streamlyThrowIfEmpty #-}
#if MIN_VERSION_streamly(0,9,0)
streamlyFolder :: Monad m => (x -> a -> x) -> x -> Streamly.Stream m a -> m x
streamlyFolder step start = Streamly.fold (streamlyBuildFold step start id)
#else
streamlyFolder :: (IsStream t, Monad m) => (x -> a -> x) -> x -> t m a -> m x
streamlyFolder step start = Streamly.fold (streamlyBuildFold step start id) . Streamly.adapt
#endif
{-# INLINABLE streamlyFolder #-}
#if MIN_VERSION_streamly(0,9,0)
linesUsingSplitOn :: MonadIO m => IO.Handle -> Streamly.Stream m Text
linesUsingSplitOn h = Streamly.unfold Streamly.Handle.chunkReader h
& Array.Stream.splitOnSuffix _lf
& fmap (Text.decodeUtf8 . Streamly.BS.fromArray)
#else
linesUsingSplitOn :: (IsStream t, MonadIO m) => IO.Handle -> t m Text
linesUsingSplitOn h = Streamly.unfold Streamly.Handle.readChunks h
& Array.Stream.splitOnSuffix _lf
& Streamly.map (Text.decodeUtf8 . Streamly.BS.fromArray)
#endif
{-# INLINEABLE linesUsingSplitOn #-}
#if MIN_VERSION_streamly(0,9,0)
tokenized :: MonadIO m => Common.Separator -> Common.QuotingMode -> IO.Handle -> Streamly.Stream m [Text]
tokenized sep qm h = Streamly.unfold Streamly.Handle.chunkReader h
& Array.Stream.splitOnSuffix _lf
& fmap (Common.tokenizeRow sep qm . Text.decodeUtf8 . Streamly.BS.fromArray)
#else
tokenized :: (IsStream t, MonadIO m) => Common.Separator -> Common.QuotingMode -> IO.Handle -> t m [Text]
tokenized sep qm h = Streamly.unfold Streamly.Handle.readChunks h
& Array.Stream.splitOnSuffix _lf
& Streamly.map (Common.tokenizeRow sep qm . Text.decodeUtf8 . Streamly.BS.fromArray)
#endif
{-# INLINEABLE tokenized #-}
{-
tokenized2 :: (IsStream t, Streamly.MonadAsync m) => Common.Separator -> Common.QuotingMode -> IO.Handle -> t m [Text]
tokenized2 sep qm h = Streamly.unfold Streamly.Handle.readChunks h
& Array.Stream.splitOnSuffix _lf
& wordArraysToTextLists sep qm
{-# INLINE tokenized2 #-}
wordArraysToTextLists :: (IsStream t, Streamly.MonadAsync m) => Common.Separator -> Common.QuotingMode -> t m (Array.Array Word8) -> t m [Text]
wordArraysToTextLists sep qm = case sep of
Common.TextSeparator _ -> Streamly.map (Common.tokenizeRow sep qm . Text.decodeUtf8 . Streamly.BS.fromArray)
Common.CharSeparator c -> Streamly.mapM (fmap (Common.handleQuoting sep qm) . processArray2 c)
{-# INLINE wordArraysToTextLists #-}
wordArraysToTextListsRaw :: (IsStream t, Streamly.MonadAsync m) => Common.Separator -> t m (Array.Array Word8) -> t m [Text]
wordArraysToTextListsRaw sep = case sep of
Common.TextSeparator _ -> Streamly.map (Common.splitRow sep . Text.decodeUtf8 . Streamly.BS.fromArray)
Common.CharSeparator c -> Streamly.mapM (processArray2 c)
{-# INLINE wordArraysToTextListsRaw #-}
tokenizedRaw :: (IsStream t, MonadIO m) => Common.Separator -> IO.Handle -> t m [Text]
tokenizedRaw sep h = Streamly.unfold Streamly.Handle.readChunks h
& Array.Stream.splitOnSuffix _lf
& Streamly.map (Common.splitRow sep . Text.decodeUtf8 . Streamly.BS.fromArray)
{-# INLINE tokenizedRaw #-}
tokenizedRaw3 :: forall t m.(IsStream t, Streamly.MonadAsync m) => Common.Separator -> IO.Handle -> t m [Text]
tokenizedRaw3 sep h = Streamly.unfold Streamly.Handle.readChunks h
& Array.Stream.splitOnSuffix _lf
& wordArraysToTextListsRaw sep
{-# INLINE tokenizedRaw3 #-}
{-# INLINE processArray2 #-}
processArray2 :: MonadIO m => Char -> Array.Array Word8 -> m [Text]
processArray2 c arr =
let c2w = fromIntegral . ord
toText arr = Text.decodeUtf8 $ Streamly.BS.fromArray arr
in Streamly.toList $ Streamly.map toText $ Array.Stream.splitOn (c2w c) $ Streamly.fromPure arr
tokenizedRaw2 :: forall t m.(IsStream t, Streamly.MonadAsync m) => Common.Separator -> IO.Handle -> t m [Text]
tokenizedRaw2 sep h = Streamly.unfold Streamly.Handle.readChunks h & processArrayStream sep
{-# INLINE tokenizedRaw2 #-}
{-# INLINE toTextFld #-}
toTextFld :: MonadIO m => Streamly.Fold.Fold m Word8 Text
toTextFld = fmap (Text.decodeUtf8With Text.lenientDecode) Streamly.BS.write
{-# INLINE lineFold #-}
lineFold :: MonadIO m => Char -> Streamly.Fold.Fold m Word8 [Text]
lineFold c =
let c2w = fromIntegral . ord
split = Streamly.Fold.takeEndBy (== c2w c) toTextFld
in Streamly.Fold.many split Streamly.Fold.toList
{-# INLINE processArray #-}
processArray :: MonadIO m => Char -> Array.Array Word8 -> m [Text]
processArray c arr = Streamly.unfold Array.read arr
& Streamly.fold (lineFold c)
{-# INLINE processArrayBaseLine #-}
processArrayBaseLine :: Char -> Array.Array Word8 -> [Text]
processArrayBaseLine c arr = Common.splitRow (Common.CharSeparator c) $ Text.decodeUtf8 $ Streamly.BS.fromArray arr
{-# INLINE processArrayBaseLine2 #-}
processArrayBaseLine2 :: MonadIO m => Char -> Array.Array Word8 -> m [Text]
processArrayBaseLine2 c arr = Common.splitRow (Common.CharSeparator c) <$> Array.fold toTextFld arr
{-# INLINE processArrayStream #-}
processArrayStream :: (Streamly.MonadAsync m, IsStream t) => Common.Separator -> t m (Array.Array Word8) -> t m [Text]
processArrayStream sep arrS =
let arrayToText = case sep of
Common.TextSeparator _ -> Streamly.map (Common.splitRow sep . Text.decodeUtf8 . Streamly.BS.fromArray)
Common.CharSeparator c -> Streamly.mapM (processArray2 c)
in arrayToText $ Array.Stream.splitOnSuffix _lf arrS
-}
{-
tokenizedLines :: (IsStream t, MonadIO m) => Word8 -> IO.Handle -> t m Text
tokenizedLines s h = Streamly.unfold Streamly.Handle.readChunks h
& Streamly.Array.splitOnSuffix _lf
& Streamly.filter (not . F.null)
& Streamly.map (Text.decodeUtf8 . Streamly.BS.fromArray . S)
{-# INLINE tokenizedLines #-}
-}
{-
streamlyReadTextLines' :: (Streamly.IsStream t, Streamly.MonadAsync m, MonadCatch m) => FilePath -> t m Text
streamlyReadTextLines' = word8ToTextLines2 . streamWord8
{-# INLINE streamlyReadTextLines' #-}
streamWord8 :: (Streamly.IsStream t, Streamly.MonadAsync m, MonadCatch m) => FilePath -> t m Word8
streamWord8 = Streamly.File.toBytes
{-# INLINE streamWord8 #-}
word8ToTextLines2 :: (IsStream t, MonadIO m) => t m Word8 -> t m T.Text
word8ToTextLines2 = Streamly.map (T.pack . Streamly.Array.toList)
. Streamly.Unicode.Array.lines
. Streamly.Unicode.decodeUtf8
{-# INLINE word8ToTextLines2 #-}
-- | Convert a stream of Word8 to lines of `Text` by decoding as UTF8 and splitting on "\n"
word8ToTextLines :: (IsStream t, MonadIO m) => t m Word8 -> t m T.Text
word8ToTextLines = Streamly.splitOnSuffix(=='\n') (toText <$> Streamly.Fold.toList)
. Streamly.Unicode.decodeUtf8
{-# INLINE word8ToTextLines #-}
-}
{-
-- use streamly to read Word8 and then parse to lines
textLinesFromHandle :: (MonadThrow m, IsStream t) => MonadIO m => IO.Handle -> t m Text
textLinesFromHandle = Reduce.parseManyD newlineParserD . Streamly.unfold Streamly.Handle.read
{-# INLINE textLinesFromHandle #-}
foldWord8ToText :: Monad m => Streamly.Fold.Fold m Word8 Text
foldWord8ToText = fmap (T.pack . fmap w2c) $ Streamly.Fold.toList
{-# INLINE foldWord8ToText #-}
foldWord8ToText2 :: Monad m => Streamly.Fold.Fold m Word8 Text
foldWord8ToText2 = fmap TB.run $ Streamly.Fold.foldl' (\b w -> b <> TB.char (w2c w)) mempty
{-# INLINE foldWord8ToText2 #-}
newlineParserD :: (MonadIO m, MonadThrow m) => ParserD.Parser m Word8 Text
newlineParserD = ParserD.takeWhile (/= _lf) foldWord8ToText2 <* next
{-# INLINE newlineParserD #-}
data PState = PState !FArray.Array Word8 [Text]
arrayWordStreamToTextStream :: t m (FArray.Array Word8) -> t m Text
arrayWordStreamToTextStream = Reduce.foldIterateM g initial where
g :: PState -> m (Streamly.Fold (FArray.Array Word8) PState)
g (PState remainder lines) = Streamly.Fold.runStep fld remainder where
fld :: Streamly.Fold (FArray.Array Word8) PState = Streamly.Fold.foldlM' step p0 where
step :: PState -> FArray.Array Word8 -> m PState
step (PState remainder lines) cur = do
newChunk <- FArray.spliceTwo remainder cur
(newRemainder, newLines) <- breakAll newChunk
return $ PState newRemainder newLines
p0 = PState mempty []
initial :: PState
initial = PState mempty []
breakAll :: FArray.Array Word8 -> m (FArray.Array Word8, [FArray.Array Word8])
breakAll a = go (a, []) where
go a l = do
ma <- FArray.breakOn _lf a
case ma of
(prefix, Just suffix) -> go (prefix, suffix : l)
(prefix, Nothing) -> return (prefix, l)
{-# INLINE breakAllOn #-}
next :: Monad m => ParserD.Parser m a (Maybe a)
next = ParserD.Parser step initial extract
where
initial = pure $ ParserD.IPartial ()
step _ a = pure $ ParserD.Done 0 (Just a)
extract _ = pure Nothing
{-# INLINE next #-}
-}
{-
lines :: BL.ByteString -> DL.DList (BL.ByteString)
lines = DL.unfoldr inner
where
{-# INLINE inner #-}
inner input'
| BL.null input' = Nothing
| otherwise =
case BL.elemIndex _lf input' of
Nothing -> Just (input', BL.empty)
Just i ->
let (prefix, suffix) = BL.splitAt i input'
in Just (prefix, BL.drop 1 suffix)
{-# INLINE lines #-}
unfoldViaLBS' :: Applicative m => Word8 -> Streamly.Unfold.Unfold m BL.ByteString BL.ByteString
unfoldViaLBS' w = Streamly.Unfold.unfoldr inner
where
{-# INLINE inner #-}
inner input'
| BL.null input' = Nothing
| otherwise =
case BL.elemIndex w input' of
Nothing -> Just (input', BL.empty)
Just i ->
let (prefix, suffix) = BL.splitAt i input'
in Just (prefix, BL.drop 1 suffix)
{-# INLINE unfoldViaLBS' #-}
unfoldViaSBS' :: Applicative m => Word8 -> Streamly.Unfold.Unfold m BS.ByteString BS.ByteString
unfoldViaSBS' w = Streamly.Unfold.unfoldr inner
where
{-# INLINE inner #-}
inner input'
| BS.null input' = Nothing
| otherwise =
case BS.elemIndex w input' of
Nothing -> Just (input', BS.empty)
Just i ->
let (prefix, suffix) = BS.splitAt i input'
in Just (prefix, BS.drop 1 suffix)
{-# INLINE unfoldViaSBS' #-}
unfoldViaLBS :: MonadIO m => Word8 -> Streamly.Unfold.Unfold m IO.Handle Text
unfoldViaLBS w = fmap (Text.decodeUtf8 . BL.toStrict) $ Streamly.Unfold.lmapM (liftIO . BL.hGetContents) (unfoldViaLBS' w)
{-# INLINE unfoldViaLBS #-}
readTextLinesRaw :: (IsStream t, MonadIO m) => IO.Handle -> t m Text
readTextLinesRaw = Streamly.foldMany lineFold . Streamly.unfoldMany read' . fileStream where
fileStream = Streamly.unfold Streamly.Handle.readChunks
{-# INLINE readTextLinesRaw #-}
read' :: MonadIO m => Streamly.Unfold.Unfold m (F.Array Word8) Word8
read' = Streamly.Unfold.lmap F.unsafeThaw FM.read
{-# INLINE [0] read' #-}
lineFold :: Applicative m => Streamly.Fold.Fold m Word8 Text
lineFold = Streamly.Fold.Fold step initial extract
where
dlToText = T.pack . fmap w2c . DL.toList
initial = pure $ Streamly.Fold.Partial DL.empty
step !s !a
| a == _lf = pure $ Streamly.Fold.Done $ dlToText s
| otherwise = pure $ Streamly.Fold.Partial (DL.snoc s a)
extract !s = pure $ dlToText s
{-# INLINE [2] lineFold #-}
-}