@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE DefaultSignatures #-}
23{-# LANGUAGE FlexibleInstances #-}
34{-# LANGUAGE OverloadedStrings #-}
@@ -36,8 +37,14 @@ import qualified Data.Text as T
3637import qualified Data.Text.Lazy as L
3738
3839import Data.Time (Day)
40+import Data.Version
41+
42+#if MIN_VERSION_base(4,8,0)
43+import Data.Void
44+#endif
3945
4046import Text.Read (readMaybe)
47+import Text.ParserCombinators.ReadP (readP_to_S)
4148
4249-- $setup
4350--
@@ -124,7 +131,21 @@ parseBounded reader input = do
124131instance ToHttpApiData () where
125132 toUrlPiece () = "_"
126133
134+instance ToHttpApiData Char where toUrlPiece = T.singleton
135+
136+-- |
137+-- >>> toUrlPiece (Version [1, 2, 3] [])
138+-- "1.2.3"
139+instance ToHttpApiData Version where
140+ toUrlPiece = T.pack . showVersion
141+
142+#if MIN_VERSION_base(4,8,0)
143+instance ToHttpApiData Void where
144+ toUrlPiece = absurd
145+#endif
146+
127147instance ToHttpApiData Bool where toUrlPiece = showUrlPiece
148+instance ToHttpApiData Ordering where toUrlPiece = showUrlPiece
128149instance ToHttpApiData Double where toUrlPiece = showUrlPiece
129150instance ToHttpApiData Float where toUrlPiece = showUrlPiece
130151instance ToHttpApiData Int where toUrlPiece = showUrlPiece
@@ -143,6 +164,15 @@ instance ToHttpApiData Text where toUrlPiece = id
143164instance ToHttpApiData L.Text where toUrlPiece = L.toStrict
144165instance ToHttpApiData Day where toUrlPiece = showUrlPiece
145166
167+instance ToHttpApiData All where toUrlPiece = toUrlPiece . getAll
168+instance ToHttpApiData Any where toUrlPiece = toUrlPiece . getAny
169+
170+instance ToHttpApiData a => ToHttpApiData (Dual a) where toUrlPiece = toUrlPiece . getDual
171+instance ToHttpApiData a => ToHttpApiData (Sum a) where toUrlPiece = toUrlPiece . getSum
172+instance ToHttpApiData a => ToHttpApiData (Product a) where toUrlPiece = toUrlPiece . getProduct
173+instance ToHttpApiData a => ToHttpApiData (First a) where toUrlPiece = toUrlPiece . getFirst
174+instance ToHttpApiData a => ToHttpApiData (Last a) where toUrlPiece = toUrlPiece . getLast
175+
146176-- |
147177-- >>> toUrlPiece (Just "Hello")
148178-- "Just Hello"
@@ -150,6 +180,15 @@ instance ToHttpApiData a => ToHttpApiData (Maybe a) where
150180 toUrlPiece (Just x) = "Just " <> toUrlPiece x
151181 toUrlPiece Nothing = "Nothing"
152182
183+-- |
184+-- >>> toUrlPiece (Left "err" :: Either String Int)
185+-- "Left err"
186+-- >>> toUrlPiece (Right 3 :: Either String Int)
187+-- "Right 3"
188+instance (ToHttpApiData a, ToHttpApiData b) => ToHttpApiData (Either a b) where
189+ toUrlPiece (Left x) = "Left " <> toUrlPiece x
190+ toUrlPiece (Right x) = "Right " <> toUrlPiece x
191+
153192-- |
154193-- >>> parseUrlPiece "_" :: Either Text ()
155194-- Right ()
@@ -157,7 +196,28 @@ instance FromHttpApiData () where
157196 parseUrlPiece "_" = return ()
158197 parseUrlPiece s = defaultParseError s
159198
199+instance FromHttpApiData Char where
200+ parseUrlPiece s =
201+ case T.uncons s of
202+ Just (c, s') | T.null s' -> return c
203+ _ -> defaultParseError s
204+
205+-- |
206+-- >>> showVersion <$> parseUrlPiece "1.2.3"
207+-- Right "1.2.3"
208+instance FromHttpApiData Version where
209+ parseUrlPiece s =
210+ case reverse (readP_to_S parseVersion (T.unpack s)) of
211+ ((x, ""):_) -> return x
212+ _ -> defaultParseError s
213+
214+#if MIN_VERSION_base(4,8,0)
215+instance FromHttpApiData Void where
216+ parseUrlPiece _ = Left "Void cannot be parsed!"
217+#endif
218+
160219instance FromHttpApiData Bool where parseUrlPiece = readEitherUrlPiece
220+instance FromHttpApiData Ordering where parseUrlPiece = readEitherUrlPiece
161221instance FromHttpApiData Double where parseUrlPiece = runReader rational
162222instance FromHttpApiData Float where parseUrlPiece = runReader rational
163223instance FromHttpApiData Int where parseUrlPiece = parseBounded (signed decimal)
@@ -176,6 +236,15 @@ instance FromHttpApiData Text where parseUrlPiece = Right
176236instance FromHttpApiData L.Text where parseUrlPiece = Right . L.fromStrict
177237instance FromHttpApiData Day where parseUrlPiece = readEitherUrlPiece
178238
239+instance FromHttpApiData All where parseUrlPiece = fmap All . parseUrlPiece
240+instance FromHttpApiData Any where parseUrlPiece = fmap Any . parseUrlPiece
241+
242+instance FromHttpApiData a => FromHttpApiData (Dual a) where parseUrlPiece = fmap Dual . parseUrlPiece
243+instance FromHttpApiData a => FromHttpApiData (Sum a) where parseUrlPiece = fmap Sum . parseUrlPiece
244+instance FromHttpApiData a => FromHttpApiData (Product a) where parseUrlPiece = fmap Product . parseUrlPiece
245+instance FromHttpApiData a => FromHttpApiData (First a) where parseUrlPiece = fmap First . parseUrlPiece
246+instance FromHttpApiData a => FromHttpApiData (Last a) where parseUrlPiece = fmap Last . parseUrlPiece
247+
179248-- |
180249-- >>> parseUrlPiece "Just 123" :: Either Text (Maybe Int)
181250-- Right (Just 123)
@@ -186,6 +255,17 @@ instance FromHttpApiData a => FromHttpApiData (Maybe a) where
186255 Nothing -> defaultParseError s
187256 Just x -> Just <$> parseUrlPiece x
188257
258+-- |
259+-- >>> parseUrlPiece "Right 123" :: Either Text (Either String Int)
260+-- Right (Right 123)
261+instance (FromHttpApiData a, FromHttpApiData b) => FromHttpApiData (Either a b) where
262+ parseUrlPiece s =
263+ case T.stripPrefix "Right " s of
264+ Just r -> Right <$> parseUrlPiece r
265+ _ -> case T.stripPrefix "Left " s of
266+ Just l -> Left <$> parseUrlPiece l
267+ _ -> defaultParseError s
268+
189269-- $examples
190270--
191271-- Booleans: