@@ -1,15 +1,18 @@
1{-# LANGUAGE CPP #-}
1{-# LANGUAGE CPP #-}
2+{-# LANGUAGE AllowAmbiguousTypes #-}
2{-# LANGUAGE ConstraintKinds #-}
3{-# LANGUAGE ConstraintKinds #-}
3{-# LANGUAGE DataKinds #-}
4{-# LANGUAGE DataKinds #-}
4{-# LANGUAGE DeriveDataTypeable #-}
5{-# LANGUAGE DeriveDataTypeable #-}
5{-# LANGUAGE FlexibleContexts #-}
6{-# LANGUAGE FlexibleContexts #-}
6{-# LANGUAGE FlexibleInstances #-}
7{-# LANGUAGE FlexibleInstances #-}
8+{-# LANGUAGE InstanceSigs #-}
7{-# LANGUAGE MultiParamTypeClasses #-}
9{-# LANGUAGE MultiParamTypeClasses #-}
8{-# LANGUAGE OverloadedStrings #-}
10{-# LANGUAGE OverloadedStrings #-}
9{-# LANGUAGE PolyKinds #-}
11{-# LANGUAGE PolyKinds #-}
10{-# LANGUAGE RankNTypes #-}
12{-# LANGUAGE RankNTypes #-}
11{-# LANGUAGE ScopedTypeVariables #-}
13{-# LANGUAGE ScopedTypeVariables #-}
12{-# LANGUAGE TupleSections #-}
14{-# LANGUAGE TupleSections #-}
15+{-# LANGUAGE TypeApplications #-}
13{-# LANGUAGE TypeFamilies #-}
16{-# LANGUAGE TypeFamilies #-}
14{-# LANGUAGE TypeOperators #-}
17{-# LANGUAGE TypeOperators #-}
15{-# LANGUAGE UndecidableInstances #-}
18{-# LANGUAGE UndecidableInstances #-}
@@ -18,6 +21,10 @@
18#define HAS_TYPE_ERROR
21#define HAS_TYPE_ERROR
24+#if __GLASGOW_HASKELL__ >= 806
25+{-# LANGUAGE QuantifiedConstraints #-}
21module Servant.Server.Internal
28module Servant.Server.Internal
22 ( module Servant.Server.Internal
29 ( module Servant.Server.Internal
23 , module Servant.Server.Internal.BasicAuth
30 , module Servant.Server.Internal.BasicAuth
@@ -42,6 +49,7 @@ import qualified Data.ByteString as B
42import qualified Data.ByteString.Builder as BB
49import qualified Data.ByteString.Builder as BB
43import qualified Data.ByteString.Char8 as BC8
50import qualified Data.ByteString.Char8 as BC8
44import qualified Data.ByteString.Lazy as BL
51import qualified Data.ByteString.Lazy as BL
52+import Data.Constraint (Dict(..))
45import Data.Either
53import Data.Either
46 (partitionEithers)
54 (partitionEithers)
47import Data.Maybe
55import Data.Maybe
@@ -54,6 +62,7 @@ import Data.Tagged
54 (Tagged (..), retag, untag)
62 (Tagged (..), retag, untag)
55import qualified Data.Text as T
63import qualified Data.Text as T
56import Data.Typeable
64import Data.Typeable
57import GHC.TypeLits
66import GHC.TypeLits
58 (KnownNat, KnownSymbol, natVal, symbolVal)
67 (KnownNat, KnownSymbol, natVal, symbolVal)
59import qualified Network.HTTP.Media as NHM
68import qualified Network.HTTP.Media as NHM
@@ -75,7 +84,8 @@ import Servant.API
75 QueryParam', QueryParams, Raw, ReflectMethod (reflectMethod),
84 QueryParam', QueryParams, Raw, ReflectMethod (reflectMethod),
76 RemoteHost, ReqBody', SBool (..), SBoolI (..), SourceIO,
85 RemoteHost, ReqBody', SBool (..), SBoolI (..), SourceIO,
77 Stream, StreamBody', Summary, ToSourceIO (..), Vault, Verb,
86 Stream, StreamBody', Summary, ToSourceIO (..), Vault, Verb,
78− WithNamedContext)
87+ WithNamedContext, NamedRoutes)
88+import Servant.API.Generic (GenericMode(..), ToServant, ToServantApi, GServantProduct, toServant, fromServant)
79import Servant.API.ContentTypes
89import Servant.API.ContentTypes
80 (AcceptHeader (..), AllCTRender (..), AllCTUnrender (..),
90 (AcceptHeader (..), AllCTRender (..), AllCTUnrender (..),
81 AllMime, MimeRender (..), MimeUnrender (..), NoContent,
91 AllMime, MimeRender (..), MimeUnrender (..), NoContent,
@@ -905,3 +915,76 @@ instance (HasServer api context)
907-- >>> import Servant
917-- >>> import Servant
919+-- | A type that specifies that an API record contains a server implementation.
920+data AsServerT (m :: * -> *)
921+instance GenericMode (AsServerT m) where
922+ type AsServerT m :- api = ServerT api m
924+type AsServer = AsServerT Handler
927+#if __GLASGOW_HASKELL__ >= 806
929+-- | Set of constraints required to convert to / from vanilla server types.
930+type GServerConstraints api m =
931+ ( ToServant api (AsServerT m) ~ ServerT (ToServantApi api) m
932+ , GServantProduct (Rep (api (AsServerT m)))
935+-- | This class is a necessary evil: in the implementation of 'HasServer' for
936+-- @'NamedRoutes' api@, we essentially need the quantified constraint @forall
937+-- m. 'GServerConstraints' m@ to hold.
939+-- We cannot require do that directly as the definition of 'GServerConstraints'
940+-- contains type family applications ('Rep' and 'ServerT'). The trick is to hide
941+-- those type family applications behind a typeclass providing evidence for
942+-- @'GServerConstraints' api m@ in the form of a dictionary, and require that
943+-- @forall m. 'GServer' api m@ instead.
945+-- Users shouldn't have to worry about this class, as the only possible instance
946+-- is provided in this module for all record APIs.
948+class GServer (api :: * -> *) (m :: * -> *) where
949+ proof :: Dict (GServerConstraints api m)
952+ ( ToServant api (AsServerT m) ~ ServerT (ToServantApi api) m
953+ , GServantProduct (Rep (api (AsServerT m)))
954+ ) => GServer api m where
958+ ( HasServer (ToServantApi api) context
959+ , forall m. Generic (api (AsServerT m))
960+ , forall m. GServer api m
961+ ) => HasServer (NamedRoutes api) context where
963+ type ServerT (NamedRoutes api) m = api (AsServerT m)
966+ :: Proxy (NamedRoutes api)
968+ -> Delayed env (api (AsServerT Handler))
970+ route _ ctx delayed =
971+ case proof @api @Handler of
972+ Dict -> route (Proxy @(ToServantApi api)) ctx (toServant <$> delayed)
974+ hoistServerWithContext
975+ :: forall m n. Proxy (NamedRoutes api)
977+ -> (forall x. m x -> n x)
978+ -> api (AsServerT m)
979+ -> api (AsServerT n)
980+ hoistServerWithContext _ pctx nat server =
981+ case (proof @api @m, proof @api @n) of
983+ fromServant servantSrvN
985+ servantSrvM :: ServerT (ToServantApi api) m =
987+ servantSrvN :: ServerT (ToServantApi api) n =
988+ hoistServerWithContext (Proxy @(ToServantApi api)) pctx nat servantSrvM