@@ -126,6 +126,7 @@ module Streamly.Internal.Data.Stream.StreamD
126126 -- ** Specialized Folds
127127 , tap
128128 , tapAsync
129+ , tapRate
129130 , drain
130131 , null
131132 , head
@@ -300,8 +301,9 @@ module Streamly.Internal.Data.Stream.StreamD
300301 )
301302where
302303
303−import Control.Concurrent (myThreadId, takeMVar)
304−import Control.Exception (Exception, SomeException, fromException)
304+import Control.Concurrent (killThread, myThreadId, takeMVar, threadDelay)
305+import Control.Exception
306+ (Exception, SomeException, AsyncException, fromException)
305307import Control.Monad (void, when)
306308import Control.Monad.Catch (MonadCatch, throwM)
307309import Control.Monad.IO.Class (MonadIO(..))
@@ -310,7 +312,7 @@ import Control.Monad.State.Strict (StateT)
310312import Control.Monad.Trans (MonadTrans(lift))
311313import Data.Bits (shiftR, shiftL, (.|.), (.&.))
312314import Data.Functor.Identity (Identity(..))
313−import Data.IORef (newIORef, readIORef, mkWeakIORef, writeIORef)
315+import Data.IORef (newIORef, readIORef, mkWeakIORef, writeIORef, modifyIORef')
314316import Data.Maybe (fromJust, isJust, isNothing)
315317import Data.Word (Word32)
316318import Foreign.Ptr (Ptr)
@@ -3218,6 +3220,51 @@ tap (Fold fstep initial extract) (Stream step state) = Stream step' Nothing
32183220 void $ extract acc
32193221 return $ Stop
32203222
3223+{-# INLINE_NORMAL tapRate #-}
3224+tapRate ::
3225+ (MonadAsync m, MonadCatch m)
3226+ => Double
3227+ -> (Int -> m b)
3228+ -> Stream m a
3229+ -> Stream m a
3230+tapRate samplingRate action (Stream step state) = Stream step' Nothing
3231+ where
3232+ {-# NOINLINE loop #-}
3233+ loop countRef prev = do
3234+ i <-
3235+ MC.catch
3236+ (do liftIO $ threadDelay (round $ samplingRate * 1000000)
3237+ i <- liftIO $ readIORef countRef
3238+ let !diff = i - prev
3239+ void $ action diff
3240+ return i)
3241+ (\(e :: AsyncException) -> do
3242+ i <- liftIO $ readIORef countRef
3243+ let !diff = i - prev
3244+ void $ action diff
3245+ throwM (MC.toException e))
3246+ loop countRef i
3247+
3248+ {-# INLINE_LATE step' #-}
3249+ step' _ Nothing = do
3250+ countRef <- liftIO $ newIORef 0
3251+ tid <- fork $ loop countRef 0
3252+ ref <- liftIO $ newIORef ()
3253+ _ <- liftIO $ mkWeakIORef ref (killThread tid)
3254+ return $ Skip (Just (countRef, tid, state, ref))
3255+
3256+ step' gst (Just (countRef, tid, st, ref)) = do
3257+ r <- step gst st
3258+ case r of
3259+ Yield x s -> do
3260+ liftIO $ modifyIORef' countRef (+ 1)
3261+ return $ Yield x (Just (countRef, tid, s, ref))
3262+ Skip s -> return $ Skip (Just (countRef, tid, s, ref))
3263+ Stop -> do
3264+ liftIO $ killThread tid
3265+ return Stop
3266+
3267+
32213268-------------------------------------------------------------------------------
32223269-- Filtering
32233270-------------------------------------------------------------------------------