@@ -27,6 +27,7 @@ module Control.ActionRegistry (
27
27
, AbortActionRegistryError (.. )
28
28
, AbortActionRegistryReason (.. )
29
29
, getReasonExitCaseException
30
+ , mapExceptionWithActionRegistry
30
31
-- * Registering actions #registeringActions#
31
32
-- $registering-actions
32
33
, withRollback
@@ -42,6 +43,8 @@ import Control.Monad.Primitive
42
43
import Data.Kind
43
44
import Data.List.NonEmpty (NonEmpty (.. ))
44
45
import qualified Data.List.NonEmpty as NE
46
+ import Data.Maybe (fromMaybe )
47
+ import Data.Monoid (First (.. ))
45
48
import Data.Primitive.MutVar
46
49
47
50
#ifdef NO_IGNORE_ASSERTS
@@ -408,6 +411,46 @@ runActions = go []
408
411
Left e -> go (mkActionError e a : es) as
409
412
Right _ -> go es as
410
413
414
+ {-# SPECIALISE mapExceptionWithActionRegistry ::
415
+ (Exception e1, Exception e2)
416
+ => (e1 -> e2)
417
+ -> IO a
418
+ -> IO a #-}
419
+ -- | As 'Control.Exception.mapException', but aware of the structure of
420
+ -- 'AbortActionRegistryError' and 'CommitActionRegistryError'.
421
+ mapExceptionWithActionRegistry ::
422
+ (Exception e1 , Exception e2 , MonadCatch m )
423
+ => (e1 -> e2 )
424
+ -> m a
425
+ -> m a
426
+ mapExceptionWithActionRegistry f action = action `catch` (throwIO . mapSomeException)
427
+ where
428
+ -- TODO: This erases the `ExceptionContext` of the underlying exception.
429
+ -- Unfortunately, the API exposed by `io-classes` does not currently
430
+ -- have the primitives to preserve the `ExceptionContext`.
431
+ mapSomeException :: SomeException -> SomeException
432
+ mapSomeException e =
433
+ fromMaybe e . getFirst . mconcat . fmap First $
434
+ [ toException . f <$> fromException e
435
+ , toException . mapAbortActionRegistryError <$> fromException e
436
+ , toException . mapCommitActionRegistryError <$> fromException e
437
+ ]
438
+
439
+ mapAbortActionRegistryError :: AbortActionRegistryError -> AbortActionRegistryError
440
+ mapAbortActionRegistryError = \ case
441
+ AbortActionRegistryError reason es ->
442
+ AbortActionRegistryError (mapAbortActionRegistryReason reason) (mapActionError mapSomeException <$> es)
443
+
444
+ mapAbortActionRegistryReason :: AbortActionRegistryReason -> AbortActionRegistryReason
445
+ mapAbortActionRegistryReason = \ case
446
+ ReasonExitCaseException e -> ReasonExitCaseException (mapSomeException e)
447
+ ReasonExitCaseAbort -> ReasonExitCaseAbort
448
+
449
+ mapCommitActionRegistryError :: CommitActionRegistryError -> CommitActionRegistryError
450
+ mapCommitActionRegistryError = \ case
451
+ CommitActionRegistryError es ->
452
+ CommitActionRegistryError (mapActionError mapSomeException <$> es)
453
+
411
454
{- ------------------------------------------------------------------------------
412
455
Registering actions
413
456
-------------------------------------------------------------------------------}
0 commit comments