-- |
-- Module:      Boots.Internal.Plugin
-- Copyright:   2019 Daniel YU
-- License:     BSD3
-- Maintainer:  leptonyu@gmail.com
-- Stability:   experimental
-- Portability: portable
--
-- This module defines a generic application monad transformation.
--
module Boots.Internal.App(
    AppT
  , runAppT
  , liftIO
  , ask
  , lift
  , throwM
  ) where

import           Boots.Internal.Plugin
import           Control.Monad.Catch
import           Control.Monad.IO.Unlift
import           Control.Monad.Reader

-- | Application monad transformation.
newtype AppT cxt m a = AppT { unAppT :: ReaderT cxt m a }
  deriving (Functor, Applicative, Monad, MonadTrans, MonadReader cxt, MonadIO, MonadThrow, MonadCatch, MonadMask)

-- | Run application monad transformation.
runAppT :: cxt -> AppT cxt m a -> m a
runAppT cxt ma = runReaderT (unAppT ma) cxt

instance MonadUnliftIO m => MonadUnliftIO (AppT cxt m) where
  {-# INLINE askUnliftIO #-}
  askUnliftIO = AppT $ ReaderT $ \r ->
                withUnliftIO $ \u ->
                return (UnliftIO (unliftIO u . runAppT r))
  {-# INLINE withRunInIO #-}
  withRunInIO inner =
    AppT $ ReaderT $ \r ->
    withRunInIO $ \run ->
    inner (run . runAppT r)