-- | Splitting functions for @ByteString m r@ into @Stream (ByteString m) m r@.
--
-- TODO These functions need quickcheck tests.

module Data.ByteString.Streaming.Split where

import Data.ByteString.Streaming.Char8 as S8
import Data.ByteString.Streaming.Internal as SI
import Streaming.Internal (Stream(..))



-- | Split a @ByteString m r@ after every @k@ characters.
--
-- Streams in constant memory.
--
-- BUG: Once the stream is exhausted, it will still call @splitAt@, forever
-- creating empty @ByteString@s.

splitsByteStringAt  Monad m  Int  ByteString m r  Stream (ByteString m) m r
splitsByteStringAt :: Int -> ByteString m r -> Stream (ByteString m) m r
splitsByteStringAt !Int
k = ByteString m r -> Stream (ByteString m) m r
loop where
  loop :: ByteString m r -> Stream (ByteString m) m r
loop (Empty r
r) = r -> Stream (ByteString m) m r
forall (m :: * -> *) a. Monad m => a -> m a
return r
r
  loop ByteString m r
p = ByteStream m (Stream (ByteString m) m r)
-> Stream (ByteString m) m r
forall (f :: * -> *) (m :: * -> *) r.
f (Stream f m r) -> Stream f m r
Step (ByteStream m (Stream (ByteString m) m r)
 -> Stream (ByteString m) m r)
-> ByteStream m (Stream (ByteString m) m r)
-> Stream (ByteString m) m r
forall a b. (a -> b) -> a -> b
$ (ByteString m r -> Stream (ByteString m) m r)
-> ByteStream m (ByteString m r)
-> ByteStream m (Stream (ByteString m) m r)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString m r -> Stream (ByteString m) m r
loop (ByteStream m (ByteString m r)
 -> ByteStream m (Stream (ByteString m) m r))
-> ByteStream m (ByteString m r)
-> ByteStream m (Stream (ByteString m) m r)
forall a b. (a -> b) -> a -> b
$ Int64 -> ByteString m r -> ByteStream m (ByteString m r)
forall (m :: * -> *) r.
Monad m =>
Int64 -> ByteStream m r -> ByteStream m (ByteStream m r)
S8.splitAt (Int -> Int64
forall a b. (Integral a, Num b) => a -> b
fromIntegral Int
k) ByteString m r
p
{- -- this version would consume all memory
  loop p = SI.Effect $ do
    e ← nextChunk p
    return $ case e of
      Left r → SI.Return r
      Right (a,p') → SI.Step (fmap loop (S8.splitAt (fromIntegral k) (chunk a >> p')))
      -}
{-# Inlinable splitsByteStringAt #-}



-- | For lists, this would be @sbs (f :: [a] -> ([a],[a])) -> [a] -> [[a]]@.
-- Takes a function that splits the bytestring into two elements repeatedly,
-- where the first is followed by the repeated application of the function.
--
-- cf. <http://hackage.haskell.org/package/streaming-utils-0.1.4.7/docs/src/Streaming-Pipes.html#chunksOf>
--
-- TODO these functions should go into a helper library

separatesByteString
   Monad m
   (ByteString m r  ByteString m (ByteString m r))
   ByteString m r
   Stream (ByteString m) m r
separatesByteString :: (ByteString m r -> ByteString m (ByteString m r))
-> ByteString m r -> Stream (ByteString m) m r
separatesByteString ByteString m r -> ByteString m (ByteString m r)
f = ByteString m r -> Stream (ByteString m) m r
loop where
  loop :: ByteString m r -> Stream (ByteString m) m r
loop (Empty r
r) = r -> Stream (ByteString m) m r
forall (m :: * -> *) a. Monad m => a -> m a
return r
r
  loop ByteString m r
p = ByteStream m (Stream (ByteString m) m r)
-> Stream (ByteString m) m r
forall (f :: * -> *) (m :: * -> *) r.
f (Stream f m r) -> Stream f m r
Step (ByteStream m (Stream (ByteString m) m r)
 -> Stream (ByteString m) m r)
-> ByteStream m (Stream (ByteString m) m r)
-> Stream (ByteString m) m r
forall a b. (a -> b) -> a -> b
$ (ByteString m r -> Stream (ByteString m) m r)
-> ByteString m (ByteString m r)
-> ByteStream m (Stream (ByteString m) m r)
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap ByteString m r -> Stream (ByteString m) m r
loop (ByteString m (ByteString m r)
 -> ByteStream m (Stream (ByteString m) m r))
-> ByteString m (ByteString m r)
-> ByteStream m (Stream (ByteString m) m r)
forall a b. (a -> b) -> a -> b
$ ByteString m r -> ByteString m (ByteString m r)
f ByteString m r
p
{-
  loop p = SI.Effect $ do
    e ← nextChunk p
    return $ case e of
      Left r → SI.Return r
      Right (a,p') → SI.Step (fmap loop (f (chunk a >> p')))
-}
{-# Inlinable separatesByteString #-}