@@ -39,6 +39,7 @@ module Data.Aeson.Types.Class
3939 , withText
4040 , withArray
4141 , withNumber
42+ , withScientific
4243 , withBool
4344
4445 -- * Functions
@@ -53,7 +54,8 @@ module Data.Aeson.Types.Class
5354import Control.Applicative ((<$>), (<*>), (<|>), pure, empty)
5455import Data.Aeson.Functions
5556import Data.Aeson.Types.Internal
56−import Data.Attoparsec.Char8 (Number(..))
57+import Data.Scientific (Scientific, coefficient, base10Exponent)
58+import Data.Attoparsec.Number (Number(..))
5759import Data.Fixed
5860import Data.Hashable (Hashable(..))
5961import Data.Int (Int8, Int16, Int32, Int64)
@@ -311,23 +313,21 @@ instance FromJSON Char where
311313 {-# INLINE parseJSON #-}
312314
313315instance ToJSON Double where
314− toJSON = Number . D
316+ toJSON = Number . realToFrac
315317 {-# INLINE toJSON #-}
316318
317319instance FromJSON Double where
318− parseJSON (Number n) = case n of
319− D d -> pure d
320− I i -> pure (fromIntegral i)
320+ parseJSON (Number s) = pure $ realToFrac s
321321 parseJSON Null = pure (0/0)
322322 parseJSON v = typeMismatch "Double" v
323323 {-# INLINE parseJSON #-}
324324
325325instance ToJSON Number where
326− toJSON = Number
326+ toJSON = Number . numberToScientific
327327 {-# INLINE toJSON #-}
328328
329329instance FromJSON Number where
330− parseJSON (Number n) = pure n
330+ parseJSON (Number s) = pure $ scientificToNumber s
331331 parseJSON Null = pure (D (0/0))
332332 parseJSON v = typeMismatch "Number" v
333333 {-# INLINE parseJSON #-}
@@ -337,9 +337,7 @@ instance ToJSON Float where
337337 {-# INLINE toJSON #-}
338338
339339instance FromJSON Float where
340− parseJSON (Number n) = pure $ case n of
341− D d -> realToFrac d
342− I i -> fromIntegral i
340+ parseJSON (Number s) = pure $ realToFrac s
343341 parseJSON Null = pure (0/0)
344342 parseJSON v = typeMismatch "Float" v
345343 {-# INLINE parseJSON #-}
@@ -360,9 +358,7 @@ instance HasResolution a => ToJSON (Fixed a) where
360358 {-# INLINE toJSON #-}
361359
362360instance HasResolution a => FromJSON (Fixed a) where
363− parseJSON (Number n) = pure $ case n of
364− D d -> realToFrac d
365− I i -> fromIntegral i
361+ parseJSON (Number s) = pure $ realToFrac s
366362 parseJSON v = typeMismatch "Fixed" v
367363 {-# INLINE parseJSON #-}
368364
@@ -375,7 +371,7 @@ instance FromJSON Int where
375371 {-# INLINE parseJSON #-}
376372
377373parseIntegral :: Integral a => Value -> Parser a
378−parseIntegral = withNumber "Integral" $ pure . floor
374+parseIntegral = withScientific "Integral" $ pure . floor
379375{-# INLINE parseIntegral #-}
380376
381377instance ToJSON Integer where
@@ -857,28 +853,35 @@ withObject _ f (Object obj) = f obj
857853withObject expected _ v = typeMismatch expected v
858854{-# INLINE withObject #-}
859855
860−-- | @withObject expected f value@ applies @f@ to the 'Text' when @value@ is a @String@
856+-- | @withText expected f value@ applies @f@ to the 'Text' when @value@ is a @String@
861857-- and fails using @'typeMismatch' expected@ otherwise.
862858withText :: String -> (Text -> Parser a) -> Value -> Parser a
863859withText _ f (String txt) = f txt
864860withText expected _ v = typeMismatch expected v
865861{-# INLINE withText #-}
866862
867−-- | @withObject expected f value@ applies @f@ to the 'Array' when @value@ is an @Array@
863+-- | @withArray expected f value@ applies @f@ to the 'Array' when @value@ is an @Array@
868864-- and fails using @'typeMismatch' expected@ otherwise.
869865withArray :: String -> (Array -> Parser a) -> Value -> Parser a
870866withArray _ f (Array arr) = f arr
871867withArray expected _ v = typeMismatch expected v
872868{-# INLINE withArray #-}
873869
874−-- | @withObject expected f value@ applies @f@ to the 'Number' when @value@ is a @Number@
870+-- | @withNumber expected f value@ applies @f@ to the 'Number' when @value@ is a 'Number'.
875871-- and fails using @'typeMismatch' expected@ otherwise.
876872withNumber :: String -> (Number -> Parser a) -> Value -> Parser a
877−withNumber _ f (Number num) = f num
878−withNumber expected _ v = typeMismatch expected v
873+withNumber expected f = withScientific expected (f . scientificToNumber)
879874{-# INLINE withNumber #-}
875+{-# DEPRECATED withNumber "Use withScientific instead" #-}
876+
877+-- | @withScientific expected f value@ applies @f@ to the 'Scientific' number when @value@ is a 'Number'.
878+-- and fails using @'typeMismatch' expected@ otherwise.
879+withScientific :: String -> (Scientific -> Parser a) -> Value -> Parser a
880+withScientific _ f (Number scientific) = f scientific
881+withScientific expected _ v = typeMismatch expected v
882+{-# INLINE withScientific #-}
880883
881−-- | @withObject expected f value@ applies @f@ to the 'Bool' when @value@ is a @Bool@
884+-- | @withBool expected f value@ applies @f@ to the 'Bool' when @value@ is a @Bool@
882885-- and fails using @'typeMismatch' expected@ otherwise.
883886withBool :: String -> (Bool -> Parser a) -> Value -> Parser a
884887withBool _ f (Bool arr) = f arr
@@ -954,3 +957,17 @@ typeMismatch expected actual =
954957 Number _ -> "Number"
955958 Bool _ -> "Boolean"
956959 Null -> "Null"
960+
961+scientificToNumber :: Scientific -> Number
962+scientificToNumber s
963+ | e < 0 = D $ fromInteger c / 10 ^ negate e
964+ | otherwise = I $ c * 10 ^ e
965+ where
966+ e = base10Exponent s
967+ c = coefficient s
968+{-# INLINE scientificToNumber #-}
969+
970+numberToScientific :: Number -> Scientific
971+numberToScientific (I i) = fromInteger i
972+numberToScientific (D d) = realToFrac d
973+{-# INLINE numberToScientific #-}