@@ -7,14 +7,16 @@
77{-# LANGUAGE MultiParamTypeClasses #-}
88{-# LANGUAGE NoImplicitPrelude #-}
99{-# LANGUAGE OverloadedStrings #-}
10−{-# LANGUAGE PolyKinds #-}
1110{-# LANGUAGE RecordWildCards #-}
1211{-# LANGUAGE ScopedTypeVariables #-}
1312{-# LANGUAGE TypeOperators #-}
14−{-# LANGUAGE TupleSections #-}
1513{-# LANGUAGE UndecidableInstances #-}
1614{-# LANGUAGE ViewPatterns #-}
1715
16+#if __GLASGOW_HASKELL__ >= 706
17+{-# LANGUAGE PolyKinds #-}
18+#endif
19+
1820#include "incoherent-compat.h"
1921#include "overlapping-compat.h"
2022
@@ -23,6 +25,7 @@
2325
2426module Data.Aeson.Types.FromJSON
2527 (
28+
2629 -- * Core JSON classes
2730 FromJSON(..)
2831 -- * Liftings to unary and binary type constructors
@@ -118,9 +121,9 @@ import GHC.Generics
118121import Numeric.Natural (Natural)
119122import Text.ParserCombinators.ReadP (readP_to_S)
120123import Unsafe.Coerce (unsafeCoerce)
124+import qualified Data.Aeson.Compat as Compat
121125import qualified Data.Aeson.Parser.Time as Time
122126import qualified Data.Attoparsec.ByteString.Char8 as A (endOfInput, parseOnly, scientific)
123−import qualified Data.ByteString.Lazy as L
124127import qualified Data.DList as DList
125128import qualified Data.HashMap.Strict as H
126129import qualified Data.HashSet as HashSet
@@ -155,8 +158,18 @@ import qualified Data.Primitive.UnliftedArray as PM
155158import qualified Data.Primitive.PrimArray as PM
156159#endif
157160
161+#ifndef HAS_COERCIBLE
162+#define HAS_COERCIBLE (__GLASGOW_HASKELL__ >= 707)
163+#endif
158164
165+#if HAS_COERCIBLE
159166import Data.Coerce (Coercible, coerce)
167+coerce' :: Coercible a b => a -> b
168+coerce' = coerce
169+#else
170+coerce' :: a -> b
171+coerce' = unsafeCoerce
172+#endif
160173
161174parseIndexedJSON :: (Value -> Parser a) -> Int -> Value -> Parser a
162175parseIndexedJSON p idx value = p value <?> Index idx
@@ -428,7 +441,11 @@ class FromJSONKey a where
428441-- At the moment this type is intentionally not exported. 'FromJSONKeyFunction'
429442-- can be inspected, but cannot be constructed.
430443data CoerceText a where
444+#if HAS_COERCIBLE
431445 CoerceText :: Coercible Text a => CoerceText a
446+#else
447+ CoerceText :: CoerceText a
448+#endif
432449
433450-- | This type is related to 'ToJSONKeyFunction'. If 'FromJSONKeyValue' is used in the
434451-- 'FromJSONKey' instance, then 'ToJSONKeyValue' should be used in the 'ToJSONKey'
@@ -448,7 +465,7 @@ data FromJSONKeyFunction a
448465
449466-- | Only law abiding up to interpretation
450467instance Functor FromJSONKeyFunction where
451− fmap h (FromJSONKeyCoerce CoerceText) = FromJSONKeyText (h . coerce)
468+ fmap h (FromJSONKeyCoerce CoerceText) = FromJSONKeyText (h . coerce')
452469 fmap h (FromJSONKeyText f) = FromJSONKeyText (h . f)
453470 fmap h (FromJSONKeyTextParser f) = FromJSONKeyTextParser (fmap h . f)
454471 fmap h (FromJSONKeyValue f) = FromJSONKeyValue (fmap h . f)
@@ -462,7 +479,9 @@ instance Functor FromJSONKeyFunction where
462479--
463480-- On pre GHC 7.8 this is unconstrainted function.
464481fromJSONKeyCoerce ::
482+#if HAS_COERCIBLE
465483 Coercible Text a =>
484+#endif
466485 FromJSONKeyFunction a
467486fromJSONKeyCoerce = FromJSONKeyCoerce CoerceText
468487
@@ -470,18 +489,29 @@ fromJSONKeyCoerce = FromJSONKeyCoerce CoerceText
470489--
471490-- See note on 'fromJSONKeyCoerce'.
472491coerceFromJSONKeyFunction ::
492+#if HAS_COERCIBLE
473493 Coercible a b =>
494+#endif
474495 FromJSONKeyFunction a -> FromJSONKeyFunction b
496+#if HAS_COERCIBLE
475497coerceFromJSONKeyFunction = coerce
498+#else
499+coerceFromJSONKeyFunction (FromJSONKeyCoerce CoerceText) = FromJSONKeyCoerce CoerceText
500+coerceFromJSONKeyFunction (FromJSONKeyText f) = FromJSONKeyText (coerce' . f)
501+coerceFromJSONKeyFunction (FromJSONKeyTextParser f) = FromJSONKeyTextParser (fmap coerce' . f)
502+coerceFromJSONKeyFunction (FromJSONKeyValue f) = FromJSONKeyValue (fmap coerce' . f)
503+#endif
476504
477505{-# RULES
478506 "FromJSONKeyCoerce: fmap id" forall (x :: FromJSONKeyFunction a).
479507 fmap id x = x
480508 #-}
509+#if HAS_COERCIBLE
481510{-# RULES
482511 "FromJSONKeyCoerce: fmap coerce" forall x .
483512 fmap coerce x = coerceFromJSONKeyFunction x
484513 #-}
514+#endif
485515
486516-- | Same as 'fmap'. Provided for the consistency with 'ToJSONKeyFunction'.
487517mapFromJSONKeyFunction :: (a -> b) -> FromJSONKeyFunction a -> FromJSONKeyFunction b
@@ -676,6 +706,7 @@ instance (FromJSON a) => FromJSON [a] where
676706prependContext :: String -> Parser a -> Parser a
677707prependContext name = prependFailure ("parsing " ++ name ++ " failed, ")
678708
709+
679710-- | @'withObject' name f value@ applies @f@ to the 'Object' when @value@
680711-- is an 'Data.Aeson.Object' and fails otherwise.
681712--
@@ -768,13 +799,13 @@ withBoundedScientific' f v = withBoundedScientific_ id f v
768799-- | A variant of 'withBoundedScientific_' parameterized by a function to apply
769800-- to the 'Parser' in case of failure.
770801withBoundedScientific_ :: (Parser a -> Parser a) -> (Scientific -> Parser a) -> Value -> Parser a
771−withBoundedScientific_ whenFail f (Number scientific) =
772− if exp10 > 1024
802+withBoundedScientific_ whenFail f v@(Number scientific) =
803+ if exponent > 1024
773804 then whenFail (fail msg)
774805 else f scientific
775806 where
776− exp10 = base10Exponent scientific
777− msg = "found a number with exponent " ++ show exp10 ++ ", but it must not be greater than 1024"
807+ exponent = base10Exponent scientific
808+ msg = "found a number with exponent " ++ show exponent ++ ", but it must not be greater than 1024"
778809withBoundedScientific_ whenFail _ v =
779810 whenFail (typeMismatch "Number" v)
780811{-# INLINE withBoundedScientific_ #-}
@@ -794,7 +825,7 @@ withBool name _ v = prependContext name (typeMismatch "Boolean" v)
794825-- | Decode a nested JSON-encoded string.
795826withEmbeddedJSON :: String -> (Value -> Parser a) -> Value -> Parser a
796827withEmbeddedJSON _ innerParser (String txt) =
797− either fail innerParser $ eitherDecode (L.fromStrict $ T.encodeUtf8 txt)
828+ either fail innerParser $ eitherDecode (Compat.fromStrict $ T.encodeUtf8 txt)
798829 where
799830 eitherDecode = eitherFormatError . eitherDecodeWith jsonEOF ifromJSON
800831 eitherFormatError = either (Left . uncurry formatError) Right
@@ -930,7 +961,7 @@ contextType = prependContext
930961contextTag :: Text -> [String] -> Parser a -> Parser a
931962contextTag tagKey cnames = prependFailure
932963 ("expected Object with key \"" ++ unpack tagKey ++ "\"" ++
933− " containing one of " ++ show cnames ++ ", ")
964+ " associated to one of " ++ show cnames ++ ", ")
934965
935966-- | Add the name of the constructor being parsed to a parser's error messages.
936967contextCons :: ConName -> TypeName -> Parser a -> Parser a
@@ -1201,9 +1232,9 @@ class FromTaggedObject' arity f isRecord where
12011232 :: String :* ConName :* TypeName :* Options :* FromArgs arity a
12021233 -> Object -> Tagged isRecord (Parser (f a))
12031234
1204−instance (RecordFromJSON arity f, FieldNames f) => FromTaggedObject' arity f True where
1235+instance (RecordFromJSON arity f) => FromTaggedObject' arity f True where
12051236 -- Records are unpacked in the tagged object
1206− parseFromTaggedObject' (_ :* p) = Tagged . recordParseJSON (True :* p)
1237+ parseFromTaggedObject' (_ :* p) = Tagged . recordParseJSON p
12071238
12081239instance (ConsFromJSON arity f) => FromTaggedObject' arity f False where
12091240 -- Nonnullary nonrecords are encoded in the contents field
@@ -1244,11 +1275,11 @@ instance OVERLAPPING_
12441275 ) => ConsFromJSON' arity (S1 s a) True where
12451276 consParseJSON' p@(cname :* tname :* opts :* fargs)
12461277 | unwrapUnaryRecords opts = Tagged . fmap M1 . gParseJSON opts fargs
1247− | otherwise = Tagged . withObject (showCons cname tname) (recordParseJSON (False :* p))
1278+ | otherwise = Tagged . withObject (showCons cname tname) (recordParseJSON p)
12481279
12491280instance RecordFromJSON arity f => ConsFromJSON' arity f True where
12501281 consParseJSON' p@(cname :* tname :* _) =
1251− Tagged . withObject (showCons cname tname) (recordParseJSON (False :* p))
1282+ Tagged . withObject (showCons cname tname) (recordParseJSON p)
12521283
12531284instance OVERLAPPING_
12541285 ConsFromJSON' arity U1 False where
@@ -1274,55 +1305,21 @@ instance (ProductFromJSON arity f, ProductSize f
12741305
12751306--------------------------------------------------------------------------------
12761307
1277−class FieldNames f where
1278− fieldNames :: f a -> [Text] -> [Text]
1279−
1280−instance (FieldNames a, FieldNames b) => FieldNames (a :*: b) where
1281− fieldNames _ =
1282− fieldNames (undefined :: a x) .
1283− fieldNames (undefined :: b y)
1284−
1285−instance (Selector s) => FieldNames (S1 s f) where
1286− fieldNames _ = (pack (selName (undefined :: M1 _i s _f _p)) :)
1287−
12881308class RecordFromJSON arity f where
12891309 recordParseJSON
1290− :: Bool :* ConName :* TypeName :* Options :* FromArgs arity a
1291− -> Object -> Parser (f a)
1292−
1293−instance ( FieldNames f
1294− , RecordFromJSON' arity f
1295− ) => RecordFromJSON arity f where
1296− recordParseJSON (fromTaggedSum :* p@(cname :* tname :* opts :* _)) =
1297− \obj -> checkUnknown obj >> recordParseJSON' p obj
1298− where
1299− knownFields :: H.HashMap Text ()
1300− knownFields = H.fromList $ map (,()) $
1301− fieldNames (undefined :: f a)
1302− [pack (tagFieldName (sumEncoding opts)) | fromTaggedSum]
1303− checkUnknown =
1304− if not (rejectUnknownFields opts)
1305− then \_ -> return ()
1306− else \obj -> case H.keys (H.difference obj knownFields) of
1307− [] -> return ()
1308− unknownFields -> contextCons cname tname $
1309− fail ("unknown fields: " ++ show unknownFields)
1310−
1311−class RecordFromJSON' arity f where
1312− recordParseJSON'
13131310 :: ConName :* TypeName :* Options :* FromArgs arity a
13141311 -> Object -> Parser (f a)
13151312
1316−instance ( RecordFromJSON' arity a
1317− , RecordFromJSON' arity b
1318− ) => RecordFromJSON' arity (a :*: b) where
1319− recordParseJSON' p obj =
1320− (:*:) <$> recordParseJSON' p obj
1321− <*> recordParseJSON' p obj
1313+instance ( RecordFromJSON arity a
1314+ , RecordFromJSON arity b
1315+ ) => RecordFromJSON arity (a :*: b) where
1316+ recordParseJSON p obj =
1317+ (:*:) <$> recordParseJSON p obj
1318+ <*> recordParseJSON p obj
13221319
13231320instance OVERLAPPABLE_ (Selector s, GFromJSON arity a) =>
1324− RecordFromJSON' arity (S1 s a) where
1325− recordParseJSON' (cname :* tname :* opts :* fargs) obj = do
1321+ RecordFromJSON arity (S1 s a) where
1322+ recordParseJSON (cname :* tname :* opts :* fargs) obj = do
13261323 fv <- contextCons cname tname (obj .: label)
13271324 M1 <$> gParseJSON opts fargs fv <?> Key label
13281325 where
@@ -1330,16 +1327,16 @@ instance OVERLAPPABLE_ (Selector s, GFromJSON arity a) =>
13301327 sname = selName (undefined :: M1 _i s _f _p)
13311328
13321329instance INCOHERENT_ (Selector s, FromJSON a) =>
1333− RecordFromJSON' arity (S1 s (K1 i (Maybe a))) where
1334− recordParseJSON' (_ :* _ :* opts :* _) obj = M1 . K1 <$> obj .:? pack label
1330+ RecordFromJSON arity (S1 s (K1 i (Maybe a))) where
1331+ recordParseJSON (_ :* _ :* opts :* _) obj = M1 . K1 <$> obj .:? pack label
13351332 where
13361333 label = fieldLabelModifier opts sname
13371334 sname = selName (undefined :: M1 _i s _f _p)
13381335
13391336-- Parse an Option like a Maybe.
13401337instance INCOHERENT_ (Selector s, FromJSON a) =>
1341− RecordFromJSON' arity (S1 s (K1 i (Semigroup.Option a))) where
1342− recordParseJSON' p obj = wrap <$> recordParseJSON' p obj
1338+ RecordFromJSON arity (S1 s (K1 i (Semigroup.Option a))) where
1339+ recordParseJSON p obj = wrap <$> recordParseJSON p obj
13431340 where
13441341 wrap :: S1 s (K1 i (Maybe a)) p -> S1 s (K1 i (Semigroup.Option a)) p
13451342 wrap (M1 (K1 a)) = M1 (K1 (Semigroup.Option a))
@@ -1576,22 +1573,12 @@ instance FromJSONKey Float where
15761573 _ -> Scientific.toRealFloat <$> parseScientificText t
15771574
15781575instance (FromJSON a, Integral a) => FromJSON (Ratio a) where
1579− parseJSON (Number x)
1580− | exp10 <= 1024
1581− , exp10 >= -1024 = return $! realToFrac x
1582− | otherwise = prependContext "Ratio" $ fail msg
1583− where
1584− exp10 = base10Exponent x
1585− msg = "found a number with exponent " ++ show exp10
1586− ++ ", but it must not be greater than 1024 or less than -1024"
1587− parseJSON o = objParser o
1588− where
1589− objParser = withObject "Rational" $ \obj -> do
1590− numerator <- obj .: "numerator"
1591− denominator <- obj .: "denominator"
1592− if denominator == 0
1593− then fail "Ratio denominator was 0"
1594− else pure $ numerator % denominator
1576+ parseJSON = withObject "Rational" $ \obj -> do
1577+ numerator <- obj .: "numerator"
1578+ denominator <- obj .: "denominator"
1579+ if denominator == 0
1580+ then fail "Ratio denominator was 0"
1581+ else pure $ numerator % denominator
15951582 {-# INLINE parseJSON #-}
15961583
15971584-- | This instance includes a bounds check to prevent maliciously
@@ -2006,6 +1993,7 @@ instance FromJSON DotNetTime where
20061993-- primitive
20071994-------------------------------------------------------------------------------
20081995
1996+#if MIN_VERSION_base(4,7,0)
20091997instance FromJSON a => FromJSON (PM.Array a) where
20101998 -- note: we could do better than this if vector exposed the data
20111999 -- constructor in Data.Vector.
@@ -2023,6 +2011,7 @@ instance (PM.PrimUnlifted a,FromJSON a) => FromJSON (PM.UnliftedArray a) where
20232011 parseJSON = fmap Exts.fromList . parseJSON
20242012#endif
20252013#endif
2014+#endif
20262015
20272016-------------------------------------------------------------------------------
20282017-- time