-- | Error handling in B9 via extensible effects. -- B9 wraps errors in `SomeException`. -- -- @since 0.5.64 module B9.B9Error ( throwSomeException, throwSomeException_, throwB9Error, throwB9Error_, errorOnException, ExcB9, WithIoExceptions, runExcB9, B9Error (MkB9Error), fromB9Error, catchB9Error, catchB9ErrorAsEither, finallyB9, ) where import Control.Eff as Eff import Control.Eff.Exception as Eff import Control.Exception ( Exception, SomeException, displayException, toException, ) import Control.Monad import Data.String (IsString (..)) -- | The exception effect used in most places in B9. -- This is `Exc` specialized with `SomeException`. -- -- @since 0.5.64 type ExcB9 = Exc SomeException -- | Constraint alias for the exception effect that allows to -- throw 'SomeException'. -- -- @since 1.0.0 type WithIoExceptions e = SetMember Exc (Exc SomeException) e -- | This is a simple runtime exception to indicate that B9 code encountered -- some exceptional event. -- -- @since 0.5.64 newtype B9Error = MkB9Error {fromB9Error :: String} deriving (IsString) instance Show B9Error where show (MkB9Error msg) = "B9 internal error: " ++ msg instance Exception B9Error -- | Run an `ExcB9`. -- -- @since 0.5.64 runExcB9 :: Eff (ExcB9 ': e) a -> Eff e (Either SomeException a) runExcB9 = runError -- | Run an `ExcB9` and rethrow the exception with `error`. -- -- @since 0.5.64 errorOnException :: Eff (ExcB9 ': e) a -> Eff e a errorOnException = runError >=> either (error . displayException) pure -- | 'SomeException' wrapped into 'Exc'ecption 'Eff'ects -- -- @since 0.5.64 throwSomeException :: (Member ExcB9 e, Exception x) => x -> Eff e a throwSomeException = throwError . toException -- | 'SomeException' wrapped into 'Exc'ecption 'Eff'ects -- -- @since 0.5.64 throwSomeException_ :: (Member ExcB9 e, Exception x) => x -> Eff e () throwSomeException_ = throwError_ . toException -- | 'SomeException' wrapped into 'Exc'ecption 'Eff'ects -- -- @since 0.5.64 throwB9Error :: Member ExcB9 e => String -> Eff e a throwB9Error = throwSomeException . MkB9Error -- | 'SomeException' wrapped into 'Exc'ecption 'Eff'ects -- -- @since 0.5.64 throwB9Error_ :: Member ExcB9 e => String -> Eff e () throwB9Error_ = throwSomeException_ . MkB9Error -- | Catch exceptions. -- -- @since 0.5.64 catchB9Error :: Member ExcB9 e => Eff e a -> (SomeException -> Eff e a) -> Eff e a catchB9Error = catchError -- | Catch exceptions and return them via 'Either'. -- -- @since 0.5.64 catchB9ErrorAsEither :: Member ExcB9 e => Eff e a -> Eff e (Either SomeException a) catchB9ErrorAsEither x = catchB9Error (Right <$> x) (pure . Left) -- | Always execute an action and rethrow any exceptions caught. -- -- @since 1.0.0 finallyB9 :: Member ExcB9 e => Eff e a -> Eff e () -> Eff e a finallyB9 mainAction cleanupAction = catchB9Error ( do res <- mainAction cleanupAction return res ) (\e -> cleanupAction >> throwSomeException e)