on master help sign in
Add bracket' combinator
1e00573Harendra Kumar
src/Streamly/Internal/Data/Stream/IsStream/Exception.hs+19−2
@@ -13,6 +13,7 @@ module Streamly.Internal.Data.Stream.IsStream.Exception
13 , after
13 , after
14 , bracket_
14 , bracket_
15 , bracket
15 , bracket
16+ , bracket'
16 , onException
17 , onException
17 , finally_
18 , finally_
18 , finally
19 , finally
@@ -166,8 +167,24 @@ bracket_ bef aft bet = D.fromStreamD $
166{-# INLINE bracket #-}
167{-# INLINE bracket #-}
167bracket :: (IsStream t, MonadAsync m, MonadCatch m)
168bracket :: (IsStream t, MonadAsync m, MonadCatch m)
168 => m b -> (b -> m c) -> (b -> t m a) -> t m a
169 => m b -> (b -> m c) -> (b -> t m a) -> t m a
170+bracket bef aft = bracket' bef aft aft aft
171+
172+-- For a use case of this see the "streamly-process" package. It needs to kill
173+-- the process in case of exception or garbage collection, but waits for the
174+-- process to terminate in normal cases.
175+--
176+-- | Like 'bracket' but can use separate cleanup actions depending on the mode
177+-- of termination. @bracket' before onStop onGC onException action@ runs
178+-- @action@ using the result of @before@. If the stream stops, @onStop@ action
179+-- is executed, if the stream is abandoned @onGC@ is executed, if the stream
180+-- encounters an exception @onException@ is executed.
181+--
182+-- /Pre-release/
183+{-# INLINE bracket' #-}
184+bracket' :: (IsStream t, MonadAsync m, MonadCatch m)
185+ => m b -> (b -> m c) -> (b -> m d) -> (b -> m e) -> (b -> t m a) -> t m a
169−bracket bef aft bet = D.fromStreamD $
186+bracket' bef aft gc exc bet = D.fromStreamD $
170− D.bracket bef aft (toStreamD . bet)
187+ D.bracket' bef aft exc gc (toStreamD . bet)
171
188
172-- | Like 'handle' but the exception handler is also provided with the stream
189-- | Like 'handle' but the exception handler is also provided with the stream
173-- that generated the exception as input. The exception handler can thus
190-- that generated the exception as input. The exception handler can thus
src/Streamly/Internal/Data/Stream/StreamD/Exception.hs+26−18
@@ -14,7 +14,7 @@ module Streamly.Internal.Data.Stream.StreamD.Exception
14 , after_
14 , after_
15 , after
15 , after
16 , bracket_
16 , bracket_
17− , bracket
17+ , bracket'
18 , onException
18 , onException
19 , finally_
19 , finally_
20 , finally
20 , finally
@@ -101,7 +101,9 @@ data GbracketIOState s1 s2 v wref
101-- output @c@ as input to @c -> Stream m b@ to generate an output stream. When
101-- output @c@ as input to @c -> Stream m b@ to generate an output stream. When
102-- generating the stream use the supplied @try@ operation @forall s. m s -> m
102-- generating the stream use the supplied @try@ operation @forall s. m s -> m
103-- (Either e s)@ to catch synchronous exceptions. If an exception occurs run
103-- (Either e s)@ to catch synchronous exceptions. If an exception occurs run
104−-- the exception handler @c -> e -> Stream m b -> m (Stream m b)@.
104+-- the exception handler @c -> e -> Stream m b -> m (Stream m b)@. Note that
105+-- 'gbracket' does not rethrow the exception, it has to be done by the
106+-- exception handler if desired.
105--
107--
106-- The cleanup action @c -> m d@, runs whenever the stream ends normally, due
108-- The cleanup action @c -> m d@, runs whenever the stream ends normally, due
107-- to a sync or async exception or if it gets garbage collected after a partial
109-- to a sync or async exception or if it gets garbage collected after a partial
@@ -115,13 +117,14 @@ data GbracketIOState s1 s2 v wref
115{-# INLINE_NORMAL gbracket #-}
117{-# INLINE_NORMAL gbracket #-}
116gbracket
118gbracket
117 :: (MonadIO m, MonadBaseControl IO m)
119 :: (MonadIO m, MonadBaseControl IO m)
118− => m c -- ^ before
120+ => m c -- ^ before
119− -> (forall s. m s -> m (Either e s)) -- ^ try (exception handling)
121+ -> (forall s. m s -> m (Either e s)) -- ^ try (exception handling)
122+ -> (c -> m d1) -- ^ on normal stop
120− -> (c -> m d) -- ^ after, on normal stop or GC
123+ -> (c -> m d2) -- ^ on GC without normal stop or exception
121 -> (c -> e -> Stream m b -> m (Stream m b)) -- ^ on exception
124 -> (c -> e -> Stream m b -> m (Stream m b)) -- ^ on exception
122− -> (c -> Stream m b) -- ^ stream generator
125+ -> (c -> Stream m b) -- ^ stream generator
123 -> Stream m b
126 -> Stream m b
124−gbracket bef exc aft fexc fnormal =
127+gbracket bef exc aft gc fexc fnormal =
125 Stream step GBracketIOInit
128 Stream step GBracketIOInit
126
129
127 where
130 where
@@ -137,7 +140,7 @@ gbracket bef exc aft fexc fnormal =
137 -- Tutorial: https://markkarpov.com/tutorial/exceptions.html
140 -- Tutorial: https://markkarpov.com/tutorial/exceptions.html
138 (r, ref) <- liftBaseOp_ mask_ $ do
141 (r, ref) <- liftBaseOp_ mask_ $ do
139 r <- bef
142 r <- bef
140− ref <- newIOFinalizer (aft r)
143+ ref <- newIOFinalizer (gc r)
141 return (r, ref)
144 return (r, ref)
142 return $ Skip $ GBracketIONormal (fnormal r) r ref
145 return $ Skip $ GBracketIONormal (fnormal r) r ref
143
146
@@ -149,9 +152,8 @@ gbracket bef exc aft fexc fnormal =
149 return $ Yield x (GBracketIONormal (Stream step1 s) v ref)
152 return $ Yield x (GBracketIONormal (Stream step1 s) v ref)
150 Skip s ->
153 Skip s ->
151 return $ Skip (GBracketIONormal (Stream step1 s) v ref)
154 return $ Skip (GBracketIONormal (Stream step1 s) v ref)
152− Stop -> do
155+ Stop ->
153− runIOFinalizer ref
154− return Stop
156+ clearingIOFinalizer ref (aft v) >> return Stop
155 -- XXX Do not handle async exceptions, just rethrow them.
157 -- XXX Do not handle async exceptions, just rethrow them.
156 Left e -> do
158 Left e -> do
157 -- Clearing of finalizer and running of exception handler must
159 -- Clearing of finalizer and running of exception handler must
@@ -261,12 +263,17 @@ bracket_ bef aft bet =
261
263
262-- | See 'Streamly.Internal.Data.Stream.IsStream.bracket'.
264-- | See 'Streamly.Internal.Data.Stream.IsStream.bracket'.
263--
265--
264−{-# INLINE_NORMAL bracket #-}
266+{-# INLINE_NORMAL bracket' #-}
265−bracket :: (MonadAsync m, MonadCatch m)
267+bracket' :: (MonadAsync m, MonadCatch m) =>
268+ m b
269+ -> (b -> m c)
270+ -> (b -> m d)
271+ -> (b -> m e)
272+ -> (b -> Stream m a)
266− => m b -> (b -> m c) -> (b -> Stream m a) -> Stream m a
273+ -> Stream m a
267−bracket bef aft bet =
274+bracket' bef aft exc gc =
268− gbracket bef (inline MC.try) aft
275+ gbracket bef (inline MC.try) aft gc
269− (\a (e :: SomeException) _ -> aft a >> return (nilM (MC.throwM e))) bet
276+ (\a (e :: SomeException) _ -> exc a >> return (nilM (MC.throwM e)))
270
277
271data BracketState s v = BracketInit | BracketRun s v
278data BracketState s v = BracketInit | BracketRun s v
272
279
@@ -306,7 +313,8 @@ finally_ action xs = bracket_ (return ()) (\_ -> action) (const xs)
306--
313--
307{-# INLINE finally #-}
314{-# INLINE finally #-}
308finally :: (MonadAsync m, MonadCatch m) => m b -> Stream m a -> Stream m a
315finally :: (MonadAsync m, MonadCatch m) => m b -> Stream m a -> Stream m a
309−finally action xs = bracket (return ()) (\_ -> action) (const xs)
316+finally action xs = bracket' (return ()) act act act (const xs)
317+ where act _ = action
310
318
311-- | See 'Streamly.Internal.Data.Stream.IsStream.ghandle'.
319-- | See 'Streamly.Internal.Data.Stream.IsStream.ghandle'.
312--
320--