on master help sign in
18 files changed+136−248
since splitsnapshots
unifiedsplit
.travis.yml+19−32 Data/Aeson.hs+3−3 Data/Aeson/Encoding/Builder.hs+1 Data/Aeson/Encoding/Internal.hs+1 Data/Aeson/Parser/Internal.hs+46−45 Data/Aeson/TH.hs+14−41 Data/Aeson/Text.hs+1 Data/Aeson/Types.hs−1 Data/Aeson/Types/FromJSON.hs+1 Data/Aeson/Types/Internal.hs+14−33 Data/Aeson/Types/ToJSON.hs+1 aeson.cabal+5−5 attoparsec-iso8601/Data/Attoparsec/Time/Internal.hs+18−3 attoparsec-iso8601/attoparsec-iso8601.cabal+4−5 changelog.md+2−61 tests/UnitTests.hs−8 travis/install.sh+3−8 travis/script.sh+3−3
.travis.yml+19−32
@@ -25,59 +25,46 @@ before_cache:
2525matrix:
2626 include:
2727
28− # Do the special build steps and handle the newest and oldest
29− # GHCs first, since these are the most likely to fail.
30−
31− # HLint
3228 - env: BUILD=hlint CABALVER=2.2 GHCVER=8.4.4
3329 compiler: ": #GHC 8.4.4"
3430 addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.4], sources: [hvr-ghc]}}
3531
36− # Latest GHC
37− - env: BUILD=cabal2 CABALVER=3.0 GHCVER=8.10.1
38− compiler: ": #GHC 8.10.1"
39− addons: {apt: {packages: [cabal-install-3.0,ghc-8.10.1], sources: [hvr-ghc]}}
40−
41− # Oldest GHC
42− - env: BUILD=cabal CABALVER=1.18 GHCVER=7.8.4
43− compiler: ": #GHC 7.8.4"
44− addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4], sources: [hvr-ghc]}}
45−
46− # Benchmarks
47− - env: BUILD=stack CABALVER=3.0 GHCVER=8.6.5 STACK_YAML=stack-bench.yaml
32+ - env: BUILD=stack CABALVER=2.4 GHCVER=8.6.5 STACK_YAML=stack-bench.yaml
4833 compiler: ": #GHC 8.6.5"
49− addons: {apt: {packages: [cabal-install-3.0,ghc-8.6.5], sources: [hvr-ghc]}}
34+ addons: {apt: {packages: [cabal-install-2.4,ghc-8.6.5], sources: [hvr-ghc]}}
5035
51− # C unescape implementation
52− - env: BUILD=stack CABALVER=3.0 GHCVER=8.6.5 STACK_YAML=stack-ffi-unescape.yaml
36+ - env: BUILD=stack CABALVER=2.2 GHCVER=8.6.5 STACK_YAML=stack-ffi-unescape.yaml
5337 compiler: ": #GHC 8.6.5"
54− addons: {apt: {packages: [cabal-install-3.0,ghc-8.6.5], sources: [hvr-ghc]}}
38+ addons: {apt: {packages: [cabal-install-2.2,ghc-8.6.5], sources: [hvr-ghc]}}
5539
40+ - env: BUILD=cabal2 CABALVER=3.0 GHCVER=8.8.1
41+ compiler: ": #GHC 8.8.1"
42+ addons: {apt: {packages: [cabal-install-3.0,ghc-8.8.1], sources: [hvr-ghc]}}
5643
57− - env: BUILD=cabal2 CABALVER=3.0 GHCVER=8.8.3
58− compiler: ": #GHC 8.8.3"
59− addons: {apt: {packages: [cabal-install-3.0,ghc-8.8.3], sources: [hvr-ghc]}}
60−
61− - env: BUILD=cabal2 CABALVER=3.0 GHCVER=8.6.5
44+ - env: BUILD=cabal CABALVER=2.4 GHCVER=8.6.5
6245 compiler: ": #GHC 8.6.5"
63− addons: {apt: {packages: [cabal-install-3.0,ghc-8.6.5], sources: [hvr-ghc]}}
46+ addons: {apt: {packages: [cabal-install-2.4,ghc-8.6.5], sources: [hvr-ghc]}}
6447
65− - env: BUILD=cabal2 CABALVER=3.0 GHCVER=8.4.4
48+ - env: BUILD=cabal CABALVER=2.2 GHCVER=8.4.4
6649 compiler: ": #GHC 8.4.4"
67− addons: {apt: {packages: [cabal-install-3.0,ghc-8.4.4], sources: [hvr-ghc]}}
50+ addons: {apt: {packages: [cabal-install-2.2,ghc-8.4.4], sources: [hvr-ghc]}}
6851
69− - env: BUILD=cabal2 CABALVER=3.0 GHCVER=8.2.2
52+ - env: BUILD=cabal CABALVER=2.0 GHCVER=8.2.2
7053 compiler: ": #GHC 8.2.2"
71− addons: {apt: {packages: [cabal-install-3.0,ghc-8.2.2], sources: [hvr-ghc]}}
54+ addons: {apt: {packages: [cabal-install-2.0,ghc-8.2.2], sources: [hvr-ghc]}}
7255
73− - env: BUILD=cabal2 CABALVER=3.0 GHCVER=8.0.2
56+ - env: BUILD=cabal CABALVER=2.0 GHCVER=8.0.2
7457 compiler: ": #GHC 8.0.2"
75− addons: {apt: {packages: [cabal-install-3.0,ghc-8.0.2], sources: [hvr-ghc]}}
58+ addons: {apt: {packages: [cabal-install-2.0,ghc-8.0.2], sources: [hvr-ghc]}}
7659
7760 - env: BUILD=cabal CABALVER=1.22 GHCVER=7.10.3
7861 compiler: ": #GHC 7.10.3"
7962 addons: {apt: {packages: [cabal-install-1.22,ghc-7.10.3], sources: [hvr-ghc]}}
8063
64+ - env: BUILD=cabal CABALVER=1.18 GHCVER=7.8.4
65+ compiler: ": #GHC 7.8.4"
66+ addons: {apt: {packages: [cabal-install-1.18,ghc-7.8.4], sources: [hvr-ghc]}}
67+
8168before_install:
8269 - unset CC
8370 - export PATH=$HOME/.local/bin:/opt/ghc/$GHCVER/bin:/opt/cabal/$CABALVER/bin:$PATH
Data/Aeson.hs+3−3
@@ -149,7 +149,7 @@ import Data.Aeson.Types.FromJSON (ifromJSON, parseIndexedJSON)
149149import Data.Aeson.Encoding (encodingToLazyByteString)
150150import Data.Aeson.Parser.Internal (decodeWith, decodeStrictWith, eitherDecodeWith, eitherDecodeStrictWith, jsonEOF, json, jsonEOF', json')
151151import Data.Aeson.Types
152−import Data.Aeson.Types.Internal (formatError)
152+import Data.Aeson.Types.Internal (JSONPath, formatError, (<?>))
153153import qualified Data.ByteString as B
154154import qualified Data.ByteString.Lazy as L
155155
@@ -257,7 +257,7 @@ eitherDecodeStrict =
257257-- | Like 'decodeFileStrict' but returns an error message when decoding fails.
258258eitherDecodeFileStrict :: (FromJSON a) => FilePath -> IO (Either String a)
259259eitherDecodeFileStrict =
260− fmap eitherDecodeStrict . B.readFile
260+ fmap (eitherFormatError . eitherDecodeStrictWith jsonEOF ifromJSON) . B.readFile
261261{-# INLINE eitherDecodeFileStrict #-}
262262
263263-- | Like 'decode'' but returns an error message when decoding fails.
@@ -274,7 +274,7 @@ eitherDecodeStrict' =
274274-- | Like 'decodeFileStrict'' but returns an error message when decoding fails.
275275eitherDecodeFileStrict' :: (FromJSON a) => FilePath -> IO (Either String a)
276276eitherDecodeFileStrict' =
277− fmap eitherDecodeStrict' . B.readFile
277+ fmap (eitherFormatError . eitherDecodeStrictWith jsonEOF' ifromJSON) . B.readFile
278278{-# INLINE eitherDecodeFileStrict' #-}
279279
280280-- $use
Data/Aeson/Encoding/Builder.hs+1
@@ -44,6 +44,7 @@ import Data.ByteString.Builder as B
4444import Data.ByteString.Builder.Prim as BP
4545import Data.ByteString.Builder.Scientific (scientificBuilder)
4646import Data.Char (chr, ord)
47+import Data.Semigroup ((<>))
4748import Data.Scientific (Scientific, base10Exponent, coefficient)
4849import Data.Text.Encoding (encodeUtf8BuilderEscaped)
4950import Data.Time (UTCTime(..))
Data/Aeson/Encoding/Internal.hs+1
@@ -63,6 +63,7 @@ import Data.Aeson.Types.Internal (Value)
6363import Data.ByteString.Builder (Builder, char7, toLazyByteString)
6464import Data.Int
6565import Data.Scientific (Scientific)
66+import Data.Semigroup (Semigroup ((<>)))
6667import Data.Text (Text)
6768import Data.Time (Day, LocalTime, TimeOfDay, UTCTime, ZonedTime)
6869import Data.Typeable (Typeable)
Data/Aeson/Parser/Internal.hs+46−45
@@ -2,9 +2,12 @@
22{-# LANGUAGE CPP #-}
33{-# LANGUAGE NoImplicitPrelude #-}
44{-# LANGUAGE OverloadedStrings #-}
5+#if MIN_VERSION_ghc_prim(0,3,1)
6+{-# LANGUAGE MagicHash #-}
7+#endif
58#if __GLASGOW_HASKELL__ <= 710 && __GLASGOW_HASKELL__ >= 706
69-- Work around a compiler bug
7−{-# OPTIONS_GHC -fsimpl-tick-factor=300 #-}
10+{-# OPTIONS_GHC -fsimpl-tick-factor=200 #-}
811#endif
912-- |
1013-- Module: Data.Aeson.Parser.Internal
@@ -55,10 +58,8 @@ import Data.Aeson.Types.Internal (IResult(..), JSONPath, Object, Result(..), Val
5558import Data.Attoparsec.ByteString.Char8 (Parser, char, decimal, endOfInput, isDigit_w8, signed, string)
5659import Data.Function (fix)
5760import Data.Functor.Compat (($>))
58−import Data.Bits (testBit)
5961import Data.Scientific (Scientific)
6062import Data.Text (Text)
61−import qualified Data.Text.Encoding as TE
6263import Data.Vector (Vector)
6364import qualified Data.Vector as Vector (empty, fromList, fromListN, reverse)
6465import qualified Data.Attoparsec.ByteString as A
@@ -66,13 +67,16 @@ import qualified Data.Attoparsec.Lazy as L
6667import qualified Data.ByteString as B
6768import qualified Data.ByteString.Unsafe as B
6869import qualified Data.ByteString.Lazy as L
69−import qualified Data.ByteString.Lazy as BSL
70−import qualified Data.ByteString.Lazy.Char8 as C
71−import qualified Data.ByteString.Builder as B
7270import qualified Data.HashMap.Strict as H
7371import qualified Data.Scientific as Sci
7472import Data.Aeson.Parser.Unescape (unescapeText)
7573
74+#if MIN_VERSION_ghc_prim(0,3,1)
75+import GHC.Base (Int#, (==#), isTrue#, word2Int#, orI#, andI#)
76+import GHC.Word (Word8(W8#))
77+import qualified Data.Text.Encoding as TE
78+#endif
79+
7680#define BACKSLASH 92
7781#define CLOSE_CURLY 125
7882#define CLOSE_SQUARE 93
@@ -319,20 +323,37 @@ jstring = A.word8 DOUBLE_QUOTE *> jstring_
319323-- | Parse a string without a leading quote.
320324jstring_ :: Parser Text
321325{-# INLINE jstring_ #-}
322−jstring_ = do
323− s <- A.takeWhile (\w -> w /= DOUBLE_QUOTE && w /= BACKSLASH && not (testBit w 7))
324− let txt = TE.decodeUtf8 s
325− w <- A.peekWord8
326− case w of
327− Nothing -> fail "string without end"
328− Just DOUBLE_QUOTE -> A.anyWord8 $> txt
329− _ -> jstringSlow s
330−
331−jstringSlow :: B.ByteString -> Parser Text
332−{-# INLINE jstringSlow #-}
333−jstringSlow s' = {-# SCC "jstringSlow" #-} do
326+jstring_ = {-# SCC "jstring_" #-} do
327+#if MIN_VERSION_ghc_prim(0,3,1)
328+ (s, S _ escaped) <- A.runScanner startState go <* A.anyWord8
329+ -- We escape only if there are
330+ -- non-ascii (over 7bit) characters or backslash present.
331+ --
332+ -- Note: if/when text will have fast ascii -> text conversion
333+ -- (e.g. uses utf8 encoding) we can have further speedup.
334+ if isTrue# escaped
335+ then case unescapeText s of
336+ Right r -> return r
337+ Left err -> fail $ show err
338+ else return (TE.decodeUtf8 s)
339+ where
340+ startState = S 0# 0#
341+ go (S skip escaped) (W8# c)
342+ | isTrue# skip = Just (S 0# escaped')
343+ | isTrue# (w ==# 34#) = Nothing -- double quote
344+ | otherwise = Just (S skip' escaped')
345+ where
346+ w = word2Int# c
347+ skip' = w ==# 92# -- backslash
348+ escaped' = escaped
349+ `orI#` (w `andI#` 0x80# ==# 0x80#) -- c >= 0x80
350+ `orI#` skip'
351+ `orI#` (w `andI#` 0x1f# ==# w) -- c < 0x20
352+
353+data S = S Int# Int#
354+#else
334355 s <- A.scan startState go <* A.anyWord8
335− case unescapeText (B.append s' s) of
356+ case unescapeText s of
336357 Right r -> return r
337358 Left err -> fail $ show err
338359 where
@@ -343,6 +364,7 @@ jstringSlow s' = {-# SCC "jstringSlow" #-} do
343364 | otherwise = let a' = c == backslash
344365 in Just a'
345366 where backslash = BACKSLASH
367+#endif
346368
347369decodeWith :: Parser Value -> (Value -> Result a) -> L.ByteString -> Maybe a
348370decodeWith p to s =
@@ -368,35 +390,14 @@ eitherDecodeWith p to s =
368390 L.Done _ v -> case to v of
369391 ISuccess a -> Right a
370392 IError path msg -> Left (path, msg)
371− L.Fail notparsed ctx msg -> Left ([], buildMsg notparsed ctx msg)
393+ L.Fail _ ctx msg -> Left ([], buildMsg ctx msg)
372394 where
373− buildMsg :: L.ByteString -> [String] -> String -> String
374− buildMsg notYetParsed [] msg = msg ++ formatErrorLine notYetParsed
375− buildMsg notYetParsed (expectation:_) msg =
376− msg ++ ". Expecting " ++ expectation ++ formatErrorLine notYetParsed
395+ buildMsg :: [String] -> String -> String
396+ buildMsg [] msg = msg
397+ buildMsg (expectation:_) msg =
398+ msg ++ ". Expecting " ++ expectation
377399{-# INLINE eitherDecodeWith #-}
378400
379−-- | Grab the first 100 bytes from the non parsed portion and
380−-- format to get nicer error messages
381−formatErrorLine :: L.ByteString -> String
382−formatErrorLine bs =
383− C.unpack .
384− -- if formatting results in empty ByteString just return that
385− -- otherwise construct the error message with the bytestring builder
386− (\bs' ->
387− if BSL.null bs'
388− then BSL.empty
389− else
390− B.toLazyByteString $
391− B.stringUtf8 " at '" <> B.lazyByteString bs' <> B.stringUtf8 "'"
392− ) .
393− -- if newline is present cut at that position
394− BSL.takeWhile (10 /=) .
395− -- remove spaces, CR's, tabs, backslashes and quotes characters
396− BSL.filter (`notElem` [9, 13, 32, 34, 47, 92]) .
397− -- take 100 bytes
398− BSL.take 100 $ bs
399−
400401eitherDecodeStrictWith :: Parser Value -> (Value -> IResult a) -> B.ByteString
401402 -> Either (JSONPath, String) a
402403eitherDecodeStrictWith p to s =
Data/Aeson/TH.hs+14−41
@@ -116,10 +116,7 @@ module Data.Aeson.TH
116116 , mkLiftParseJSON2
117117 ) where
118118
119−import Prelude.Compat hiding (fail)
120−
121−-- We don't have MonadFail Q, so we should use `fail` from real `Prelude`
122−import Prelude (fail)
119+import Prelude.Compat
123120
124121import Control.Applicative ((<|>))
125122import Data.Aeson (Object, (.:), FromJSON(..), FromJSON1(..), FromJSON2(..), ToJSON(..), ToJSON1(..), ToJSON2(..))
@@ -1307,8 +1304,9 @@ dispatchFunByType jc jf conName tvMap list ty = do
13071304 tyVarNames :: [Name]
13081305 tyVarNames = M.keys tvMap
13091306
1310− itf <- isInTypeFamilyApp tyVarNames tyCon tyArgs
1311− if any (`mentionsName` tyVarNames) lhsArgs || itf
1307+ itf <- isTyFamily tyCon
1308+ if any (`mentionsName` tyVarNames) lhsArgs
1309+ || itf && any (`mentionsName` tyVarNames) tyArgs
13121310 then outOfPlaceTyVarError jc conName
13131311 else if any (`mentionsName` tyVarNames) rhsArgs
13141312 then appsE $ varE (jsonFunValOrListName list jf $ toEnum numLastArgs)
@@ -1659,44 +1657,19 @@ isTyVar (VarT _) = True
16591657isTyVar (SigT t _) = isTyVar t
16601658isTyVar _ = False
16611659
1662−-- | Detect if a Name in a list of provided Names occurs as an argument to some
1663−-- type family. This makes an effort to exclude /oversaturated/ arguments to
1664−-- type families. For instance, if one declared the following type family:
1665−--
1666−-- @
1667−-- type family F a :: Type -> Type
1668−-- @
1669−--
1670−-- Then in the type @F a b@, we would consider @a@ to be an argument to @F@,
1671−-- but not @b@.
1672−isInTypeFamilyApp :: [Name] -> Type -> [Type] -> Q Bool
1673−isInTypeFamilyApp names tyFun tyArgs =
1674− case tyFun of
1675− ConT tcName -> go tcName
1676− _ -> return False
1677− where
1678− go :: Name -> Q Bool
1679− go tcName = do
1680− info <- reify tcName
1681− case info of
1660+-- | Is the given type a type family constructor (and not a data family constructor)?
1661+isTyFamily :: Type -> Q Bool
1662+isTyFamily (ConT n) = do
1663+ info <- reify n
1664+ return $ case info of
16821665#if MIN_VERSION_template_haskell(2,11,0)
1683− FamilyI (OpenTypeFamilyD (TypeFamilyHead _ bndrs _ _)) _
1684− -> withinFirstArgs bndrs
1685− FamilyI (ClosedTypeFamilyD (TypeFamilyHead _ bndrs _ _) _) _
1686− -> withinFirstArgs bndrs
1666+ FamilyI OpenTypeFamilyD{} _ -> True
16871667#else
1688− FamilyI (FamilyD TypeFam _ bndrs _) _
1689− -> withinFirstArgs bndrs
1690− FamilyI (ClosedTypeFamilyD _ bndrs _ _) _
1691− -> withinFirstArgs bndrs
1668+ FamilyI (FamilyD TypeFam _ _ _) _ -> True
16921669#endif
1693− _ -> return False
1694− where
1695− withinFirstArgs :: [a] -> Q Bool
1696− withinFirstArgs bndrs =
1697− let firstArgs = take (length bndrs) tyArgs
1698− argFVs = freeVariables firstArgs
1699− in return $ any (`elem` argFVs) names
1670+ FamilyI ClosedTypeFamilyD{} _ -> True
1671+ _ -> False
1672+isTyFamily _ = return False
17001673
17011674-- | Peel off a kind signature from a Type (if it has one).
17021675unSigT :: Type -> Type
Data/Aeson/Text.hs+1
@@ -26,6 +26,7 @@ import Prelude.Compat
2626
2727import Data.Aeson.Types (Value(..), ToJSON(..))
2828import Data.Aeson.Encoding (encodingToLazyByteString)
29+import Data.Semigroup ((<>))
2930import Data.Scientific (FPFormat(..), Scientific, base10Exponent)
3031import Data.Text.Lazy.Builder
3132import Data.Text.Lazy.Builder.Scientific (formatScientificBuilder)
Data/Aeson/Types.hs−1
@@ -35,7 +35,6 @@ module Data.Aeson.Types
3535 , parse
3636 , parseEither
3737 , parseMaybe
38− , parseFail
3938 , ToJSON(..)
4039 , KeyValue(..)
4140 , modifyFailure
Data/Aeson/Types/FromJSON.hs+1
@@ -96,6 +96,7 @@ import Data.Hashable (Hashable(..))
9696import Data.Int (Int16, Int32, Int64, Int8)
9797import Data.List.NonEmpty (NonEmpty(..))
9898import Data.Maybe (fromMaybe)
99+import Data.Semigroup ((<>))
99100import Data.Proxy (Proxy(..))
100101import Data.Ratio ((%), Ratio)
101102import Data.Scientific (Scientific, base10Exponent)
Data/Aeson/Types/Internal.hs+14−33
@@ -44,7 +44,6 @@ module Data.Aeson.Types.Internal
4444 , parse
4545 , parseEither
4646 , parseMaybe
47− , parseFail
4847 , modifyFailure
4948 , prependFailure
5049 , parserThrowError
@@ -95,6 +94,7 @@ import Data.HashMap.Strict (HashMap)
9594import Data.Hashable (Hashable(..))
9695import Data.List (intercalate)
9796import Data.Scientific (Scientific)
97+import Data.Semigroup (Semigroup((<>)))
9898import Data.String (IsString(..))
9999import Data.Text (Text, pack, unpack)
100100import Data.Time (UTCTime)
@@ -342,10 +342,6 @@ instance Monoid (Parser a) where
342342 mappend = (<>)
343343 {-# INLINE mappend #-}
344344
345−-- | Raise a parsing failure with some custom message.
346−parseFail :: String -> Parser a
347−parseFail = fail
348−
349345apP :: Parser (a -> b) -> Parser a -> Parser b
350346apP d e = do
351347 b <- d
@@ -425,9 +421,6 @@ instance TH.Lift Value where
425421 where a' = V.toList a
426422 lift (Object o) = [| Object (H.fromList . map (first pack) $ o') |]
427423 where o' = map (first unpack) . H.toList $ o
428−#if MIN_VERSION_template_haskell(2,16,0)
429− liftTyped = TH.unsafeTExpCoerce . TH.lift
430−#endif
431424
432425-- | The empty array.
433426emptyArray :: Value
@@ -588,53 +581,41 @@ data Options = Options
588581 -- the constructor tag. If 'False' the encoding will always
589582 -- follow the `sumEncoding`.
590583 , omitNothingFields :: Bool
591− -- ^ If 'True', record fields with a 'Nothing' value will be
592− -- omitted from the resulting object. If 'False', the resulting
584+ -- ^ If 'True' record fields with a 'Nothing' value will be
585+ -- omitted from the resulting object. If 'False' the resulting
593586 -- object will include those fields mapping to @null@.
594587 --
595− -- Note that this /does not/ affect parsing: 'Maybe' fields are
596− -- optional regardless of the value of 'omitNothingFields', subject
597− -- to the note below.
598− --
599588 -- === Note
600589 --
601590 -- Setting 'omitNothingFields' to 'True' only affects fields which are of
602− -- type 'Maybe' /uniformly/ in the 'ToJSON' instance.
603− -- In particular, if the type of a field is declared as a type variable, it
591+ -- type 'Maybe' /uniformly/ in the 'ToJSON' or 'FromJSON' instance. In
592+ -- particular, if the type of a field is declared as a type variable, it
604593 -- will not be omitted from the JSON object, unless the field is
605594 -- specialized upfront in the instance.
606595 --
607− -- The same holds for 'Maybe' fields being optional in the 'FromJSON' instance.
608− --
609596 -- ==== __Example__
610597 --
611598 -- The generic instance for the following type @Fruit@ depends on whether
612599 -- the instance head is @Fruit a@ or @Fruit (Maybe a)@.
613600 --
614601 -- @
615− -- data Fruit a = Fruit
602+ -- data Fruit a =
616603 -- { apples :: a -- A field whose type is a type variable.
617604 -- , oranges :: 'Maybe' Int
618− -- } deriving 'Generic'
605+ -- }
606+ --
607+ -- options :: 'Options'
608+ -- options = 'defaultOptions' { 'omitNothingFields' = 'True' }
619609 --
620610 -- -- apples required, oranges optional
621611 -- -- Even if 'Data.Aeson.fromJSON' is then specialized to (Fruit ('Maybe' a)).
622− -- instance 'Data.Aeson.FromJSON' a => 'Data.Aeson.FromJSON' (Fruit a)
612+ -- instance 'Data.Aeson.FromJSON' a => 'Data.Aeson.FromJSON' (Fruit a) where
613+ -- 'Data.Aeson.fromJSON' = 'Data.Aeson.genericFromJSON' options
623614 --
624615 -- -- apples optional, oranges optional
625616 -- -- In this instance, the field apples is uniformly of type ('Maybe' a).
626− -- instance 'Data.Aeson.FromJSON' a => 'Data.Aeson.FromJSON' (Fruit ('Maybe' a))
627− --
628− -- options :: 'Options'
629− -- options = 'defaultOptions' { 'omitNothingFields' = 'True' }
630− --
631− -- -- apples always present in the output, oranges is omitted if 'Nothing'
632− -- instance 'Data.Aeson.ToJSON' a => 'Data.Aeson.ToJSON' (Fruit a) where
633− -- 'Data.Aeson.toJSON' = 'Data.Aeson.genericToJSON' options
634− --
635− -- -- both apples and oranges are omitted if 'Nothing'
636− -- instance 'Data.Aeson.ToJSON' a => 'Data.Aeson.ToJSON' (Fruit ('Maybe' a)) where
637− -- 'Data.Aeson.toJSON' = 'Data.Aeson.genericToJSON' options
617+ -- instance 'Data.Aeson.FromJSON' a => 'Data.Aeson.FromJSON' (Fruit ('Maybe' a)) where
618+ -- 'Data.Aeson.fromJSON' = 'Data.Aeson.genericFromJSON' options
638619 -- @
639620 , sumEncoding :: SumEncoding
640621 -- ^ Specifies how to encode constructors of a sum datatype.
Data/Aeson/Types/ToJSON.hs+1
@@ -79,6 +79,7 @@ import Data.Functor.Sum (Sum(..))
7979import Data.Int (Int16, Int32, Int64, Int8)
8080import Data.List (intersperse)
8181import Data.List.NonEmpty (NonEmpty(..))
82+import Data.Semigroup ((<>))
8283import Data.Proxy (Proxy(..))
8384import Data.Ratio (Ratio, denominator, numerator)
8485import Data.Scientific (Scientific)
aeson.cabal+5−5
@@ -1,5 +1,5 @@
11name: aeson
2−version: 1.4.7.1
2+version: 1.4.6.0
33license: BSD3
44license-file: LICENSE
55category: Text, Web, JSON
@@ -106,8 +106,8 @@ library
106106 bytestring >= 0.10.4.0 && < 0.11,
107107 containers >= 0.5.5.1 && < 0.7,
108108 deepseq >= 1.3.0.0 && < 1.5,
109− ghc-prim >= 0.2 && < 0.7,
110− template-haskell >= 2.9.0.0 && < 2.17,
109+ ghc-prim >= 0.2 && < 0.6,
110+ template-haskell >= 2.9.0.0 && < 2.16,
111111 text >= 1.2.3.0 && < 1.3,
112112 time >= 1.4 && < 1.10
113113
@@ -116,8 +116,8 @@ library
116116
117117 -- Compat
118118 build-depends:
119− base-compat-batteries >= 0.10.0 && < 0.12,
120− time-compat >= 1.9.2.2 && < 1.10
119+ base-compat >= 0.9.1 && < 0.12,
120+ time-compat >= 1.9.2.2 && < 1.10
121121
122122 if !impl(ghc >= 8.6)
123123 build-depends:
attoparsec-iso8601/Data/Attoparsec/Time/Internal.hs+18−3
@@ -1,3 +1,4 @@
1+{-# LANGUAGE CPP #-}
12{-# LANGUAGE NoImplicitPrelude #-}
23-- |
34-- Module: Data.Aeson.Internal.Time
@@ -18,10 +19,24 @@ module Data.Attoparsec.Time.Internal
1819
1920import Prelude.Compat
2021
21−import Data.Fixed (Fixed(MkFixed), Pico)
2222import Data.Int (Int64)
23−import Data.Time (TimeOfDay(..))
24−import Data.Time.Clock.Compat
23+import Data.Time
24+import Unsafe.Coerce (unsafeCoerce)
25+
26+#if MIN_VERSION_time(1,6,0)
27+
28+import Data.Time.Clock (diffTimeToPicoseconds)
29+
30+#endif
31+
32+import Data.Fixed (Pico, Fixed(MkFixed))
33+
34+#if !MIN_VERSION_time(1,6,0)
35+
36+diffTimeToPicoseconds :: DiffTime -> Integer
37+diffTimeToPicoseconds = unsafeCoerce
38+
39+#endif
2540
2641toPico :: Integer -> Pico
2742toPico = MkFixed
attoparsec-iso8601/attoparsec-iso8601.cabal+4−5
@@ -35,12 +35,11 @@ library
3535 Data.Attoparsec.Time.Internal
3636 Data.Attoparsec.Time
3737 build-depends:
38− attoparsec >= 0.13.0.1 && < 0.14.0.0,
38+ attoparsec >= 0.13.0.1,
3939 base >= 4.7 && < 5,
40− base-compat-batteries >= 0.10.0 && < 0.12,
41− time-compat >= 1.9.2.2 && < 1.10,
42− text >= 1.1.1.0 && < 1.3.0.0,
43− time >= 1.1.1.4 && < 1.11
40+ base-compat >= 0.9.1 && < 0.12,
41+ text >= 1.1.1.0,
42+ time >= 1.1.1.4
4443
4544 if flag(fast)
4645 ghc-options: -O0
changelog.md+2−61
@@ -1,68 +1,9 @@
11For the latest version of this document, please see [https://github.com/bos/aeson/blob/master/changelog.md](https://github.com/bos/aeson/blob/master/changelog.md).
22
3−#### 1.4.7.1
4−
5−* GHC 8.10 compatibility, thanks to Ryan Scott.
6−
7−### 1.4.7.0
8−
9−Long overdue release (once again), so there's quite a bit of stuff
10−included even though it's a "minor" release. Big thanks to all the
11−contributors, the project would not exist without you!
12−
13−Special thanks to Oleg Grenrus and Xia Li-Yao for reviewing tons
14−of stuff.
15−
16−New stuff:
17−
18−* Add `rejectUnknownFields` to Options which rejects unknown fields on
19− deserialization. Useful to find errors during development, but
20− enabling this should be considered a breaking change as previously
21− accepted inputs may now be rejected. Thanks to rmanne.
22−
23−```
24−instance FromJSON Foo where
25− parseJSON = gParseJSON defaultOptions { rejectUnknownFields = True }
26−```
3+### upcoming
274
285* `FromJSON` instance of `Ratio a` now parses numbers in addtion to
29− standard `{numerator=..., denumerator=...}` encoding. Thanks to
30− Aleksey Khudyakov.
31−
32−* Add more information to parse errors, including a sample of the
33− surrounding text. Hopefully this will lead to less "Failed to read:
34− satisfy" confusion! Thanks to Sasha Bogicevic. We expect some
35− downstream test suites to break because of this, apologies in
36− advance. Hopefully you will like the improvement anyway :-)
37−
38−* Add `parseFail` to `Data.Aeson.Types`. `parseFail = fail` but
39− doesn't require users to know about `MonadFail`. Thanks to Colin
40− Woodbury.
41−
42−* Make Template Haskell type family detection smarter when deriving
43− `ToJSON1` instances, thanks to Ryan Scott.
44−
45−* Optimize string parsing for the common case of strings without
46− escapes, thanks to Yuras.
47−
48−
49−Misc:
50−
51−* Clean up compiler warnings and switch from base-compat to
52− base-compat-batteries. Thanks to Colin Woodbury & Oleg Grenrus.
53−
54−* Clarification & fixes to documentation regarding treatment of Maybe fields, thanks to Roman Cheplyaka.
55−
56−* Add documentation for internal development workflows. Thanks to Guru
57− Devanla.
58−
59−* Drop support for GHC < 7.8. We've chosen to support older GHCs as
60− long as it doesn't prevent us from adding new features, but now it
61− does! Thanks to Oleg Grenrus for the patch.
62−
63−* Allow generic-deriving 1.13 in test suite.
64−
65−* Some DRY fixes thanks to Mark Fajkus.
6+ standard `{numerator=..., denumerator=...}` encoding.
667
678### 1.4.6.0
689
tests/UnitTests.hs−8
@@ -5,7 +5,6 @@
55{-# LANGUAGE OverloadedStrings #-}
66{-# LANGUAGE ScopedTypeVariables #-}
77{-# LANGUAGE TemplateHaskell #-}
8−{-# LANGUAGE TypeFamilies #-}
98{-# LANGUAGE QuasiQuotes #-}
109
1110-- For Data.Aeson.Types.camelTo
@@ -748,11 +747,6 @@ bigNaturalKeyDecoding =
748747 (Left "Error in $['1e2000']: found a number with exponent 2000, but it must not be greater than 1024")
749748 ((eitherDecode :: L.ByteString -> Either String (HashMap Natural Value)) "{ \"1e2000\": null }")
750749
751−-- A regression test for: https://github.com/bos/aeson/issues/757
752−type family Fam757 :: * -> *
753−type instance Fam757 = Maybe
754−newtype Newtype757 a = MkNewtype757 (Fam757 a)
755−
756750deriveJSON defaultOptions{omitNothingFields=True} ''MyRecord
757751
758752deriveToJSON defaultOptions ''Foo
@@ -764,5 +758,3 @@ deriveJSON defaultOptions{rejectUnknownFields=True} ''UnknownFields
764758deriveJSON defaultOptions{rejectUnknownFields=True} ''UnknownFieldsTag
765759deriveJSON defaultOptions{tagSingleConstructors=True,rejectUnknownFields=True} ''UnknownFieldsUnaryTagged
766760deriveJSON defaultOptions{rejectUnknownFields=True} ''UnknownFieldsSum
767−
768−deriveToJSON1 defaultOptions ''Newtype757
travis/install.sh+3−8
@@ -50,14 +50,9 @@ case $BUILD in
5050 fi
5151 ;;
5252 cabal2)
53− cabal v2-update -v
53+ cabal v2-update -v
5454 sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
5555
56− cabal v2-build --only-dependencies --enable-tests --enable-benchmarks --dry
57− ;;
58− attoparsec-iso8601)
59− cd attoparsec-iso8601
60− cabal v2-update -v
61− sed -i 's/^jobs:/-- jobs:/' ${HOME}/.cabal/config
62− cabal v2-build --only-dependencies --enable-tests --enable-benchmarks --dry
56+ cabal v2-build --only-dependencies --enable-tests --enable-benchmarks --dry
57+ ;;
6358esac
travis/script.sh+3−3
@@ -19,9 +19,9 @@ case $BUILD in
1919 SRC_TGZ=$(cabal info . | awk '{print $2;exit}').tar.gz &&
2020 (cd dist && cabal install --force-reinstalls "$SRC_TGZ")
2121 ;;
22− cabal2)
23− cabal v2-build all --enable-tests --enable-benchmarks
24− cabal v2-test all --enable-tests --enable-benchmarks
22+ cabal2)
23+ cabal v2-build --enable-tests --enable-benchmarks
24+ cabal v2-test --enable-tests --enable-benchmarks
2525 ;;
2626 hlint)
2727 make lint