on master help sign in
Add NonEmpty instances
66bbc19Oleg Grenrus
Data/Aeson/Types/Instances.hs+15
@@ -71,6 +71,7 @@ import Data.Foldable (toList)
71import Data.Functor.Identity (Identity(..))
71import Data.Functor.Identity (Identity(..))
72import Data.Hashable (Hashable(..))
72import Data.Hashable (Hashable(..))
73import Data.Int (Int8, Int16, Int32, Int64)
73import Data.Int (Int8, Int16, Int32, Int64)
74+import Data.List.NonEmpty (NonEmpty(..))
74import Data.Maybe (fromMaybe)
75import Data.Maybe (fromMaybe)
75import Data.Monoid ((<>))
76import Data.Monoid ((<>))
76import Data.Monoid (Dual(..), First(..), Last(..))
77import Data.Monoid (Dual(..), First(..), Last(..))
@@ -491,6 +492,20 @@ instance FromJSON LT.Text where
491 parseJSON = withText "Lazy Text" $ pure . LT.fromStrict
492 parseJSON = withText "Lazy Text" $ pure . LT.fromStrict
492 {-# INLINE parseJSON #-}
493 {-# INLINE parseJSON #-}
493
494
495+instance (ToJSON a) => ToJSON (NonEmpty a) where
496+ toJSON = toJSON . toList
497+ {-# INLINE toJSON #-}
498+
499+ toEncoding = toEncoding . toList
500+ {-# INLINE toEncoding #-}
501+
502+instance (FromJSON a) => FromJSON (NonEmpty a) where
503+ parseJSON = withArray "NonEmpty a" $
504+ (>>= ne) . Tr.sequence . zipWith parseIndexedJSON [0..] . V.toList
505+ where
506+ ne [] = fail "Expected a NonEmpty but got an empty list"
507+ ne (x:xs) = pure (x :| xs)
508+
494instance OVERLAPPABLE_ (ToJSON a) => ToJSON [a] where
509instance OVERLAPPABLE_ (ToJSON a) => ToJSON [a] where
495 toJSON = Array . V.fromList . map toJSON
510 toJSON = Array . V.fromList . map toJSON
496 {-# INLINE toJSON #-}
511 {-# INLINE toJSON #-}
aeson.cabal+4−1
@@ -145,7 +145,7 @@ test-suite tests
145
145
146 build-depends:
146 build-depends:
147 HUnit,
147 HUnit,
148− QuickCheck >= 2.7,
148+ QuickCheck >= 2.7 && <2.8.3,
149 aeson,
149 aeson,
150 attoparsec,
150 attoparsec,
151 base,
151 base,
@@ -162,6 +162,9 @@ test-suite tests
162 vector,
162 vector,
163 quickcheck-instances >=0.3.12
163 quickcheck-instances >=0.3.12
164
164
165+ if !impl(ghc >= 8.0)
166+ build-depends: semigroups >= 0.16.1
167+
165 if flag(old-locale)
168 if flag(old-locale)
166 build-depends: time < 1.5, old-locale
169 build-depends: time < 1.5, old-locale
167 else
170 else
tests/Instances.hs+4
@@ -14,6 +14,7 @@ import Test.QuickCheck (Arbitrary(..), getNonNegative, elements,
14 listOf1, oneof, resize)
14 listOf1, oneof, resize)
15import Data.Time.Clock (UTCTime(..))
15import Data.Time.Clock (UTCTime(..))
16import Data.Time (ZonedTime(..), TimeZone(..))
16import Data.Time (ZonedTime(..), TimeZone(..))
17+import Data.List.NonEmpty (NonEmpty(..))
17import Data.Version
18import Data.Version
18import Data.Aeson.Types
19import Data.Aeson.Types
19import Control.Applicative
20import Control.Applicative
@@ -136,6 +137,9 @@ instance (ApproxEq a) => ApproxEq [a] where
136instance Arbitrary Version where
137instance Arbitrary Version where
137 arbitrary = makeVersion . fmap getNonNegative <$> resize 4 (listOf1 arbitrary)
138 arbitrary = makeVersion . fmap getNonNegative <$> resize 4 (listOf1 arbitrary)
138
139
140+instance Arbitrary a => Arbitrary (NonEmpty a) where
141+ arbitrary = (:|) <$> arbitrary <*> arbitrary
142+
139-- Version tags are deprecated, so we avoid using them in the Arbitrary
143-- Version tags are deprecated, so we avoid using them in the Arbitrary
140-- instance. However, the recommended constructor 'makeVersion' is not
144-- instance. However, the recommended constructor 'makeVersion' is not
141-- exported by "Data.Version" until base-4.8.0.0. For previous versions,
145-- exported by "Data.Version" until base-4.8.0.0. For previous versions,
tests/Properties.hs+2
@@ -9,6 +9,7 @@ import Data.Aeson.Parser (value)
9import Data.Aeson.Types
9import Data.Aeson.Types
10import Data.ByteString.Builder (toLazyByteString)
10import Data.ByteString.Builder (toLazyByteString)
11import Data.Int (Int8)
11import Data.Int (Int8)
12+import Data.List.NonEmpty (NonEmpty)
12import Data.Time (Day, LocalTime, NominalDiffTime, TimeOfDay, UTCTime,
13import Data.Time (Day, LocalTime, NominalDiffTime, TimeOfDay, UTCTime,
13 ZonedTime)
14 ZonedTime)
14import Data.Version (Version)
15import Data.Version (Version)
@@ -127,6 +128,7 @@ tests = testGroup "properties" [
127 testProperty "Bool" $ roundTripEq True
128 testProperty "Bool" $ roundTripEq True
128 , testProperty "Double" $ roundTripEq (1 :: Approx Double)
129 , testProperty "Double" $ roundTripEq (1 :: Approx Double)
129 , testProperty "Int" $ roundTripEq (1 :: Int)
130 , testProperty "Int" $ roundTripEq (1 :: Int)
131+ , testProperty "NonEmpty Char" $ roundTripEq (undefined :: NonEmpty Char)
130 , testProperty "Integer" $ roundTripEq (1 :: Integer)
132 , testProperty "Integer" $ roundTripEq (1 :: Integer)
131 , testProperty "String" $ roundTripEq ("" :: String)
133 , testProperty "String" $ roundTripEq ("" :: String)
132 , testProperty "Text" $ roundTripEq T.empty
134 , testProperty "Text" $ roundTripEq T.empty