@@ -1,6 +1,7 @@
11{-# LANGUAGE DefaultSignatures #-}
22{-# LANGUAGE FlexibleInstances #-}
33{-# LANGUAGE OverloadedStrings #-}
4+{-# LANGUAGE ScopedTypeVariables #-}
45{-# LANGUAGE TypeSynonymInstances #-}
56-- |
67-- Convert Haskell values to and from HTTP API data
@@ -100,6 +101,17 @@ runReader reader input =
100101 | T.null rest -> Right x
101102 | otherwise -> Left ("could not convert: `" <> input <> "'")
102103
104+-- | Run @'Reader'@ to parse bounded integral value with bounds checking.
105+parseBounded :: forall a. (Bounded a, Integral a) => Reader Integer -> Text -> Either Text a
106+parseBounded reader input = do
107+ n <- runReader reader input
108+ if (n > h || n < l)
109+ then Left ("out of bounds: `" <> input <> "' (should be between " <> T.pack (show l) <> " and " <> T.pack (show h) <> ")")
110+ else Right (fromInteger n)
111+ where
112+ l = toInteger (minBound :: a)
113+ h = toInteger (maxBound :: a)
114+
103115instance ToHttpApiData Bool where toUrlPiece = showUrlPiece
104116instance ToHttpApiData Double where toUrlPiece = showUrlPiece
105117instance ToHttpApiData Float where toUrlPiece = showUrlPiece
@@ -122,17 +134,17 @@ instance ToHttpApiData Day where toUrlPiece = showUrlPiece
122134instance FromHttpApiData Bool where parseUrlPiece = readEitherUrlPiece
123135instance FromHttpApiData Double where parseUrlPiece = runReader rational
124136instance FromHttpApiData Float where parseUrlPiece = runReader rational
125−instance FromHttpApiData Int where parseUrlPiece = runReader (signed decimal)
126−instance FromHttpApiData Int8 where parseUrlPiece = runReader (signed decimal)
127−instance FromHttpApiData Int16 where parseUrlPiece = runReader (signed decimal)
128−instance FromHttpApiData Int32 where parseUrlPiece = runReader (signed decimal)
129−instance FromHttpApiData Int64 where parseUrlPiece = runReader (signed decimal)
137+instance FromHttpApiData Int where parseUrlPiece = parseBounded (signed decimal)
138+instance FromHttpApiData Int8 where parseUrlPiece = parseBounded (signed decimal)
139+instance FromHttpApiData Int16 where parseUrlPiece = parseBounded (signed decimal)
140+instance FromHttpApiData Int32 where parseUrlPiece = parseBounded (signed decimal)
141+instance FromHttpApiData Int64 where parseUrlPiece = parseBounded (signed decimal)
130142instance FromHttpApiData Integer where parseUrlPiece = runReader (signed decimal)
131−instance FromHttpApiData Word where parseUrlPiece = runReader decimal
132−instance FromHttpApiData Word8 where parseUrlPiece = runReader decimal
133−instance FromHttpApiData Word16 where parseUrlPiece = runReader decimal
134−instance FromHttpApiData Word32 where parseUrlPiece = runReader decimal
135−instance FromHttpApiData Word64 where parseUrlPiece = runReader decimal
143+instance FromHttpApiData Word where parseUrlPiece = parseBounded decimal
144+instance FromHttpApiData Word8 where parseUrlPiece = parseBounded decimal
145+instance FromHttpApiData Word16 where parseUrlPiece = parseBounded decimal
146+instance FromHttpApiData Word32 where parseUrlPiece = parseBounded decimal
147+instance FromHttpApiData Word64 where parseUrlPiece = parseBounded decimal
136148instance FromHttpApiData String where parseUrlPiece = Right . T.unpack
137149instance FromHttpApiData Text where parseUrlPiece = Right
138150instance FromHttpApiData L.Text where parseUrlPiece = Right . L.fromStrict
@@ -155,6 +167,8 @@ instance FromHttpApiData Day where parseUrlPiece = readEitherUrlPiece
155167-- "45.2"
156168-- >>> parseUrlPiece "452" :: Either Text Int
157169-- Right 452
170+-- >>> parseUrlPiece "256" :: Either Text Int8
171+-- Left "out of bounds: `256' (should be between -128 and 127)"
158172--
159173-- Strings:
160174--