6
6
{-# LANGUAGE ScopedTypeVariables #-}
7
7
{-# LANGUAGE TypeFamilies #-}
8
8
{-# LANGUAGE TypeOperators #-}
9
- {-# LANGUAGE UndecidableInstances #-}
10
9
{-# OPTIONS_HADDOCK not-home #-}
11
10
12
11
-- | Type safe generation of internal links.
79
78
-- bad_link under api after trying the open (but empty) type family
80
79
-- `IsElem'` as a last resort.
81
80
module Servant.Utils.Links (
81
+ module Servant.API.TypeLevel ,
82
+
82
83
-- * Building and using safe links
83
84
--
84
85
-- | Note that 'URI' is Network.URI.URI from the network-uri package.
@@ -88,18 +89,13 @@ module Servant.Utils.Links (
88
89
, HasLink (.. )
89
90
, linkURI
90
91
, Link
91
- , IsElem'
92
- -- * Illustrative exports
93
- , IsElem
94
- , Or
95
92
) where
96
93
97
94
import Data.List
98
95
import Data.Monoid.Compat ( (<>) )
99
96
import Data.Proxy ( Proxy (.. ) )
100
97
import qualified Data.Text as Text
101
98
import qualified Data.Text.Encoding as TE
102
- import GHC.Exts (Constraint )
103
99
import GHC.TypeLits ( KnownSymbol , symbolVal )
104
100
import Network.URI ( URI (.. ), escapeURIString , isUnreserved )
105
101
import Prelude ()
@@ -115,7 +111,7 @@ import Servant.API.RemoteHost ( RemoteHost )
115
111
import Servant.API.Verbs ( Verb )
116
112
import Servant.API.Sub ( type (:> ) )
117
113
import Servant.API.Raw ( Raw )
118
- import Servant.API.Alternative ( type ( :<|> ) )
114
+ import Servant.API.TypeLevel
119
115
120
116
-- | A safe link datatype.
121
117
-- The only way of constructing a 'Link' is using 'safeLink', which means any
@@ -131,58 +127,6 @@ instance ToHttpApiData Link where
131
127
let uri = linkURI l
132
128
in Text. pack $ uriPath uri ++ uriQuery uri
133
129
134
- -- | If either a or b produce an empty constraint, produce an empty constraint.
135
- type family Or (a :: Constraint ) (b :: Constraint ) :: Constraint where
136
- -- This works because of:
137
- -- https://ghc.haskell.org/trac/ghc/wiki/NewAxioms/CoincidentOverlap
138
- Or () b = ()
139
- Or a () = ()
140
-
141
- -- | If both a or b produce an empty constraint, produce an empty constraint.
142
- type family And (a :: Constraint ) (b :: Constraint ) :: Constraint where
143
- And () () = ()
144
-
145
- -- | You may use this type family to tell the type checker that your custom
146
- -- type may be skipped as part of a link. This is useful for things like
147
- -- 'QueryParam' that are optional in a URI and do not affect them if they are
148
- -- omitted.
149
- --
150
- -- >>> data CustomThing
151
- -- >>> type instance IsElem' e (CustomThing :> s) = IsElem e s
152
- --
153
- -- Note that 'IsElem' is called, which will mutually recurse back to `IsElem'`
154
- -- if it exhausts all other options again.
155
- --
156
- -- Once you have written a HasLink instance for CustomThing you are ready to
157
- -- go.
158
- type family IsElem' a s :: Constraint
159
-
160
- -- | Closed type family, check if endpoint is within api
161
- type family IsElem endpoint api :: Constraint where
162
- IsElem e (sa :<|> sb ) = Or (IsElem e sa ) (IsElem e sb )
163
- IsElem (e :> sa ) (e :> sb ) = IsElem sa sb
164
- IsElem sa (Header sym x :> sb ) = IsElem sa sb
165
- IsElem sa (ReqBody y x :> sb ) = IsElem sa sb
166
- IsElem (Capture z y :> sa ) (Capture x y :> sb )
167
- = IsElem sa sb
168
- IsElem (CaptureAll z y :> sa ) (CaptureAll x y :> sb )
169
- = IsElem sa sb
170
- IsElem sa (QueryParam x y :> sb ) = IsElem sa sb
171
- IsElem sa (QueryParams x y :> sb ) = IsElem sa sb
172
- IsElem sa (QueryFlag x :> sb ) = IsElem sa sb
173
- IsElem (Verb m s ct typ ) (Verb m s ct' typ )
174
- = IsSubList ct ct'
175
- IsElem e e = ()
176
- IsElem e a = IsElem' e a
177
-
178
- type family IsSubList a b :: Constraint where
179
- IsSubList '[] b = ()
180
- IsSubList (x ': xs ) y = Elem x y `And ` IsSubList xs y
181
-
182
- type family Elem e es :: Constraint where
183
- Elem x (x ': xs ) = ()
184
- Elem y (x ': xs ) = Elem y xs
185
-
186
130
-- Phantom types for Param
187
131
data Query
188
132
0 commit comments