{-# LANGUAGE CPP #-}
{-# LANGUAGE Trustworthy #-}
{-# LANGUAGE NoImplicitPrelude #-}

module Protolude.Exceptions (
  hush,
  note,
  tryIO,
) where

import Protolude.Base (IO)
import Data.Function ((.))
import Control.Monad.Trans (liftIO)
import Control.Monad.IO.Class (MonadIO)
import Control.Monad.Except (ExceptT(ExceptT), MonadError, throwError)
import Control.Exception as Exception
import Control.Applicative
import Data.Maybe (Maybe, maybe)
import Data.Either (Either(Left,Right))

hush :: Alternative m => Either e a -> m a
hush :: forall (m :: * -> *) e a. Alternative m => Either e a -> m a
hush (Left e
_)  = m a
forall a. m a
forall (f :: * -> *) a. Alternative f => f a
empty
hush (Right a
x) = a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure a
x

-- To suppress redundant applicative constraint warning on GHC 8.0
#if ( __GLASGOW_HASKELL__ >= 800 )
note :: (MonadError e m) => e -> Maybe a -> m a
note :: forall e (m :: * -> *) a. MonadError e m => e -> Maybe a -> m a
note e
err = m a -> (a -> m a) -> Maybe a -> m a
forall b a. b -> (a -> b) -> Maybe a -> b
maybe (e -> m a
forall a. e -> m a
forall e (m :: * -> *) a. MonadError e m => e -> m a
throwError e
err) a -> m a
forall a. a -> m a
forall (f :: * -> *) a. Applicative f => a -> f a
pure
#else
note :: (MonadError e m, Applicative m) => e -> Maybe a -> m a
note err = maybe (throwError err) pure
#endif

tryIO :: MonadIO m => IO a -> ExceptT IOException m a
tryIO :: forall (m :: * -> *) a.
MonadIO m =>
IO a -> ExceptT IOException m a
tryIO = m (Either IOException a) -> ExceptT IOException m a
forall e (m :: * -> *) a. m (Either e a) -> ExceptT e m a
ExceptT (m (Either IOException a) -> ExceptT IOException m a)
-> (IO a -> m (Either IOException a))
-> IO a
-> ExceptT IOException m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO (Either IOException a) -> m (Either IOException a)
forall a. IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO (Either IOException a) -> m (Either IOException a))
-> (IO a -> IO (Either IOException a))
-> IO a
-> m (Either IOException a)
forall b c a. (b -> c) -> (a -> b) -> a -> c
. IO a -> IO (Either IOException a)
forall e a. Exception e => IO a -> IO (Either e a)
Exception.try