{-# LANGUAGE CPP #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE ImplicitParams #-}
-- | Please see the README.md file in the safe-exceptions repo for
-- information on how to use this module. Relevant links:
--
-- * https://github.com/fpco/safe-exceptions#readme
--
-- * https://www.stackage.org/package/safe-exceptions
module Control.Exception.Safe
    ( -- * Throwing
      throw
    , throwIO
    , throwM
    , throwString
    , StringException (..)
    , throwTo
    , impureThrow
      -- * Catching (with recovery)
    , catch
    , catchIO
    , catchAny
    , catchDeep
    , catchAnyDeep
    , catchAsync
    , catchJust

    , handle
    , handleIO
    , handleAny
    , handleDeep
    , handleAnyDeep
    , handleAsync
    , handleJust

    , try
    , tryIO
    , tryAny
    , tryDeep
    , tryAnyDeep
    , tryAsync
    , tryJust

    , Handler(..)
    , catches
    , catchesDeep
    , catchesAsync

      -- * Cleanup (no recovery)
    , onException
    , bracket
    , bracket_
    , finally
    , withException
    , bracketOnError
    , bracketOnError_
    , bracketWithError

      -- * Coercion to sync and async
    , SyncExceptionWrapper (..)
    , toSyncException
    , AsyncExceptionWrapper (..)
    , toAsyncException

      -- * Check exception type
    , isSyncException
    , isAsyncException
      -- * Reexports
    , C.MonadThrow
    , C.MonadCatch
    , C.MonadMask (..)
    , C.mask_
    , C.uninterruptibleMask_
    , C.catchIOError
    , C.handleIOError
    -- FIXME , C.tryIOError
    , Exception (..)
    , Typeable
    , SomeException (..)
    , SomeAsyncException (..)
    , E.IOException
    , E.assert
#if !MIN_VERSION_base(4,8,0)
    , displayException
#endif
    ) where

import Control.Concurrent (ThreadId)
import Control.DeepSeq (($!!), NFData)
import Control.Exception (Exception (..), SomeException (..), SomeAsyncException (..))
import qualified Control.Exception as E
import qualified Control.Monad.Catch as C
import Control.Monad.Catch (Handler (..))
import Control.Monad (liftM, void)
import Control.Monad.IO.Class (MonadIO, liftIO)
import Data.Typeable (Typeable, cast)

#if MIN_VERSION_base(4,9,0)
import GHC.Stack (prettySrcLoc)
import GHC.Stack.Types (HasCallStack, CallStack, getCallStack)
#endif

-- | Synchronously throw the given exception
--
-- @since 0.1.0.0
throw :: (C.MonadThrow m, Exception e) => e -> m a
throw :: e -> m a
throw = SomeException -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
C.throwM (SomeException -> m a) -> (e -> SomeException) -> e -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> SomeException
forall e. Exception e => e -> SomeException
toSyncException

-- | Synonym for 'throw'
--
-- @since 0.1.0.0
throwIO :: (C.MonadThrow m, Exception e) => e -> m a
throwIO :: e -> m a
throwIO = e -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw

-- | Synonym for 'throw'
--
-- @since 0.1.0.0
throwM :: (C.MonadThrow m, Exception e) => e -> m a
throwM :: e -> m a
throwM = e -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throw

-- | A convenience function for throwing a user error. This is useful
-- for cases where it would be too high a burden to define your own
-- exception type.
--
-- This throws an exception of type 'StringException'. When GHC
-- supports it (base 4.9 and GHC 8.0 and onward), it includes a call
-- stack.
--
-- @since 0.1.5.0
#if MIN_VERSION_base(4,9,0)
throwString :: (C.MonadThrow m, HasCallStack) => String -> m a
throwString :: String -> m a
throwString String
s = StringException -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM (String -> CallStack -> StringException
StringException String
s ?callStack::CallStack
CallStack
?callStack)
#else
throwString :: C.MonadThrow m => String -> m a
throwString s = throwM (StringException s ())
#endif

-- | Exception type thrown by 'throwString'.
--
-- Note that the second field of the data constructor depends on
-- GHC/base version. For base 4.9 and GHC 8.0 and later, the second
-- field is a call stack. Previous versions of GHC and base do not
-- support call stacks, and the field is simply unit (provided to make
-- pattern matching across GHC versions easier).
--
-- @since 0.1.5.0
#if MIN_VERSION_base(4,9,0)
data StringException = StringException String CallStack
  deriving Typeable

instance Show StringException where
    show :: StringException -> String
show (StringException String
s CallStack
cs) = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
        ([String] -> String) -> [String] -> String
forall a b. (a -> b) -> a -> b
$ String
"Control.Exception.Safe.throwString called with:\n\n"
        String -> [String] -> [String]
forall a. a -> [a] -> [a]
: String
s
        String -> [String] -> [String]
forall a. a -> [a] -> [a]
: String
"\nCalled from:\n"
        String -> [String] -> [String]
forall a. a -> [a] -> [a]
: ((String, SrcLoc) -> String) -> [(String, SrcLoc)] -> [String]
forall a b. (a -> b) -> [a] -> [b]
map (String, SrcLoc) -> String
go (CallStack -> [(String, SrcLoc)]
getCallStack CallStack
cs)
      where
        go :: (String, SrcLoc) -> String
go (String
x, SrcLoc
y) = [String] -> String
forall (t :: * -> *) a. Foldable t => t [a] -> [a]
concat
          [ String
"  "
          , String
x
          , String
" ("
          , SrcLoc -> String
prettySrcLoc SrcLoc
y
          , String
")\n"
          ]
#else
data StringException = StringException String ()
  deriving Typeable

instance Show StringException where
    show (StringException s _) = "Control.Exception.Safe.throwString called with:\n\n" ++ s
#endif
instance Exception StringException

-- | Throw an asynchronous exception to another thread.
--
-- Synchronously typed exceptions will be wrapped into an
-- `AsyncExceptionWrapper`, see
-- <https://github.com/fpco/safe-exceptions#determining-sync-vs-async>
--
-- It's usually a better idea to use the async package, see
-- <https://github.com/fpco/safe-exceptions#quickstart>
--
-- @since 0.1.0.0
throwTo :: (Exception e, MonadIO m) => ThreadId -> e -> m ()
throwTo :: ThreadId -> e -> m ()
throwTo ThreadId
tid = IO () -> m ()
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO () -> m ()) -> (e -> IO ()) -> e -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. ThreadId -> SomeException -> IO ()
forall e. Exception e => ThreadId -> e -> IO ()
E.throwTo ThreadId
tid (SomeException -> IO ()) -> (e -> SomeException) -> e -> IO ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> SomeException
forall e. Exception e => e -> SomeException
toAsyncException

-- | Generate a pure value which, when forced, will synchronously
-- throw the given exception
--
-- Generally it's better to avoid using this function and instead use 'throw',
-- see <https://github.com/fpco/safe-exceptions#quickstart>
--
-- @since 0.1.0.0
impureThrow :: Exception e => e -> a
impureThrow :: e -> a
impureThrow = SomeException -> a
forall a e. Exception e => e -> a
E.throw (SomeException -> a) -> (e -> SomeException) -> e -> a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> SomeException
forall e. Exception e => e -> SomeException
toSyncException

-- | Same as upstream 'C.catch', but will not catch asynchronous
-- exceptions
--
-- @since 0.1.0.0
catch :: (C.MonadCatch m, Exception e) => m a -> (e -> m a) -> m a
catch :: m a -> (e -> m a) -> m a
catch m a
f e -> m a
g = m a
f m a -> (e -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
`C.catch` \e
e ->
    if e -> Bool
forall e. Exception e => e -> Bool
isSyncException e
e
        then e -> m a
g e
e
        -- intentionally rethrowing an async exception synchronously,
        -- since we want to preserve async behavior
        else e -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
C.throwM e
e

-- | 'C.catch' specialized to only catching 'E.IOException's
--
-- @since 0.1.3.0
catchIO :: C.MonadCatch m => m a -> (E.IOException -> m a) -> m a
catchIO :: m a -> (IOException -> m a) -> m a
catchIO = m a -> (IOException -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
C.catch

-- | 'catch' specialized to catch all synchronous exception
--
-- @since 0.1.0.0
catchAny :: C.MonadCatch m => m a -> (SomeException -> m a) -> m a
catchAny :: m a -> (SomeException -> m a) -> m a
catchAny = m a -> (SomeException -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
catch

-- | Same as 'catch', but fully force evaluation of the result value
-- to find all impure exceptions.
--
-- @since 0.1.1.0
catchDeep :: (C.MonadCatch m, MonadIO m, Exception e, NFData a)
          => m a -> (e -> m a) -> m a
catchDeep :: m a -> (e -> m a) -> m a
catchDeep = m a -> (e -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
catch (m a -> (e -> m a) -> m a)
-> (m a -> m a) -> m a -> (e -> m a) -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. m a -> m a
forall (m :: * -> *) a. (MonadIO m, NFData a) => m a -> m a
evaluateDeep

-- | Internal helper function
evaluateDeep :: (MonadIO m, NFData a) => m a -> m a
evaluateDeep :: m a -> m a
evaluateDeep m a
action = do
    a
res <- m a
action
    IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (a -> IO a
forall a. a -> IO a
E.evaluate (a -> IO a) -> a -> IO a
forall a b. NFData a => (a -> b) -> a -> b
$!! a
res)

-- | 'catchDeep' specialized to catch all synchronous exception
--
-- @since 0.1.1.0
catchAnyDeep :: (C.MonadCatch m, MonadIO m, NFData a) => m a -> (SomeException -> m a) -> m a
catchAnyDeep :: m a -> (SomeException -> m a) -> m a
catchAnyDeep = m a -> (SomeException -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, MonadIO m, Exception e, NFData a) =>
m a -> (e -> m a) -> m a
catchDeep

-- | 'catch' without async exception safety
--
-- Generally it's better to avoid using this function since we do not want to
-- recover from async exceptions, see
-- <https://github.com/fpco/safe-exceptions#quickstart>
--
-- @since 0.1.0.0
catchAsync :: (C.MonadCatch m, Exception e) => m a -> (e -> m a) -> m a
catchAsync :: m a -> (e -> m a) -> m a
catchAsync = m a -> (e -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
C.catch

-- | 'catchJust' is like 'catch' but it takes an extra argument which
-- is an exception predicate, a function which selects which type of
-- exceptions we're interested in.
--
-- @since 0.1.4.0
catchJust :: (C.MonadCatch m, Exception e) => (e -> Maybe b) -> m a -> (b -> m a) -> m a
catchJust :: (e -> Maybe b) -> m a -> (b -> m a) -> m a
catchJust e -> Maybe b
f m a
a b -> m a
b = m a
a m a -> (e -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
`catch` \e
e -> m a -> (b -> m a) -> Maybe b -> m a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (e -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM e
e) b -> m a
b (Maybe b -> m a) -> Maybe b -> m a
forall a b. (a -> b) -> a -> b
$ e -> Maybe b
f e
e

-- | Flipped version of 'catch'
--
-- @since 0.1.0.0
handle :: (C.MonadCatch m, Exception e) => (e -> m a) -> m a -> m a
handle :: (e -> m a) -> m a -> m a
handle = (m a -> (e -> m a) -> m a) -> (e -> m a) -> m a -> m a
forall a b c. (a -> b -> c) -> b -> a -> c
flip m a -> (e -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
catch

-- | 'C.handle' specialized to only catching 'E.IOException's
--
-- @since 0.1.3.0
handleIO :: C.MonadCatch m => (E.IOException -> m a) -> m a -> m a
handleIO :: (IOException -> m a) -> m a -> m a
handleIO = (IOException -> m a) -> m a -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
(e -> m a) -> m a -> m a
C.handle


-- | Flipped version of 'catchAny'
--
-- @since 0.1.0.0
handleAny :: C.MonadCatch m => (SomeException -> m a) -> m a -> m a
handleAny :: (SomeException -> m a) -> m a -> m a
handleAny = (m a -> (SomeException -> m a) -> m a)
-> (SomeException -> m a) -> m a -> m a
forall a b c. (a -> b -> c) -> b -> a -> c
flip m a -> (SomeException -> m a) -> m a
forall (m :: * -> *) a.
MonadCatch m =>
m a -> (SomeException -> m a) -> m a
catchAny

-- | Flipped version of 'catchDeep'
--
-- @since 0.1.1.0
handleDeep :: (C.MonadCatch m, Exception e, MonadIO m, NFData a) => (e -> m a) -> m a -> m a
handleDeep :: (e -> m a) -> m a -> m a
handleDeep = (m a -> (e -> m a) -> m a) -> (e -> m a) -> m a -> m a
forall a b c. (a -> b -> c) -> b -> a -> c
flip m a -> (e -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, MonadIO m, Exception e, NFData a) =>
m a -> (e -> m a) -> m a
catchDeep

-- | Flipped version of 'catchAnyDeep'
--
-- @since 0.1.1.0
handleAnyDeep :: (C.MonadCatch m, MonadIO m, NFData a) => (SomeException -> m a) -> m a -> m a
handleAnyDeep :: (SomeException -> m a) -> m a -> m a
handleAnyDeep = (m a -> (SomeException -> m a) -> m a)
-> (SomeException -> m a) -> m a -> m a
forall a b c. (a -> b -> c) -> b -> a -> c
flip m a -> (SomeException -> m a) -> m a
forall (m :: * -> *) a.
(MonadCatch m, MonadIO m, NFData a) =>
m a -> (SomeException -> m a) -> m a
catchAnyDeep

-- | Flipped version of 'catchAsync'
--
-- Generally it's better to avoid using this function since we do not want to
-- recover from async exceptions, see
-- <https://github.com/fpco/safe-exceptions#quickstart>
--
-- @since 0.1.0.0
handleAsync :: (C.MonadCatch m, Exception e) => (e -> m a) -> m a -> m a
handleAsync :: (e -> m a) -> m a -> m a
handleAsync = (e -> m a) -> m a -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
(e -> m a) -> m a -> m a
C.handle

-- | Flipped 'catchJust'.
--
-- @since 0.1.4.0
handleJust :: (C.MonadCatch m, Exception e) => (e -> Maybe b) -> (b -> m a) -> m a -> m a
handleJust :: (e -> Maybe b) -> (b -> m a) -> m a -> m a
handleJust e -> Maybe b
f = (m a -> (b -> m a) -> m a) -> (b -> m a) -> m a -> m a
forall a b c. (a -> b -> c) -> b -> a -> c
flip ((e -> Maybe b) -> m a -> (b -> m a) -> m a
forall (m :: * -> *) e b a.
(MonadCatch m, Exception e) =>
(e -> Maybe b) -> m a -> (b -> m a) -> m a
catchJust e -> Maybe b
f)

-- | Same as upstream 'C.try', but will not catch asynchronous
-- exceptions
--
-- @since 0.1.0.0
try :: (C.MonadCatch m, E.Exception e) => m a -> m (Either e a)
try :: m a -> m (Either e a)
try m a
f = m (Either e a) -> (e -> m (Either e a)) -> m (Either e a)
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
catch ((a -> Either e a) -> m a -> m (Either e a)
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM a -> Either e a
forall a b. b -> Either a b
Right m a
f) (Either e a -> m (Either e a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either e a -> m (Either e a))
-> (e -> Either e a) -> e -> m (Either e a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> Either e a
forall a b. a -> Either a b
Left)

-- | 'C.try' specialized to only catching 'E.IOException's
--
-- @since 0.1.3.0
tryIO :: C.MonadCatch m => m a -> m (Either E.IOException a)
tryIO :: m a -> m (Either IOException a)
tryIO = m a -> m (Either IOException a)
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> m (Either e a)
C.try

-- | 'try' specialized to catch all synchronous exceptions
--
-- @since 0.1.0.0
tryAny :: C.MonadCatch m => m a -> m (Either SomeException a)
tryAny :: m a -> m (Either SomeException a)
tryAny = m a -> m (Either SomeException a)
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> m (Either e a)
try

-- | Same as 'try', but fully force evaluation of the result value
-- to find all impure exceptions.
--
-- @since 0.1.1.0
tryDeep :: (C.MonadCatch m, MonadIO m, E.Exception e, NFData a) => m a -> m (Either e a)
tryDeep :: m a -> m (Either e a)
tryDeep m a
f = m (Either e a) -> (e -> m (Either e a)) -> m (Either e a)
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
catch ((a -> Either e a) -> m a -> m (Either e a)
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
liftM a -> Either e a
forall a b. b -> Either a b
Right (m a -> m a
forall (m :: * -> *) a. (MonadIO m, NFData a) => m a -> m a
evaluateDeep m a
f)) (Either e a -> m (Either e a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either e a -> m (Either e a))
-> (e -> Either e a) -> e -> m (Either e a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> Either e a
forall a b. a -> Either a b
Left)

-- | 'tryDeep' specialized to catch all synchronous exceptions
--
-- @since 0.1.1.0
tryAnyDeep :: (C.MonadCatch m, MonadIO m, NFData a) => m a -> m (Either SomeException a)
tryAnyDeep :: m a -> m (Either SomeException a)
tryAnyDeep = m a -> m (Either SomeException a)
forall (m :: * -> *) e a.
(MonadCatch m, MonadIO m, Exception e, NFData a) =>
m a -> m (Either e a)
tryDeep

-- | 'try' without async exception safety
--
-- Generally it's better to avoid using this function since we do not want to
-- recover from async exceptions, see
-- <https://github.com/fpco/safe-exceptions#quickstart>
--
-- @since 0.1.0.0
tryAsync :: (C.MonadCatch m, E.Exception e) => m a -> m (Either e a)
tryAsync :: m a -> m (Either e a)
tryAsync = m a -> m (Either e a)
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> m (Either e a)
C.try

-- | A variant of 'try' that takes an exception predicate to select
-- which exceptions are caught.
--
-- @since 0.1.4.0
tryJust :: (C.MonadCatch m, Exception e) => (e -> Maybe b) -> m a -> m (Either b a)
tryJust :: (e -> Maybe b) -> m a -> m (Either b a)
tryJust e -> Maybe b
f m a
a = m (Either b a) -> (e -> m (Either b a)) -> m (Either b a)
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
catch (a -> Either b a
forall a b. b -> Either a b
Right (a -> Either b a) -> m a -> m (Either b a)
forall (m :: * -> *) a1 r. Monad m => (a1 -> r) -> m a1 -> m r
`liftM` m a
a) (\e
e -> m (Either b a)
-> (b -> m (Either b a)) -> Maybe b -> m (Either b a)
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (e -> m (Either b a)
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM e
e) (Either b a -> m (Either b a)
forall (m :: * -> *) a. Monad m => a -> m a
return (Either b a -> m (Either b a))
-> (b -> Either b a) -> b -> m (Either b a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. b -> Either b a
forall a b. a -> Either a b
Left) (e -> Maybe b
f e
e))

-- | Async safe version of 'E.onException'
--
-- @since 0.1.0.0
onException :: C.MonadMask m => m a -> m b -> m a
onException :: m a -> m b -> m a
onException m a
thing m b
after = m a -> (SomeException -> m b) -> m a
forall (m :: * -> *) e a b.
(MonadMask m, Exception e) =>
m a -> (e -> m b) -> m a
withException m a
thing (\(SomeException
_ :: SomeException) -> m b
after)

-- | Like 'onException', but provides the handler the thrown
-- exception.
--
-- @since 0.1.0.0
withException :: (C.MonadMask m, E.Exception e) => m a -> (e -> m b) -> m a
withException :: m a -> (e -> m b) -> m a
withException m a
thing e -> m b
after = ((forall a. m a -> m a) -> m a) -> m a
forall (m :: * -> *) b.
MonadMask m =>
((forall a. m a -> m a) -> m b) -> m b
C.uninterruptibleMask (((forall a. m a -> m a) -> m a) -> m a)
-> ((forall a. m a -> m a) -> m a) -> m a
forall a b. (a -> b) -> a -> b
$ \forall a. m a -> m a
restore -> do
    ((a, ()) -> a) -> m (a, ()) -> m a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, ()) -> a
forall a b. (a, b) -> a
fst (m (a, ()) -> m a) -> m (a, ()) -> m a
forall a b. (a -> b) -> a -> b
$ m () -> (() -> ExitCase a -> m ()) -> (() -> m a) -> m (a, ())
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> ExitCase b -> m c) -> (a -> m b) -> m (b, c)
C.generalBracket (() -> m ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) () -> ExitCase a -> m ()
forall a. () -> ExitCase a -> m ()
cAfter (m a -> () -> m a
forall a b. a -> b -> a
const (m a -> () -> m a) -> m a -> () -> m a
forall a b. (a -> b) -> a -> b
$ m a -> m a
forall a. m a -> m a
restore m a
thing)
  where
    -- ignore the exception from after, see bracket for explanation
    cAfter :: () -> ExitCase a -> m ()
cAfter () (C.ExitCaseException SomeException
se) | Just e
ex <- SomeException -> Maybe e
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
se =
        m b -> m ()
forall (m :: * -> *) a. MonadMask m => m a -> m ()
ignoreExceptions (m b -> m ()) -> m b -> m ()
forall a b. (a -> b) -> a -> b
$ e -> m b
after e
ex
    cAfter () ExitCase a
_ = () -> m ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

-- | Async safe version of 'E.bracket'
--
-- @since 0.1.0.0
bracket :: forall m a b c. C.MonadMask m
        => m a -> (a -> m b) -> (a -> m c) -> m c
bracket :: m a -> (a -> m b) -> (a -> m c) -> m c
bracket m a
before a -> m b
after = m a -> (Maybe SomeException -> a -> m b) -> (a -> m c) -> m c
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (Maybe SomeException -> a -> m b) -> (a -> m c) -> m c
bracketWithError m a
before ((a -> m b) -> Maybe SomeException -> a -> m b
forall a b. a -> b -> a
const a -> m b
after)

-- | Async safe version of 'E.bracket_'
--
-- @since 0.1.0.0
bracket_ :: C.MonadMask m => m a -> m b -> m c -> m c
bracket_ :: m a -> m b -> m c -> m c
bracket_ m a
before m b
after m c
thing = m a -> (a -> m b) -> (a -> m c) -> m c
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> m b) -> (a -> m c) -> m c
bracket m a
before (m b -> a -> m b
forall a b. a -> b -> a
const m b
after) (m c -> a -> m c
forall a b. a -> b -> a
const m c
thing)

-- | Async safe version of 'E.finally'
--
-- @since 0.1.0.0
finally :: C.MonadMask m => m a -> m b -> m a
finally :: m a -> m b -> m a
finally m a
thing m b
after = ((forall a. m a -> m a) -> m a) -> m a
forall (m :: * -> *) b.
MonadMask m =>
((forall a. m a -> m a) -> m b) -> m b
C.uninterruptibleMask (((forall a. m a -> m a) -> m a) -> m a)
-> ((forall a. m a -> m a) -> m a) -> m a
forall a b. (a -> b) -> a -> b
$ \forall a. m a -> m a
restore -> do
    ((a, ()) -> a) -> m (a, ()) -> m a
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (a, ()) -> a
forall a b. (a, b) -> a
fst (m (a, ()) -> m a) -> m (a, ()) -> m a
forall a b. (a -> b) -> a -> b
$ m () -> (() -> ExitCase a -> m ()) -> (() -> m a) -> m (a, ())
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> ExitCase b -> m c) -> (a -> m b) -> m (b, c)
C.generalBracket (() -> m ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()) () -> ExitCase a -> m ()
forall a. () -> ExitCase a -> m ()
cAfter (m a -> () -> m a
forall a b. a -> b -> a
const (m a -> () -> m a) -> m a -> () -> m a
forall a b. (a -> b) -> a -> b
$ m a -> m a
forall a. m a -> m a
restore m a
thing)
  where
    -- ignore the exception from after, see bracket for explanation
    cAfter :: () -> ExitCase a -> m ()
cAfter () (C.ExitCaseException SomeException
se) =
        m b -> m ()
forall (m :: * -> *) a. MonadMask m => m a -> m ()
ignoreExceptions m b
after
    cAfter () ExitCase a
_ = m b -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void m b
after

-- | Async safe version of 'E.bracketOnError'
--
-- @since 0.1.0.0
bracketOnError :: forall m a b c. C.MonadMask m
               => m a -> (a -> m b) -> (a -> m c) -> m c
bracketOnError :: m a -> (a -> m b) -> (a -> m c) -> m c
bracketOnError m a
before a -> m b
after a -> m c
thing = ((c, ()) -> c) -> m (c, ()) -> m c
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (c, ()) -> c
forall a b. (a, b) -> a
fst (m (c, ()) -> m c) -> m (c, ()) -> m c
forall a b. (a -> b) -> a -> b
$ m a -> (a -> ExitCase c -> m ()) -> (a -> m c) -> m (c, ())
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> ExitCase b -> m c) -> (a -> m b) -> m (b, c)
C.generalBracket m a
before a -> ExitCase c -> m ()
forall a. a -> ExitCase a -> m ()
cAfter a -> m c
thing
  where
    -- ignore the exception from after, see bracket for explanation
    cAfter :: a -> ExitCase a -> m ()
cAfter a
x (C.ExitCaseException SomeException
se) =
        m () -> m ()
forall (m :: * -> *) a. MonadMask m => m a -> m a
C.uninterruptibleMask_ (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ m b -> m ()
forall (m :: * -> *) a. MonadMask m => m a -> m ()
ignoreExceptions (m b -> m ()) -> m b -> m ()
forall a b. (a -> b) -> a -> b
$ a -> m b
after a
x
    cAfter a
x ExitCase a
_ = () -> m ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ()


-- | A variant of 'bracketOnError' where the return value from the first
-- computation is not required.
--
-- @since 0.1.0.0
bracketOnError_ :: C.MonadMask m => m a -> m b -> m c -> m c
bracketOnError_ :: m a -> m b -> m c -> m c
bracketOnError_ m a
before m b
after m c
thing = m a -> (a -> m b) -> (a -> m c) -> m c
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> m b) -> (a -> m c) -> m c
bracketOnError m a
before (m b -> a -> m b
forall a b. a -> b -> a
const m b
after) (m c -> a -> m c
forall a b. a -> b -> a
const m c
thing)

-- | Async safe version of 'E.bracket' with access to the exception in the
-- cleanup action.
--
-- @since 0.1.7.0
bracketWithError :: forall m a b c. C.MonadMask m
        => m a -> (Maybe SomeException -> a -> m b) -> (a -> m c) -> m c
bracketWithError :: m a -> (Maybe SomeException -> a -> m b) -> (a -> m c) -> m c
bracketWithError m a
before Maybe SomeException -> a -> m b
after a -> m c
thing = ((c, ()) -> c) -> m (c, ()) -> m c
forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (c, ()) -> c
forall a b. (a, b) -> a
fst (m (c, ()) -> m c) -> m (c, ()) -> m c
forall a b. (a -> b) -> a -> b
$ m a -> (a -> ExitCase c -> m ()) -> (a -> m c) -> m (c, ())
forall (m :: * -> *) a b c.
MonadMask m =>
m a -> (a -> ExitCase b -> m c) -> (a -> m b) -> m (b, c)
C.generalBracket m a
before a -> ExitCase c -> m ()
forall a. a -> ExitCase a -> m ()
cAfter a -> m c
thing
  where
    cAfter :: a -> ExitCase a -> m ()
cAfter a
x (C.ExitCaseException SomeException
se) =
        m () -> m ()
forall (m :: * -> *) a. MonadMask m => m a -> m a
C.uninterruptibleMask_ (m () -> m ()) -> m () -> m ()
forall a b. (a -> b) -> a -> b
$ m b -> m ()
forall (m :: * -> *) a. MonadMask m => m a -> m ()
ignoreExceptions (m b -> m ()) -> m b -> m ()
forall a b. (a -> b) -> a -> b
$ Maybe SomeException -> a -> m b
after (SomeException -> Maybe SomeException
forall a. a -> Maybe a
Just SomeException
se) a
x
    cAfter a
x ExitCase a
_ =
        m b -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void (m b -> m ()) -> m b -> m ()
forall a b. (a -> b) -> a -> b
$ m b -> m b
forall (m :: * -> *) a. MonadMask m => m a -> m a
C.uninterruptibleMask_ (m b -> m b) -> m b -> m b
forall a b. (a -> b) -> a -> b
$ Maybe SomeException -> a -> m b
after Maybe SomeException
forall a. Maybe a
Nothing a
x

-- | Internal function that swallows all exceptions, used in some bracket-like
-- combinators. When it's run inside of uninterruptibleMask, we know that
-- no async exceptions can be thrown from thing, so the other exception from
-- the combinator will not be overridden.
--
-- https://github.com/fpco/safe-exceptions/issues/2
ignoreExceptions :: C.MonadMask m => m a -> m ()
ignoreExceptions :: m a -> m ()
ignoreExceptions m a
thing = m a -> m ()
forall (f :: * -> *) a. Functor f => f a -> f ()
void m a
thing m () -> (SomeException -> m ()) -> m ()
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
`C.catch` (\(SomeException
_ :: SomeException) -> () -> m ()
forall (f :: * -> *) a. Applicative f => a -> f a
pure ())

-- | Wrap up an asynchronous exception to be treated as a synchronous
-- exception
--
-- This is intended to be created via 'toSyncException'
--
-- @since 0.1.0.0
data SyncExceptionWrapper = forall e. Exception e => SyncExceptionWrapper e
    deriving Typeable
instance Show SyncExceptionWrapper where
    show :: SyncExceptionWrapper -> String
show (SyncExceptionWrapper e
e) = e -> String
forall a. Show a => a -> String
show e
e
instance Exception SyncExceptionWrapper where
#if MIN_VERSION_base(4,8,0)
    displayException :: SyncExceptionWrapper -> String
displayException (SyncExceptionWrapper e
e) = e -> String
forall e. Exception e => e -> String
displayException e
e
#endif

-- | Convert an exception into a synchronous exception
--
-- For synchronous exceptions, this is the same as 'toException'.
-- For asynchronous exceptions, this will wrap up the exception with
-- 'SyncExceptionWrapper'
--
-- @since 0.1.0.0
toSyncException :: Exception e => e -> SomeException
toSyncException :: e -> SomeException
toSyncException e
e =
    case SomeException -> Maybe SomeAsyncException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
se of
        Just (SomeAsyncException e
_) -> SyncExceptionWrapper -> SomeException
forall e. Exception e => e -> SomeException
toException (e -> SyncExceptionWrapper
forall e. Exception e => e -> SyncExceptionWrapper
SyncExceptionWrapper e
e)
        Maybe SomeAsyncException
Nothing -> SomeException
se
  where
    se :: SomeException
se = e -> SomeException
forall e. Exception e => e -> SomeException
toException e
e

-- | Wrap up a synchronous exception to be treated as an asynchronous
-- exception
--
-- This is intended to be created via 'toAsyncException'
--
-- @since 0.1.0.0
data AsyncExceptionWrapper = forall e. Exception e => AsyncExceptionWrapper e
    deriving Typeable
instance Show AsyncExceptionWrapper where
    show :: AsyncExceptionWrapper -> String
show (AsyncExceptionWrapper e
e) = e -> String
forall a. Show a => a -> String
show e
e
instance Exception AsyncExceptionWrapper where
    toException :: AsyncExceptionWrapper -> SomeException
toException = SomeAsyncException -> SomeException
forall e. Exception e => e -> SomeException
toException (SomeAsyncException -> SomeException)
-> (AsyncExceptionWrapper -> SomeAsyncException)
-> AsyncExceptionWrapper
-> SomeException
forall b c a. (b -> c) -> (a -> b) -> a -> c
. AsyncExceptionWrapper -> SomeAsyncException
forall e. Exception e => e -> SomeAsyncException
SomeAsyncException
    fromException :: SomeException -> Maybe AsyncExceptionWrapper
fromException SomeException
se = do
        SomeAsyncException e
e <- SomeException -> Maybe SomeAsyncException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
se
        e -> Maybe AsyncExceptionWrapper
forall a b. (Typeable a, Typeable b) => a -> Maybe b
cast e
e
#if MIN_VERSION_base(4,8,0)
    displayException :: AsyncExceptionWrapper -> String
displayException (AsyncExceptionWrapper e
e) = e -> String
forall e. Exception e => e -> String
displayException e
e
#endif

-- | Convert an exception into an asynchronous exception
--
-- For asynchronous exceptions, this is the same as 'toException'.
-- For synchronous exceptions, this will wrap up the exception with
-- 'AsyncExceptionWrapper'
--
-- @since 0.1.0.0
toAsyncException :: Exception e => e -> SomeException
toAsyncException :: e -> SomeException
toAsyncException e
e =
    case SomeException -> Maybe SomeAsyncException
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
se of
        Just (SomeAsyncException e
_) -> SomeException
se
        Maybe SomeAsyncException
Nothing -> AsyncExceptionWrapper -> SomeException
forall e. Exception e => e -> SomeException
toException (e -> AsyncExceptionWrapper
forall e. Exception e => e -> AsyncExceptionWrapper
AsyncExceptionWrapper e
e)
  where
    se :: SomeException
se = e -> SomeException
forall e. Exception e => e -> SomeException
toException e
e

-- | Check if the given exception is synchronous
--
-- @since 0.1.0.0
isSyncException :: Exception e => e -> Bool
isSyncException :: e -> Bool
isSyncException e
e =
    case SomeException -> Maybe SomeAsyncException
forall e. Exception e => SomeException -> Maybe e
fromException (e -> SomeException
forall e. Exception e => e -> SomeException
toException e
e) of
        Just (SomeAsyncException e
_) -> Bool
False
        Maybe SomeAsyncException
Nothing -> Bool
True

-- | Check if the given exception is asynchronous
--
-- @since 0.1.0.0
isAsyncException :: Exception e => e -> Bool
isAsyncException :: e -> Bool
isAsyncException = Bool -> Bool
not (Bool -> Bool) -> (e -> Bool) -> e -> Bool
forall b c a. (b -> c) -> (a -> b) -> a -> c
. e -> Bool
forall e. Exception e => e -> Bool
isSyncException
{-# INLINE isAsyncException #-}

#if !MIN_VERSION_base(4,8,0)
-- | A synonym for 'show', specialized to 'Exception' instances.
--
-- Starting with base 4.8, the 'Exception' typeclass has a method @displayException@, used for user-friendly display of exceptions. This function provides backwards compatibility for users on base 4.7 and earlier, so that anyone importing this module can simply use @displayException@.
--
-- @since 0.1.1.0
displayException :: Exception e => e -> String
displayException = show
#endif

-- | Same as upstream 'C.catches', but will not catch asynchronous
-- exceptions
--
-- @since 0.1.2.0
catches :: (C.MonadCatch m, C.MonadThrow m) => m a -> [Handler m a] -> m a
catches :: m a -> [Handler m a] -> m a
catches m a
io [Handler m a]
handlers = m a
io m a -> (SomeException -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
`catch` [Handler m a] -> SomeException -> m a
forall (m :: * -> *) a.
MonadThrow m =>
[Handler m a] -> SomeException -> m a
catchesHandler [Handler m a]
handlers

-- | Same as 'catches', but fully force evaluation of the result value
-- to find all impure exceptions.
--
-- @since 0.1.2.0
catchesDeep :: (C.MonadCatch m, C.MonadThrow m, MonadIO m, NFData a) => m a -> [Handler m a] -> m a
catchesDeep :: m a -> [Handler m a] -> m a
catchesDeep m a
io [Handler m a]
handlers = m a -> m a
forall (m :: * -> *) a. (MonadIO m, NFData a) => m a -> m a
evaluateDeep m a
io m a -> (SomeException -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
`catch` [Handler m a] -> SomeException -> m a
forall (m :: * -> *) a.
MonadThrow m =>
[Handler m a] -> SomeException -> m a
catchesHandler [Handler m a]
handlers

-- | 'catches' without async exception safety
--
-- Generally it's better to avoid using this function since we do not want to
-- recover from async exceptions, see
-- <https://github.com/fpco/safe-exceptions#quickstart>
--
-- @since 0.1.2.0
catchesAsync :: (C.MonadCatch m, C.MonadThrow m) => m a -> [Handler m a] -> m a
catchesAsync :: m a -> [Handler m a] -> m a
catchesAsync m a
io [Handler m a]
handlers = m a
io m a -> (SomeException -> m a) -> m a
forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
`catchAsync` [Handler m a] -> SomeException -> m a
forall (m :: * -> *) a.
MonadThrow m =>
[Handler m a] -> SomeException -> m a
catchesHandler [Handler m a]
handlers

catchesHandler :: (C.MonadThrow m) => [Handler m a] -> SomeException -> m a
catchesHandler :: [Handler m a] -> SomeException -> m a
catchesHandler [Handler m a]
handlers SomeException
e = (Handler m a -> m a -> m a) -> m a -> [Handler m a] -> m a
forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr Handler m a -> m a -> m a
forall (m :: * -> *) a. Handler m a -> m a -> m a
tryHandler (SomeException -> m a
forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
C.throwM SomeException
e) [Handler m a]
handlers
    where tryHandler :: Handler m a -> m a -> m a
tryHandler (Handler e -> m a
handler) m a
res
              = case SomeException -> Maybe e
forall e. Exception e => SomeException -> Maybe e
fromException SomeException
e of
                Just e
e' -> e -> m a
handler e
e'
                Maybe e
Nothing -> m a
res