@@ -2,188 +2,25 @@
2{-# LANGUAGE DataKinds #-}
2{-# LANGUAGE DataKinds #-}
3{-# LANGUAGE DerivingStrategies #-}
3{-# LANGUAGE DerivingStrategies #-}
4{-# LANGUAGE FlexibleInstances #-}
4{-# LANGUAGE FlexibleInstances #-}
6−{-# LANGUAGE GeneralizedNewtypeDeriving #-}
7−{-# LANGUAGE LambdaCase #-}
8{-# LANGUAGE PolyKinds #-}
5{-# LANGUAGE PolyKinds #-}
9{-# LANGUAGE ScopedTypeVariables #-}
6{-# LANGUAGE ScopedTypeVariables #-}
10−{-# LANGUAGE StandaloneDeriving #-}
11−{-# LANGUAGE TupleSections #-}
12−{-# LANGUAGE TypeApplications #-}
13{-# LANGUAGE TypeFamilies #-}
7{-# LANGUAGE TypeFamilies #-}
14−{-# LANGUAGE TypeOperators #-}
15{-# LANGUAGE UndecidableInstances #-}
8{-# LANGUAGE UndecidableInstances #-}
17−module Roboservant.Types where
10+module Roboservant.Types
18−
11+ ( module Roboservant.Types.Breakdown,
19−import Control.Monad.Except (runExceptT)
12+ module Roboservant.Types.BuildFrom,
20−import Data.Dynamic (Dynamic, toDyn)
13+ module Roboservant.Types.ReifiedApi,
21−import Data.Function ((&))
14+ module Roboservant.Types.ReifiedApi.Server,
22−import Data.IORef (IORef)
15+ module Roboservant.Types.Internal,
23−import Data.List.NonEmpty (NonEmpty)
16+ module Roboservant.Types.Config,
24−import Data.Map.Strict (Map)
17+ )
25−import Data.Typeable (TypeRep, Typeable, typeRep)
18+where
26−import GHC.TypeLits (Symbol)
19+
27−import Hedgehog
20+import Roboservant.Types.Breakdown
28−import Servant
21+import Roboservant.Types.BuildFrom
29−import Servant.API.Modifiers
22+import Roboservant.Types.Config
30−
23+import Roboservant.Types.Internal
31−data State v
24+import Roboservant.Types.ReifiedApi
32− = State
25+import Roboservant.Types.ReifiedApi.Server
33− { stateRefs :: Map TypeRep (NonEmpty (Var (Opaque (IORef Dynamic)) v))
26+import Roboservant.Types.Orphans()
36−class FlattenServer api where
37− flattenServer :: Server api -> Bundled (Endpoints api)
40− ( Endpoints (endpoint :<|> api) ~ (endpoint ': Endpoints api),
41− Server (endpoint :<|> api) ~ (Server endpoint :<|> Server api),
44− FlattenServer (endpoint :<|> api)
46− flattenServer (endpoint :<|> server) = endpoint `AnEndpoint` flattenServer @api server
49− ( HasServer (x :> api) '[],
50− Endpoints (x :> api) ~ '[x :> api]
52− FlattenServer (x :> api)
54− flattenServer server = server `AnEndpoint` NoEndpoints
57− ( HasServer (Verb method statusCode contentTypes responseType) '[],
58− Endpoints (Verb method statusCode contentTypes responseType) ~ '[Verb method statusCode contentTypes responseType]
60− FlattenServer (Verb method statusCode contentTypes responseType)
62− flattenServer server = server `AnEndpoint` NoEndpoints
64−type ReifiedEndpoint = ([TypeRep], TypeRep, Dynamic)
66−type ReifiedApi = [(ApiOffset, [TypeRep], TypeRep, Dynamic)]
68−data Bundled endpoints where
69− AnEndpoint :: Server endpoint -> Bundled endpoints -> Bundled (endpoint ': endpoints)
70− NoEndpoints :: Bundled '[]
72−class ToReifiedApi (endpoints :: [*]) where
73− toReifiedApi :: Bundled endpoints -> Proxy endpoints -> ReifiedApi
75−class ToReifiedEndpoint (endpoint :: *) where
76− toReifiedEndpoint :: Dynamic -> Proxy endpoint -> ReifiedEndpoint
78−instance ToReifiedApi '[] where
79− toReifiedApi NoEndpoints _ = []
82− (Typeable (Normal (ServerT endpoint Handler)), NormalizeFunction (ServerT endpoint Handler), ToReifiedEndpoint endpoint, ToReifiedApi endpoints, Typeable (ServerT endpoint Handler)) =>
83− ToReifiedApi (endpoint : endpoints)
85− toReifiedApi (endpoint `AnEndpoint` endpoints) _ =
86− withOffset (toReifiedEndpoint (toDyn (normalize endpoint)) (Proxy @endpoint))
88− (\(n, x, y, z) -> (n + 1, x, y, z))
89− (toReifiedApi endpoints (Proxy @endpoints))
91− withOffset (x, y, z) = (0, x, y, z)
93−class NormalizeFunction m where
95− normalize :: m -> Normal m
97−instance NormalizeFunction x => NormalizeFunction (r -> x) where
98− type Normal (r -> x) = r -> Normal x
99− normalize = fmap normalize
101−instance Typeable x => NormalizeFunction (Handler x) where
102− type Normal (Handler x) = IO (Either ServerError (TypeRep, Dynamic))
103− normalize handler = (runExceptT . runHandler') handler >>= \case
104− Left serverError -> pure (Left serverError)
105− Right x -> pure (Right (typeRep (Proxy @x), toDyn x))
108− Typeable responseType =>
109− ToReifiedEndpoint (Verb method statusCode contentTypes responseType)
111− toReifiedEndpoint endpoint _ =
112− ([], typeRep (Proxy @responseType), endpoint)
115− (ToReifiedEndpoint endpoint) =>
116− ToReifiedEndpoint ((x :: Symbol) :> endpoint)
118− toReifiedEndpoint endpoint _ =
119− toReifiedEndpoint endpoint (Proxy @endpoint)
122− (ToReifiedEndpoint endpoint) =>
123− ToReifiedEndpoint (Description s :> endpoint)
125− toReifiedEndpoint endpoint _ =
126− toReifiedEndpoint endpoint (Proxy @endpoint)
129− (ToReifiedEndpoint endpoint) =>
130− ToReifiedEndpoint (Summary s :> endpoint)
132− toReifiedEndpoint endpoint _ =
133− toReifiedEndpoint endpoint (Proxy @endpoint)
136− (Typeable requestType, ToReifiedEndpoint endpoint) =>
137− ToReifiedEndpoint (QueryFlag name :> endpoint)
139− toReifiedEndpoint endpoint _ =
140− toReifiedEndpoint endpoint (Proxy @endpoint)
141− & \(args, result, typeRepMap) -> (typeRep (Proxy @Bool) : args, result, typeRepMap)
144− (Typeable (If (FoldRequired mods) paramType (Maybe paramType)), ToReifiedEndpoint endpoint, SBoolI (FoldRequired mods)) =>
145− ToReifiedEndpoint (QueryParam' mods name paramType :> endpoint)
147− toReifiedEndpoint endpoint _ =
148− toReifiedEndpoint endpoint (Proxy @endpoint)
149− & \(args, result, typeRepMap) -> (typeRep (Proxy @(If (FoldRequired mods) paramType (Maybe paramType))) : args, result, typeRepMap)
152− (Typeable (If (FoldRequired mods) headerType (Maybe headerType)), ToReifiedEndpoint endpoint, SBoolI (FoldRequired mods)) =>
153− ToReifiedEndpoint (Header' mods headerName headerType :> endpoint)
155− toReifiedEndpoint endpoint _ =
156− toReifiedEndpoint endpoint (Proxy @endpoint)
157− & \(args, result, typeRepMap) -> (typeRep (Proxy @(If (FoldRequired mods) headerType (Maybe headerType))) : args, result, typeRepMap)
160− (Typeable captureType, ToReifiedEndpoint endpoint) =>
161− ToReifiedEndpoint (Capture' mods name captureType :> endpoint)
163− toReifiedEndpoint endpoint _ =
164− toReifiedEndpoint endpoint (Proxy @endpoint)
165− & \(args, result, typeRepMap) -> (typeRep (Proxy @captureType) : args, result, typeRepMap)
168− (Typeable (If (FoldLenient mods) (Either String requestType) requestType), ToReifiedEndpoint endpoint, SBoolI (FoldLenient mods)) =>
169− ToReifiedEndpoint (ReqBody' mods contentTypes requestType :> endpoint)
171− toReifiedEndpoint endpoint _ =
172− toReifiedEndpoint endpoint (Proxy @endpoint)
173− & \(args, result, typeRepMap) -> (typeRep (Proxy @(If (FoldLenient mods) (Either String requestType) requestType)) : args, result, typeRepMap)
175−newtype ApiOffset = ApiOffset Int
177− deriving newtype (Enum, Num)
179−-- | we need to specify an offset because it's entirely possible to have two
180−-- functions with the same arguments that do different things.
181−data Op (v :: * -> *) = Op ApiOffset [(TypeRep, Var (Opaque (IORef Dynamic)) v)]
182− | Preload TypeRep (Var Dynamic v)
184−deriving instance Show (Op Symbolic)
186−instance HTraversable Op where
188− Op offset args -> Op offset <$> traverse (\(t, v) -> (t,) <$> htraverse r v) args
189− Preload tr v -> Preload tr <$> htraverse r v