{-# OPTIONS_GHC -fno-warn-orphans  #-}
{-# LANGUAGE FlexibleContexts      #-}
{-# LANGUAGE KindSignatures        #-}
{-# LANGUAGE RankNTypes            #-}
{-# LANGUAGE ScopedTypeVariables   #-}
{-# LANGUAGE TypeFamilies          #-}
{-# LANGUAGE TypeOperators         #-}

module  Servant.Client.Generic (
    AsClientT,
    genericClient,
    genericClientHoist,
    ) where

import           Data.Proxy
                 (Proxy (..))

import           Servant.API.Generic
import           Servant.Client.Core
import           Servant.Client.Core.HasClient (AsClientT)

-- | Generate a record of client functions.
genericClient
    :: forall routes m.
       ( HasClient m (ToServantApi routes)
       , GenericServant routes (AsClientT m)
       , Client m (ToServantApi routes) ~ ToServant routes (AsClientT m)
       )
    => routes (AsClientT m)
genericClient :: forall (routes :: Type -> Type) (m :: Type -> Type).
(HasClient m (ToServantApi routes),
 GenericServant routes (AsClientT m),
 Client m (ToServantApi routes) ~ ToServant routes (AsClientT m)) =>
routes (AsClientT m)
genericClient
    = ToServant routes (AsClientT m) -> routes (AsClientT m)
forall {k} (routes :: k -> Type) (mode :: k).
GenericServant routes mode =>
ToServant routes mode -> routes mode
fromServant
    (ToServant routes (AsClientT m) -> routes (AsClientT m))
-> ToServant routes (AsClientT m) -> routes (AsClientT m)
forall a b. (a -> b) -> a -> b
$ Proxy (ToServantApi routes)
-> Proxy m -> Client m (ToServantApi routes)
forall (m :: Type -> Type) api.
HasClient m api =>
Proxy api -> Proxy m -> Client m api
clientIn (Proxy (ToServantApi routes)
forall {k} (t :: k). Proxy t
Proxy :: Proxy (ToServantApi routes)) (Proxy m
forall {k} (t :: k). Proxy t
Proxy :: Proxy m)

-- | 'genericClient' but with 'hoistClientMonad' in between.
genericClientHoist
    :: forall routes m n.
       ( HasClient m (ToServantApi routes)
       , GenericServant routes (AsClientT n)
       , Client n (ToServantApi routes) ~ ToServant routes (AsClientT n)
       )
    => (forall x. m x -> n x)  -- ^ natural transformation
    -> routes (AsClientT n)
genericClientHoist :: forall (routes :: Type -> Type) (m :: Type -> Type)
       (n :: Type -> Type).
(HasClient m (ToServantApi routes),
 GenericServant routes (AsClientT n),
 Client n (ToServantApi routes) ~ ToServant routes (AsClientT n)) =>
(forall x. m x -> n x) -> routes (AsClientT n)
genericClientHoist forall x. m x -> n x
nt
    = ToServant routes (AsClientT n) -> routes (AsClientT n)
forall {k} (routes :: k -> Type) (mode :: k).
GenericServant routes mode =>
ToServant routes mode -> routes mode
fromServant
    (ToServant routes (AsClientT n) -> routes (AsClientT n))
-> ToServant routes (AsClientT n) -> routes (AsClientT n)
forall a b. (a -> b) -> a -> b
$ Proxy m
-> Proxy (ToServantApi routes)
-> (forall x. m x -> n x)
-> Client m (ToServantApi routes)
-> Client n (ToServantApi routes)
forall (m :: Type -> Type) api (mon :: Type -> Type)
       (mon' :: Type -> Type).
HasClient m api =>
Proxy m
-> Proxy api
-> (forall x. mon x -> mon' x)
-> Client mon api
-> Client mon' api
forall (mon :: Type -> Type) (mon' :: Type -> Type).
Proxy m
-> Proxy (ToServantApi routes)
-> (forall x. mon x -> mon' x)
-> Client mon (ToServantApi routes)
-> Client mon' (ToServantApi routes)
hoistClientMonad Proxy m
m Proxy (ToServantApi routes)
api m x -> n x
forall x. m x -> n x
nt
    (Client m (ToServantApi routes) -> Client n (ToServantApi routes))
-> Client m (ToServantApi routes) -> Client n (ToServantApi routes)
forall a b. (a -> b) -> a -> b
$ Proxy (ToServantApi routes)
-> Proxy m -> Client m (ToServantApi routes)
forall (m :: Type -> Type) api.
HasClient m api =>
Proxy api -> Proxy m -> Client m api
clientIn Proxy (ToServantApi routes)
api Proxy m
m
  where
    m :: Proxy m
m = Proxy m
forall {k} (t :: k). Proxy t
Proxy :: Proxy m
    api :: Proxy (ToServantApi routes)
api = Proxy (ToServantApi routes)
forall {k} (t :: k). Proxy t
Proxy :: Proxy (ToServantApi routes)