@@ -5,19 +5,16 @@
55{-# LANGUAGE FlexibleInstances #-}
66{-# LANGUAGE GADTs #-}
77{-# LANGUAGE MultiParamTypeClasses #-}
8−{-# LANGUAGE NamedFieldPuns #-}
98{-# LANGUAGE NoImplicitPrelude #-}
109{-# LANGUAGE OverloadedStrings #-}
10+{-# LANGUAGE PolyKinds #-}
1111{-# LANGUAGE RecordWildCards #-}
1212{-# LANGUAGE ScopedTypeVariables #-}
1313{-# LANGUAGE TypeOperators #-}
14+{-# LANGUAGE TupleSections #-}
1415{-# LANGUAGE UndecidableInstances #-}
1516{-# LANGUAGE ViewPatterns #-}
1617
17−#if __GLASGOW_HASKELL__ >= 706
18−{-# LANGUAGE PolyKinds #-}
19−#endif
20−
2118#include "incoherent-compat.h"
2219#include "overlapping-compat.h"
2320
@@ -45,6 +42,9 @@ module Data.Aeson.Types.FromJSON
4542 , coerceFromJSONKeyFunction
4643 , mapFromJSONKeyFunction
4744
45+ , GFromJSONKey()
46+ , genericFromJSONKey
47+
4848 -- * List functions
4949 , listParser
5050
@@ -118,9 +118,9 @@ import GHC.Generics
118118import Numeric.Natural (Natural)
119119import Text.ParserCombinators.ReadP (readP_to_S)
120120import Unsafe.Coerce (unsafeCoerce)
121−import qualified Data.Aeson.Compat as Compat
122121import qualified Data.Aeson.Parser.Time as Time
123122import qualified Data.Attoparsec.ByteString.Char8 as A (endOfInput, parseOnly, scientific)
123+import qualified Data.ByteString.Lazy as L
124124import qualified Data.DList as DList
125125import qualified Data.HashMap.Strict as H
126126import qualified Data.HashSet as HashSet
@@ -155,18 +155,8 @@ import qualified Data.Primitive.UnliftedArray as PM
155155import qualified Data.Primitive.PrimArray as PM
156156#endif
157157
158−#ifndef HAS_COERCIBLE
159−#define HAS_COERCIBLE (__GLASGOW_HASKELL__ >= 707)
160−#endif
161158
162−#if HAS_COERCIBLE
163159import Data.Coerce (Coercible, coerce)
164−coerce' :: Coercible a b => a -> b
165−coerce' = coerce
166−#else
167−coerce' :: a -> b
168−coerce' = unsafeCoerce
169−#endif
170160
171161parseIndexedJSON :: (Value -> Parser a) -> Int -> Value -> Parser a
172162parseIndexedJSON p idx value = p value <?> Index idx
@@ -406,6 +396,16 @@ class FromJSON a where
406396-- > newtype SomeId = SomeId { getSomeId :: Text }
407397-- > deriving (Eq,Ord,Hashable,FromJSONKey)
408398--
399+-- If you have a sum of nullary constructors, you may use the generic
400+-- implementation:
401+--
402+-- @
403+-- data Color = Red | Green | Blue
404+-- deriving Generic
405+--
406+-- instance 'FromJSONKey' Color where
407+-- 'fromJSONKey' = 'genericFromJSONKey' 'defaultJSONKeyOptions'
408+-- @
409409class FromJSONKey a where
410410 -- | Strategy for parsing the key of a map-like container.
411411 fromJSONKey :: FromJSONKeyFunction a
@@ -428,11 +428,7 @@ class FromJSONKey a where
428428-- At the moment this type is intentionally not exported. 'FromJSONKeyFunction'
429429-- can be inspected, but cannot be constructed.
430430data CoerceText a where
431−#if HAS_COERCIBLE
432431 CoerceText :: Coercible Text a => CoerceText a
433−#else
434− CoerceText :: CoerceText a
435−#endif
436432
437433-- | This type is related to 'ToJSONKeyFunction'. If 'FromJSONKeyValue' is used in the
438434-- 'FromJSONKey' instance, then 'ToJSONKeyValue' should be used in the 'ToJSONKey'
@@ -452,7 +448,7 @@ data FromJSONKeyFunction a
452448
453449-- | Only law abiding up to interpretation
454450instance Functor FromJSONKeyFunction where
455− fmap h (FromJSONKeyCoerce CoerceText) = FromJSONKeyText (h . coerce')
451+ fmap h (FromJSONKeyCoerce CoerceText) = FromJSONKeyText (h . coerce)
456452 fmap h (FromJSONKeyText f) = FromJSONKeyText (h . f)
457453 fmap h (FromJSONKeyTextParser f) = FromJSONKeyTextParser (fmap h . f)
458454 fmap h (FromJSONKeyValue f) = FromJSONKeyValue (fmap h . f)
@@ -466,9 +462,7 @@ instance Functor FromJSONKeyFunction where
466462--
467463-- On pre GHC 7.8 this is unconstrainted function.
468464fromJSONKeyCoerce ::
469−#if HAS_COERCIBLE
470465 Coercible Text a =>
471−#endif
472466 FromJSONKeyFunction a
473467fromJSONKeyCoerce = FromJSONKeyCoerce CoerceText
474468
@@ -476,34 +470,52 @@ fromJSONKeyCoerce = FromJSONKeyCoerce CoerceText
476470--
477471-- See note on 'fromJSONKeyCoerce'.
478472coerceFromJSONKeyFunction ::
479−#if HAS_COERCIBLE
480473 Coercible a b =>
481−#endif
482474 FromJSONKeyFunction a -> FromJSONKeyFunction b
483−#if HAS_COERCIBLE
484475coerceFromJSONKeyFunction = coerce
485−#else
486−coerceFromJSONKeyFunction (FromJSONKeyCoerce CoerceText) = FromJSONKeyCoerce CoerceText
487−coerceFromJSONKeyFunction (FromJSONKeyText f) = FromJSONKeyText (coerce' . f)
488−coerceFromJSONKeyFunction (FromJSONKeyTextParser f) = FromJSONKeyTextParser (fmap coerce' . f)
489−coerceFromJSONKeyFunction (FromJSONKeyValue f) = FromJSONKeyValue (fmap coerce' . f)
490−#endif
491476
492477{-# RULES
493478 "FromJSONKeyCoerce: fmap id" forall (x :: FromJSONKeyFunction a).
494479 fmap id x = x
495480 #-}
496−#if HAS_COERCIBLE
497481{-# RULES
498482 "FromJSONKeyCoerce: fmap coerce" forall x .
499483 fmap coerce x = coerceFromJSONKeyFunction x
500484 #-}
501−#endif
502485
503486-- | Same as 'fmap'. Provided for the consistency with 'ToJSONKeyFunction'.
504487mapFromJSONKeyFunction :: (a -> b) -> FromJSONKeyFunction a -> FromJSONKeyFunction b
505488mapFromJSONKeyFunction = fmap
506489
490+-- | 'fromJSONKey' for 'Generic' types.
491+-- These types must be sums of nullary constructors, whose names will be used
492+-- as keys for JSON objects.
493+--
494+-- See also 'genericToJSONKey'.
495+--
496+-- === __Example__
497+--
498+-- @
499+-- data Color = Red | Green | Blue
500+-- deriving 'Generic'
501+--
502+-- instance 'FromJSONKey' Color where
503+-- 'fromJSONKey' = 'genericFromJSONKey' 'defaultJSONKeyOptions'
504+-- @
505+genericFromJSONKey :: forall a. (Generic a, GFromJSONKey (Rep a))
506+ => JSONKeyOptions
507+ -> FromJSONKeyFunction a
508+genericFromJSONKey opts = FromJSONKeyTextParser $ \t ->
509+ case parseSumFromString (keyModifier opts) t of
510+ Nothing -> fail $
511+ "invalid key " ++ show t ++ ", expected one of " ++ show cnames
512+ Just k -> pure (to k)
513+ where
514+ cnames = unTagged2 (constructorTags (keyModifier opts) :: Tagged2 (Rep a) [String])
515+
516+class (ConstructorNames f, SumFromString f) => GFromJSONKey f where
517+instance (ConstructorNames f, SumFromString f) => GFromJSONKey f where
518+
507519-------------------------------------------------------------------------------
508520-- Functions needed for documentation
509521-------------------------------------------------------------------------------
@@ -664,7 +676,6 @@ instance (FromJSON a) => FromJSON [a] where
664676prependContext :: String -> Parser a -> Parser a
665677prependContext name = prependFailure ("parsing " ++ name ++ " failed, ")
666678
667−
668679-- | @'withObject' name f value@ applies @f@ to the 'Object' when @value@
669680-- is an 'Data.Aeson.Object' and fails otherwise.
670681--
@@ -757,13 +768,13 @@ withBoundedScientific' f v = withBoundedScientific_ id f v
757768-- | A variant of 'withBoundedScientific_' parameterized by a function to apply
758769-- to the 'Parser' in case of failure.
759770withBoundedScientific_ :: (Parser a -> Parser a) -> (Scientific -> Parser a) -> Value -> Parser a
760−withBoundedScientific_ whenFail f v@(Number scientific) =
761− if exponent > 1024
771+withBoundedScientific_ whenFail f (Number scientific) =
772+ if exp10 > 1024
762773 then whenFail (fail msg)
763774 else f scientific
764775 where
765− exponent = base10Exponent scientific
766− msg = "found a number with exponent " ++ show exponent ++ ", but it must not be greater than 1024"
776+ exp10 = base10Exponent scientific
777+ msg = "found a number with exponent " ++ show exp10 ++ ", but it must not be greater than 1024"
767778withBoundedScientific_ whenFail _ v =
768779 whenFail (typeMismatch "Number" v)
769780{-# INLINE withBoundedScientific_ #-}
@@ -783,7 +794,7 @@ withBool name _ v = prependContext name (typeMismatch "Boolean" v)
783794-- | Decode a nested JSON-encoded string.
784795withEmbeddedJSON :: String -> (Value -> Parser a) -> Value -> Parser a
785796withEmbeddedJSON _ innerParser (String txt) =
786− either fail innerParser $ eitherDecode (Compat.fromStrict $ T.encodeUtf8 txt)
797+ either fail innerParser $ eitherDecode (L.fromStrict $ T.encodeUtf8 txt)
787798 where
788799 eitherDecode = eitherFormatError . eitherDecodeWith jsonEOF ifromJSON
789800 eitherFormatError = either (Left . uncurry formatError) Right
@@ -852,7 +863,7 @@ parseFieldMaybe' = (.:!)
852863-- E.g. @'explicitParseField' 'parseJSON1' :: ('FromJSON1' f, 'FromJSON' a) -> 'Object' -> 'Text' -> 'Parser' (f a)@
853864explicitParseField :: (Value -> Parser a) -> Object -> Text -> Parser a
854865explicitParseField p obj key = case H.lookup key obj of
855− Nothing -> fail $ "key " ++ show key ++ " not present"
866+ Nothing -> fail $ "key " ++ show key ++ " not found"
856867 Just v -> p v <?> Key key
857868{-# INLINE explicitParseField #-}
858869
@@ -911,8 +922,6 @@ type ConName = String
911922contextType :: TypeName -> Parser a -> Parser a
912923contextType = prependContext
913924
914−
915−
916925-- | Add the tagKey that will be looked up while building an ADT
917926-- | Produce the error equivalent to
918927-- | Left "Error in $: parsing T failed, expected an object with keys "tag" and
@@ -920,9 +929,8 @@ contextType = prependContext
920929-- | The parser returned error was: could not find key "tag"
921930contextTag :: Text -> [String] -> Parser a -> Parser a
922931contextTag tagKey cnames = prependFailure
923− ("expected an object with key \"" ++ unpack tagKey ++
924− "\" where \"tag\" is associated to one of " ++ show cnames ++
925− ". The parser returned error was: ")
932+ ("expected Object with key \"" ++ unpack tagKey ++ "\"" ++
933+ " containing one of " ++ show cnames ++ ", ")
926934
927935-- | Add the name of the constructor being parsed to a parser's error messages.
928936contextCons :: ConName -> TypeName -> Parser a -> Parser a
@@ -1034,41 +1042,46 @@ parseAllNullarySum :: (SumFromString f, ConstructorNames f)
10341042parseAllNullarySum tname opts =
10351043 withText tname $ \tag ->
10361044 maybe (badTag tag) return $
1037− parseSumFromString opts tag
1045+ parseSumFromString modifier tag
10381046 where
1039− badTag tag = failWithCTags tname opts $ \cnames ->
1047+ badTag tag = failWithCTags tname modifier $ \cnames ->
10401048 "expected one of the tags " ++ show cnames ++
10411049 ", but found tag " ++ show tag
1050+ modifier = constructorTagModifier opts
10421051
10431052-- | Fail with an informative error message about a mismatched tag.
10441053-- The error message is parameterized by the list of expected tags,
10451054-- to be inferred from the result type of the parser.
10461055failWithCTags
1047− :: forall f a. ConstructorNames f
1048− => TypeName -> Options -> ([String] -> String) -> Parser (f a)
1049−failWithCTags tname opts f =
1056+ :: forall f a t. ConstructorNames f
1057+ => TypeName -> (String -> t) -> ([t] -> String) -> Parser (f a)
1058+failWithCTags tname modifier f =
10501059 contextType tname . fail $ f cnames
10511060 where
1052− cnames = unTagged2 (constructorTags opts :: Tagged2 f [String])
1061+ cnames = unTagged2 (constructorTags modifier :: Tagged2 f [t])
10531062
10541063class SumFromString f where
1055− parseSumFromString :: Options -> Text -> Maybe (f a)
1064+ parseSumFromString :: (String -> String) -> Text -> Maybe (f a)
10561065
10571066instance (SumFromString a, SumFromString b) => SumFromString (a :+: b) where
10581067 parseSumFromString opts key = (L1 <$> parseSumFromString opts key) <|>
10591068 (R1 <$> parseSumFromString opts key)
10601069
10611070instance (Constructor c) => SumFromString (C1 c U1) where
1062− parseSumFromString opts key | key == name = Just $ M1 U1
1063− | otherwise = Nothing
1064− where
1065− name = pack $ constructorTagModifier opts $
1066− conName (undefined :: M1 _i c _f _p)
1071+ parseSumFromString modifier key
1072+ | key == name = Just $ M1 U1
1073+ | otherwise = Nothing
1074+ where
1075+ name = pack $ modifier $ conName (undefined :: M1 _i c _f _p)
1076+
1077+-- For genericFromJSONKey
1078+instance SumFromString a => SumFromString (D1 d a) where
1079+ parseSumFromString modifier key = M1 <$> parseSumFromString modifier key
10671080
10681081-- | List of all constructor tags.
1069−constructorTags :: ConstructorNames a => Options -> Tagged2 a [String]
1070−constructorTags opts =
1071− fmap DList.toList (constructorNames' (constructorTagModifier opts))
1082+constructorTags :: ConstructorNames a => (String -> t) -> Tagged2 a [t]
1083+constructorTags modifier =
1084+ fmap DList.toList (constructorNames' modifier)
10721085
10731086-- | List of all constructor names of an ADT, after a given conversion
10741087-- function. (Better inlining.)
@@ -1089,6 +1102,12 @@ instance Constructor c => ConstructorNames (C1 c a) where
10891102 where
10901103 cname = conName (undefined :: M1 _i c _f _p)
10911104
1105+-- For genericFromJSONKey
1106+instance ConstructorNames a => ConstructorNames (D1 d a) where
1107+ constructorNames' = retag . constructorNames'
1108+ where
1109+ retag :: Tagged2 a u -> Tagged2 (D1 d a) u
1110+ retag (Tagged2 x) = Tagged2 x
10921111
10931112--------------------------------------------------------------------------------
10941113parseNonAllNullarySum :: forall f c arity.
@@ -1102,17 +1121,15 @@ parseNonAllNullarySum p@(tname :* opts :* _) =
11021121 case sumEncoding opts of
11031122 TaggedObject{..} ->
11041123 withObject tname $ \obj -> do
1105− tag <- (contextType tname) . (contextTag tagKey cnames_) $ obj .: tagKey
1124+ tag <- contextType tname . contextTag tagKey cnames_ $ obj .: tagKey
11061125 fromMaybe (badTag tag <?> Key tagKey) $
1107− parseFromTaggedObject (tag :* contentsFieldName :* p) obj
1126+ parseFromTaggedObject (tag :* contentsFieldName :* p) obj
11081127 where
11091128 tagKey = pack tagFieldName
11101129 badTag tag = failWith_ $ \cnames ->
11111130 "expected tag field to be one of " ++ show cnames ++
11121131 ", but found tag " ++ show tag
1113− cnames_ = unTagged2 (constructorTags opts :: Tagged2 f [String])
1114− --cname_ = conName (undefined :: M1 _i c _f _p)
1115− -- forall f a. ConstructorNames f
1132+ cnames_ = unTagged2 (constructorTags (constructorTagModifier opts) :: Tagged2 f [String])
11161133
11171134 ObjectWithSingleField ->
11181135 withObject tname $ \obj -> case H.toList obj of
@@ -1144,7 +1161,7 @@ parseNonAllNullarySum p@(tname :* opts :* _) =
11441161
11451162 UntaggedValue -> parseUntaggedValue p
11461163 where
1147− failWith_ = failWithCTags tname opts
1164+ failWith_ = failWithCTags tname (constructorTagModifier opts)
11481165
11491166--------------------------------------------------------------------------------
11501167
@@ -1184,9 +1201,9 @@ class FromTaggedObject' arity f isRecord where
11841201 :: String :* ConName :* TypeName :* Options :* FromArgs arity a
11851202 -> Object -> Tagged isRecord (Parser (f a))
11861203
1187−instance (RecordFromJSON arity f) => FromTaggedObject' arity f True where
1204+instance (RecordFromJSON arity f, FieldNames f) => FromTaggedObject' arity f True where
11881205 -- Records are unpacked in the tagged object
1189− parseFromTaggedObject' (_ :* p) = Tagged . recordParseJSON p
1206+ parseFromTaggedObject' (_ :* p) = Tagged . recordParseJSON (True :* p)
11901207
11911208instance (ConsFromJSON arity f) => FromTaggedObject' arity f False where
11921209 -- Nonnullary nonrecords are encoded in the contents field
@@ -1227,11 +1244,11 @@ instance OVERLAPPING_
12271244 ) => ConsFromJSON' arity (S1 s a) True where
12281245 consParseJSON' p@(cname :* tname :* opts :* fargs)
12291246 | unwrapUnaryRecords opts = Tagged . fmap M1 . gParseJSON opts fargs
1230− | otherwise = Tagged . withObject (showCons cname tname) (recordParseJSON p)
1247+ | otherwise = Tagged . withObject (showCons cname tname) (recordParseJSON (False :* p))
12311248
12321249instance RecordFromJSON arity f => ConsFromJSON' arity f True where
12331250 consParseJSON' p@(cname :* tname :* _) =
1234− Tagged . withObject (showCons cname tname) (recordParseJSON p)
1251+ Tagged . withObject (showCons cname tname) (recordParseJSON (False :* p))
12351252
12361253instance OVERLAPPING_
12371254 ConsFromJSON' arity U1 False where
@@ -1257,21 +1274,55 @@ instance (ProductFromJSON arity f, ProductSize f
12571274
12581275--------------------------------------------------------------------------------
12591276
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+
12601288class RecordFromJSON arity f where
12611289 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'
12621313 :: ConName :* TypeName :* Options :* FromArgs arity a
12631314 -> Object -> Parser (f a)
12641315
1265−instance ( RecordFromJSON arity a
1266− , RecordFromJSON arity b
1267− ) => RecordFromJSON arity (a :*: b) where
1268− recordParseJSON p obj =
1269− (:*:) <$> recordParseJSON p obj
1270− <*> recordParseJSON p obj
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
12711322
12721323instance OVERLAPPABLE_ (Selector s, GFromJSON arity a) =>
1273− RecordFromJSON arity (S1 s a) where
1274− recordParseJSON (cname :* tname :* opts :* fargs) obj = do
1324+ RecordFromJSON' arity (S1 s a) where
1325+ recordParseJSON' (cname :* tname :* opts :* fargs) obj = do
12751326 fv <- contextCons cname tname (obj .: label)
12761327 M1 <$> gParseJSON opts fargs fv <?> Key label
12771328 where
@@ -1279,16 +1330,16 @@ instance OVERLAPPABLE_ (Selector s, GFromJSON arity a) =>
12791330 sname = selName (undefined :: M1 _i s _f _p)
12801331
12811332instance INCOHERENT_ (Selector s, FromJSON a) =>
1282− RecordFromJSON arity (S1 s (K1 i (Maybe a))) where
1283− recordParseJSON (_ :* _ :* opts :* _) obj = M1 . K1 <$> obj .:? pack label
1333+ RecordFromJSON' arity (S1 s (K1 i (Maybe a))) where
1334+ recordParseJSON' (_ :* _ :* opts :* _) obj = M1 . K1 <$> obj .:? pack label
12841335 where
12851336 label = fieldLabelModifier opts sname
12861337 sname = selName (undefined :: M1 _i s _f _p)
12871338
12881339-- Parse an Option like a Maybe.
12891340instance INCOHERENT_ (Selector s, FromJSON a) =>
1290− RecordFromJSON arity (S1 s (K1 i (Semigroup.Option a))) where
1291− recordParseJSON p obj = wrap <$> recordParseJSON p obj
1341+ RecordFromJSON' arity (S1 s (K1 i (Semigroup.Option a))) where
1342+ recordParseJSON' p obj = wrap <$> recordParseJSON' p obj
12921343 where
12931344 wrap :: S1 s (K1 i (Maybe a)) p -> S1 s (K1 i (Semigroup.Option a)) p
12941345 wrap (M1 (K1 a)) = M1 (K1 (Semigroup.Option a))
@@ -1525,12 +1576,22 @@ instance FromJSONKey Float where
15251576 _ -> Scientific.toRealFloat <$> parseScientificText t
15261577
15271578instance (FromJSON a, Integral a) => FromJSON (Ratio a) where
1528− parseJSON = withObject "Rational" $ \obj -> do
1529− numerator <- obj .: "numerator"
1530− denominator <- obj .: "denominator"
1531− if denominator == 0
1532− then fail "Ratio denominator was 0"
1533− else pure $ numerator % denominator
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
15341595 {-# INLINE parseJSON #-}
15351596
15361597-- | This instance includes a bounds check to prevent maliciously
@@ -1945,7 +2006,6 @@ instance FromJSON DotNetTime where
19452006-- primitive
19462007-------------------------------------------------------------------------------
19472008
1948−#if MIN_VERSION_base(4,7,0)
19492009instance FromJSON a => FromJSON (PM.Array a) where
19502010 -- note: we could do better than this if vector exposed the data
19512011 -- constructor in Data.Vector.
@@ -1963,7 +2023,6 @@ instance (PM.PrimUnlifted a,FromJSON a) => FromJSON (PM.UnliftedArray a) where
19632023 parseJSON = fmap Exts.fromList . parseJSON
19642024#endif
19652025#endif
1966−#endif
19672026
19682027-------------------------------------------------------------------------------
19692028-- time