@@ -125,6 +125,7 @@ module Streamly.Internal.Data.Stream.StreamD
126 -- ** Specialized Folds
126 -- ** Specialized Folds
@@ -299,6 +300,7 @@ module Streamly.Internal.Data.Stream.StreamD
303+import Control.Concurrent (myThreadId, takeMVar)
302import Control.Exception (Exception, SomeException, fromException)
304import Control.Exception (Exception, SomeException, fromException)
303import Control.Monad (void, when)
305import Control.Monad (void, when)
304import Control.Monad.Catch (MonadCatch, throwM)
306import Control.Monad.Catch (MonadCatch, throwM)
@@ -336,6 +338,7 @@ import Streamly.Internal.Data.Unfold.Types (Unfold(..))
337import Streamly.Internal.Data.Stream.StreamD.Type
339import Streamly.Internal.Data.Stream.StreamD.Type
338import Streamly.Internal.Data.SVar
340import Streamly.Internal.Data.SVar
341+import Streamly.Internal.Data.Stream.SVar (fromConsumer, pushToFold)
340import qualified Streamly.Internal.Data.Pipe.Types as Pipe
343import qualified Streamly.Internal.Data.Pipe.Types as Pipe
341import qualified Streamly.Internal.Memory.Array.Types as A
344import qualified Streamly.Internal.Memory.Array.Types as A
@@ -732,6 +735,44 @@ fromSVar svar = Stream step FromSVarInit
732 liftIO $ printSVar sv "SVar Done"
735 liftIO $ printSVar sv "SVar Done"
733 return Stop
736 return Stop
738+-------------------------------------------------------------------------------
739+-- Process events received by a fold consumer from a stream producer
740+-------------------------------------------------------------------------------
742+{-# INLINE_NORMAL fromProducer #-}
743+fromProducer :: (MonadAsync m) => SVar t m a -> Stream m a
744+fromProducer svar = Stream step (FromSVarRead svar)
747+ {-# INLINE_LATE step #-}
748+ step _ (FromSVarRead sv) = do
749+ list <- readOutputQ sv
750+ -- Reversing the output is important to guarantee that we process the
751+ -- outputs in the same order as they were generated by the constituent
753+ return $ Skip $ FromSVarLoop sv (Prelude.reverse list)
755+ step _ (FromSVarLoop sv []) = return $ Skip $ FromSVarRead sv
756+ step _ (FromSVarLoop sv (ev : es)) = do
758+ ChildYield a -> return $ Yield a (FromSVarLoop sv es)
759+ ChildStop tid e -> do
760+ accountThread sv tid
763+ sendStopToProducer sv
764+ return $ Skip (FromSVarDone sv)
765+ Just _ -> error "Bug: fromProducer: received exception"
767+ step _ (FromSVarDone sv) = do
768+ when (svarInspectMode sv) $ do
769+ t <- liftIO $ getTime Monotonic
770+ liftIO $ writeIORef (svarStopTime (svarStats sv)) (Just t)
771+ liftIO $ printSVar sv "SVar Done"
774+ step _ FromSVarInit = undefined
735-------------------------------------------------------------------------------
776-------------------------------------------------------------------------------
736-- Hoisting the inner monad
777-- Hoisting the inner monad
737-------------------------------------------------------------------------------
778-------------------------------------------------------------------------------
@@ -3732,3 +3773,74 @@ foldParallel f m = do
3732 sv <- newParallelVar StopNone defState
3773 sv <- newParallelVar StopNone defState
3733 toSVarParallel defState sv (toStreamD m)
3774 toSVarParallel defState sv (toStreamD m)
3734 f $ fromStreamD $ fromSVar sv
3775 f $ fromStreamD $ fromSVar sv
3777+-------------------------------------------------------------------------------
3779+-------------------------------------------------------------------------------
3781+-- | Create an SVar with a fold consumer that will fold any elements sent to it
3782+-- using the supplied fold function.
3783+{-# INLINE newFoldSVar #-}
3784+newFoldSVar :: MonadAsync m => State t m a -> Fold m a b -> m (SVar t m a)
3785+newFoldSVar stt f = do
3786+ -- Buffer size for the SVar is derived from the current state
3787+ sv <- newParallelVar StopAny (adaptState stt)
3788+ -- Add the producer thread-id to the SVar.
3789+ liftIO myThreadId >>= modifyThread sv
3790+ void $ doFork (work sv) (svarMrun sv) (handleFoldException sv)
3795+ {-# NOINLINE work #-}
3796+ work sv = void $ runFold f $ fromProducer sv
3798+data TapState sv st = TapInit | Tapping sv st | TapDone st
3800+{-# INLINE_NORMAL tapAsync #-}
3801+tapAsync :: MonadAsync m => Fold m a b -> Stream m a -> Stream m a
3802+tapAsync f (Stream step1 state1) = Stream step TapInit
3806+ -- In general, a Stop event would come equipped with the result
3807+ -- of the fold. It is not used here but it would be useful in
3808+ -- applicative and distribute.
3809+ done <- fromConsumer svr
3810+ when (not done) $ do
3811+ liftIO $ withDiagMVar svr "teeToSVar: waiting to drain"
3812+ $ takeMVar (outputDoorBellFromConsumer svr)
3816+ liftIO $ sendStop svr Nothing
3817+ -- drain/wait until a stop event arrives from the fold.
3820+ {-# INLINE_LATE step #-}
3821+ step gst TapInit = do
3822+ sv <- newFoldSVar gst f
3823+ return $ Skip (Tapping sv state1)
3825+ step gst (Tapping sv st) = do
3829+ done <- pushToFold sv a
3832+ -- XXX we do not need to wait synchronously here
3834+ return $ Yield a (TapDone s)
3835+ else return $ Yield a (Tapping sv s)
3836+ Skip s -> return $ Skip (Tapping sv s)
3841+ step gst (TapDone st) = do
3844+ Yield a s -> Yield a (TapDone s)
3845+ Skip s -> Skip (TapDone s)