@@ -20,6 +20,7 @@ module Streamly.Internal.Data.Stream.StreamD.Exception
@@ -29,11 +30,13 @@ import Control.Exception (Exception, SomeException, mask_)
29import Control.Monad.Catch (MonadCatch)
30import Control.Monad.Catch (MonadCatch)
30import Control.Monad.IO.Class (MonadIO(..))
31import Control.Monad.IO.Class (MonadIO(..))
31import Control.Monad.Trans.Control (MonadBaseControl, liftBaseOp_)
32import Control.Monad.Trans.Control (MonadBaseControl, liftBaseOp_)
33+import Data.Map.Strict (Map)
32import GHC.Exts (inline)
34import GHC.Exts (inline)
33import Streamly.Internal.Data.IOFinalizer
35import Streamly.Internal.Data.IOFinalizer
34 (newIOFinalizer, runIOFinalizer, clearingIOFinalizer)
36 (newIOFinalizer, runIOFinalizer, clearingIOFinalizer)
36import qualified Control.Monad.Catch as MC
38import qualified Control.Monad.Catch as MC
39+import qualified Data.Map.Strict as Map
38import Streamly.Internal.Data.Stream.StreamD.Type
41import Streamly.Internal.Data.Stream.StreamD.Type
39import Streamly.Internal.Data.SVar
42import Streamly.Internal.Data.SVar
@@ -357,3 +360,55 @@ _handle f (Stream step state) = Stream step' (Left state)
357 Yield x s -> return $ Yield x (Right (Stream step1 s))
360 Yield x s -> return $ Yield x (Right (Stream step1 s))
358 Skip s -> return $ Skip (Right (Stream step1 s))
361 Skip s -> return $ Skip (Right (Stream step1 s))
359 Stop -> return Stop
362 Stop -> return Stop
364+data RetryState emap s1 s2
365+ = RetryWithMap emap s1
368+-- | See 'Streamly.Internal.Data.Stream.IsStream.retry'
370+{-# INLINE_NORMAL retry #-}
372+ :: forall e m a. (Exception e, Ord e, MonadCatch m)
374+ -- ^ map from exception to retry count
375+ -> (e -> Stream m a)
376+ -- ^ default handler for those exceptions that are not in the map
379+retry emap0 defaultHandler (Stream step0 state0) = Stream step state
383+ state = RetryWithMap emap0 state0
385+ {-# INLINE_LATE step #-}
386+ step gst (RetryWithMap emap st) = do
387+ eres <- MC.try $ step0 gst st
389+ Left e -> handler e emap st
393+ Yield x st1 -> Yield x $ RetryWithMap emap st1
394+ Skip st1 -> Skip $ RetryWithMap emap st1
396+ step gst (RetryDefault (UnStream step1 state1)) = do
397+ res <- step1 gst state1
400+ Yield x st1 -> Yield x $ RetryDefault (Stream step1 st1)
401+ Skip st1 -> Skip $ RetryDefault (Stream step1 st1)
404+ {-# INLINE handler #-}
408+ $ case Map.lookup e emap of
411+ let emap1 = Map.insert e (i - 1) emap
412+ in RetryWithMap emap1 st
413+ | otherwise -> RetryDefault $ defaultHandler e
414+ Nothing -> RetryDefault $ defaultHandler e