{-# LANGUAGE UndecidableInstances #-}

-- | @DerivingVia@ machinery for adding Amazonka functionality to a reader-like
-- transformer
--
-- This is useful when you have a /ReaderT-IO/-like stack implemented with an
-- @AppT@ wrapper to which you will add the 'MonadAWS' instance:
--
-- @
-- newtype AppT m a = AppT
--   -- ...
--   deriving MonadAWS via (ReaderAWS (AppT m))
-- @
--
-- Complete example:
--
-- @
-- {-# LANGUAGE DerivingVia #-}
--
-- module Main (main) where
--
-- import qualified "Amazonka"
-- import "Control.Lens"
-- import "Control.Monad.AWS"
-- import "Control.Monad.AWS.ViaReader"
-- import "Control.Monad.Reader"
-- import "Control.Monad.Trans.Resource"
--
-- data App = App
--   { -- ...
--   , appAWS :: 'Amazonka.Env'
--   }
--
-- instance HasEnv App where
--   envL = lens appAWS $ \x y -> x { appAWS = y }
--
-- newtype AppT m a = AppT
--   { unAppT :: ReaderT App (ResourceT m) a
--   }
--   deriving newtype
--     ( Functor
--     , Applicative
--     , Monad
--     , MonadIO
--     , MonadUnliftIO
--     , MonadResource
--     , MonadReader App
--     )
--   deriving 'MonadAWS' via ('ReaderAWS' (AppT m))
--
-- runAppT :: MonadUnliftIO m => AppT m a -> App -> m a
-- runAppT f app = runResourceT $ runReaderT (unAppT f) app
--
-- main :: IO ()
-- main = do
--   app <- undefined
--   runAppT someAction app
--
-- someAction :: (MonadIO m, 'MonadAWS' m) => m ()
-- someAction = do
--   resp <- 'send' 'newListBuckets'
--   liftIO $ print resp
-- @
module Control.Monad.AWS.ViaReader
  ( Env
  , HasEnv (..)
  , ReaderAWS (..)
  ) where

import Prelude

import qualified Amazonka.Auth as Amazonka
import Amazonka.Env
import qualified Amazonka.Send as Amazonka
import Control.Lens (Lens', to, view, (%~))
import Control.Monad.AWS.Class
import Control.Monad.Reader
import Control.Monad.Trans.Resource (MonadResource)
import Data.Functor.Identity (runIdentity)

-- |
--
-- @since 0.1.0.0
class HasEnv env where
  envL :: Lens' env Env

-- |
--
-- @since 0.1.0.0
instance HasEnv Env where
  envL :: Lens' Env Env
envL = forall a. a -> a
id

-- |
--
-- @since 0.1.0.0
newtype ReaderAWS m a = ReaderAWS
  { forall (m :: * -> *) a. ReaderAWS m a -> m a
unReaderAWS :: m a
  }
  deriving newtype
    ( forall a b. a -> ReaderAWS m b -> ReaderAWS m a
forall a b. (a -> b) -> ReaderAWS m a -> ReaderAWS m b
forall (m :: * -> *) a b.
Functor m =>
a -> ReaderAWS m b -> ReaderAWS m a
forall (m :: * -> *) a b.
Functor m =>
(a -> b) -> ReaderAWS m a -> ReaderAWS m b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> ReaderAWS m b -> ReaderAWS m a
$c<$ :: forall (m :: * -> *) a b.
Functor m =>
a -> ReaderAWS m b -> ReaderAWS m a
fmap :: forall a b. (a -> b) -> ReaderAWS m a -> ReaderAWS m b
$cfmap :: forall (m :: * -> *) a b.
Functor m =>
(a -> b) -> ReaderAWS m a -> ReaderAWS m b
Functor
    , forall a. a -> ReaderAWS m a
forall a b. ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m a
forall a b. ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m b
forall a b. ReaderAWS m (a -> b) -> ReaderAWS m a -> ReaderAWS m b
forall a b c.
(a -> b -> c) -> ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
forall {m :: * -> *}. Applicative m => Functor (ReaderAWS m)
forall (m :: * -> *) a. Applicative m => a -> ReaderAWS m a
forall (m :: * -> *) a b.
Applicative m =>
ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m a
forall (m :: * -> *) a b.
Applicative m =>
ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m b
forall (m :: * -> *) a b.
Applicative m =>
ReaderAWS m (a -> b) -> ReaderAWS m a -> ReaderAWS m b
forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> c) -> ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m c
<* :: forall a b. ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m a
$c<* :: forall (m :: * -> *) a b.
Applicative m =>
ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m a
*> :: forall a b. ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m b
$c*> :: forall (m :: * -> *) a b.
Applicative m =>
ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m b
liftA2 :: forall a b c.
(a -> b -> c) -> ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m c
$cliftA2 :: forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> c) -> ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m c
<*> :: forall a b. ReaderAWS m (a -> b) -> ReaderAWS m a -> ReaderAWS m b
$c<*> :: forall (m :: * -> *) a b.
Applicative m =>
ReaderAWS m (a -> b) -> ReaderAWS m a -> ReaderAWS m b
pure :: forall a. a -> ReaderAWS m a
$cpure :: forall (m :: * -> *) a. Applicative m => a -> ReaderAWS m a
Applicative
    , forall a. a -> ReaderAWS m a
forall a b. ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m b
forall a b. ReaderAWS m a -> (a -> ReaderAWS m b) -> ReaderAWS m b
forall {m :: * -> *}. Monad m => Applicative (ReaderAWS m)
forall (m :: * -> *) a. Monad m => a -> ReaderAWS m a
forall (m :: * -> *) a b.
Monad m =>
ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m b
forall (m :: * -> *) a b.
Monad m =>
ReaderAWS m a -> (a -> ReaderAWS m b) -> ReaderAWS m b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: forall a. a -> ReaderAWS m a
$creturn :: forall (m :: * -> *) a. Monad m => a -> ReaderAWS m a
>> :: forall a b. ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m b
$c>> :: forall (m :: * -> *) a b.
Monad m =>
ReaderAWS m a -> ReaderAWS m b -> ReaderAWS m b
>>= :: forall a b. ReaderAWS m a -> (a -> ReaderAWS m b) -> ReaderAWS m b
$c>>= :: forall (m :: * -> *) a b.
Monad m =>
ReaderAWS m a -> (a -> ReaderAWS m b) -> ReaderAWS m b
Monad
    , forall a. IO a -> ReaderAWS m a
forall (m :: * -> *).
Monad m -> (forall a. IO a -> m a) -> MonadIO m
forall {m :: * -> *}. MonadIO m => Monad (ReaderAWS m)
forall (m :: * -> *) a. MonadIO m => IO a -> ReaderAWS m a
liftIO :: forall a. IO a -> ReaderAWS m a
$cliftIO :: forall (m :: * -> *) a. MonadIO m => IO a -> ReaderAWS m a
MonadIO
    , forall a. ResourceT IO a -> ReaderAWS m a
forall {m :: * -> *}. MonadResource m => MonadIO (ReaderAWS m)
forall (m :: * -> *) a.
MonadResource m =>
ResourceT IO a -> ReaderAWS m a
forall (m :: * -> *).
MonadIO m -> (forall a. ResourceT IO a -> m a) -> MonadResource m
liftResourceT :: forall a. ResourceT IO a -> ReaderAWS m a
$cliftResourceT :: forall (m :: * -> *) a.
MonadResource m =>
ResourceT IO a -> ReaderAWS m a
MonadResource
    , MonadReader env
    )

instance (MonadResource m, MonadReader env m, HasEnv env) => MonadAWS (ReaderAWS m) where
  sendEither :: forall a.
(AWSRequest a, Typeable a, Typeable (AWSResponse a)) =>
a -> ReaderAWS m (Either Error (AWSResponse a))
sendEither a
req = do
    Env
env <- forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view forall env. HasEnv env => Lens' env Env
envL
    forall (m :: * -> *) a.
(MonadResource m, AWSRequest a, Typeable a,
 Typeable (AWSResponse a)) =>
Env -> a -> m (Either Error (AWSResponse a))
Amazonka.sendEither Env
env a
req

  awaitEither :: forall a.
(AWSRequest a, Typeable a) =>
Wait a -> a -> ReaderAWS m (Either Error Accept)
awaitEither Wait a
w a
a = do
    Env
env <- forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view forall env. HasEnv env => Lens' env Env
envL
    forall (m :: * -> *) a.
(MonadResource m, AWSRequest a, Typeable a) =>
Env -> Wait a -> a -> m (Either Error Accept)
Amazonka.awaitEither Env
env Wait a
w a
a

  withAuth :: forall a. (AuthEnv -> ReaderAWS m a) -> ReaderAWS m a
withAuth AuthEnv -> ReaderAWS m a
f = do
    Auth
auth <- forall s (m :: * -> *) a. MonadReader s m => Getting a s a -> m a
view forall a b. (a -> b) -> a -> b
$ forall env. HasEnv env => Lens' env Env
envL forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (withAuth :: * -> *) (withAuth' :: * -> *).
Lens
  (Env' withAuth) (Env' withAuth') (withAuth Auth) (withAuth' Auth)
env_auth forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (p :: * -> * -> *) (f :: * -> *) s a.
(Profunctor p, Contravariant f) =>
(s -> a) -> Optic' p f s a
to forall a. Identity a -> a
runIdentity
    forall (m :: * -> *) a.
MonadIO m =>
Auth -> (AuthEnv -> m a) -> m a
Amazonka.withAuth Auth
auth AuthEnv -> ReaderAWS m a
f

  localEnv :: forall a. (Env -> Env) -> ReaderAWS m a -> ReaderAWS m a
localEnv Env -> Env
f = forall r (m :: * -> *) a. MonadReader r m => (r -> r) -> m a -> m a
local forall a b. (a -> b) -> a -> b
$ forall env. HasEnv env => Lens' env Env
envL forall s t a b. ASetter s t a b -> (a -> b) -> s -> t
%~ Env -> Env
f