@@ -1,19 +1,31 @@
11{-# LANGUAGE DeriveDataTypeable #-}
22
3+-- Module: Data.Aeson.Types
4+-- Copyright: (c) 2011 MailRank, Inc.
5+-- License: Apache
6+-- Maintainer: Bryan O'Sullivan <bos@mailrank.com>
7+-- Stability: experimental
8+-- Portability: portable
9+--
10+-- Types for working with JSON data.
11+
312module Data.Aeson.Types
413 (
5− Array
14+ -- * Core JSON types
15+ Value(..)
16+ , Array
617 , Object
18+ -- * Type conversion
19+ , FromJSON(..)
20+ , ToJSON(..)
21+ -- * Constructors and accessors
722 , (.=)
823 , (.:)
924 , object
10− , Value(..)
11− , FromJSON(..)
12− , ToJSON(..)
1325 ) where
1426
1527import Control.Applicative
16−import Control.DeepSeq
28+import Control.DeepSeq (NFData(..))
1729import Data.Map (Map)
1830import Data.Text (Text, pack, unpack)
1931import Data.Time.Clock (UTCTime)
@@ -27,6 +39,7 @@ import qualified Data.Vector as V
2739type Object = Map Text Value
2840type Array = Vector Value
2941
42+-- | A JSON value represented as a Haskell value.
3043data Value = Object Object
3144 | Array Array
3245 | String Text
@@ -43,23 +56,57 @@ instance NFData Value where
4356 rnf (Bool b) = rnf b
4457 rnf Null = ()
4558
59+-- | Construct an 'Object' from a key and a value.
4660(.=) :: ToJSON a => Text -> a -> Object
4761name .= value = M.singleton name (toJSON value)
4862{-# INLINE (.=) #-}
4963
64+-- | Retrieve the value associated with the given key of an 'Object'.
65+-- The result is 'empty' if the key is not present or cannot be
66+-- converted to the desired type..
5067(.:) :: (Alternative f, FromJSON a) => Object -> Text -> f a
5168obj .: key = case M.lookup key obj of
5269 Nothing -> empty
5370 Just v -> fromJSON v
5471{-# INLINE (.:) #-}
5572
73+-- | Create a 'Value' from a list of 'Object's. If duplicate
74+-- keys arise, earlier keys and their associated values win.
5675object :: [Object] -> Value
5776object = Object . M.unions
5877{-# INLINE object #-}
5978
79+-- | A type that can be converted to JSON.
80+--
81+-- An example type and instance:
82+--
83+-- @data Coord { x :: Double, y :: Double }
84+--
85+-- instance ToJSON Coord where
86+-- toJSON (Coord x y) = 'object' [\"x\" '.=' x, \"y\" '.=' y]
87+-- @
6088class ToJSON a where
6189 toJSON :: a -> Value
6290
91+-- | A type that can be converted from JSON, with the possibility of
92+-- failure.
93+--
94+-- When writing an instance, use 'empty' to make a conversion fail,
95+-- e.g. if an 'Object' is missing a required key, or the value is of
96+-- the wrong type.
97+--
98+-- An example type and instance:
99+--
100+-- @data Coord { x :: Double, y :: Double }
101+--
102+-- instance FromJSON Coord where
103+-- fromJSON ('Object' v) = Coord '<$>'
104+-- v '.:' \"x\" '<*>'
105+-- v '.:' \"y\"
106+--
107+-- \-- A non-'Object' value is of the wrong type, so use 'empty' to fail.
108+-- fromJSON _ = 'empty'
109+-- @
63110class FromJSON a where
64111 fromJSON :: Alternative f => Value -> f a
65112
@@ -73,6 +120,15 @@ instance (FromJSON a) => FromJSON (Maybe a) where
73120 fromJSON a = Just <$> fromJSON a
74121 {-# INLINE fromJSON #-}
75122
123+instance (ToJSON a, ToJSON b) => ToJSON (Either a b) where
124+ toJSON (Left a) = toJSON a
125+ toJSON (Right b) = toJSON b
126+ {-# INLINE toJSON #-}
127+
128+instance (FromJSON a, FromJSON b) => FromJSON (Either a b) where
129+ fromJSON a = Left <$> fromJSON a <|> Right <$> fromJSON a
130+ {-# INLINE fromJSON #-}
131+
76132instance ToJSON Bool where
77133 toJSON = Bool
78134 {-# INLINE toJSON #-}
@@ -100,6 +156,15 @@ instance FromJSON Int where
100156 fromJSON _ = empty
101157 {-# INLINE fromJSON #-}
102158
159+instance ToJSON Integer where
160+ toJSON = Number . fromIntegral
161+ {-# INLINE toJSON #-}
162+
163+instance FromJSON Integer where
164+ fromJSON (Number n) = pure (floor n)
165+ fromJSON _ = empty
166+ {-# INLINE fromJSON #-}
167+
103168instance ToJSON Text where
104169 toJSON = String
105170 {-# INLINE toJSON #-}