@@ -1,19 +1,31 @@
1{-# LANGUAGE DeriveDataTypeable #-}
1{-# LANGUAGE DeriveDataTypeable #-}
3+-- Module: Data.Aeson.Types
4+-- Copyright: (c) 2011 MailRank, Inc.
6+-- Maintainer: Bryan O'Sullivan <bos@mailrank.com>
7+-- Stability: experimental
8+-- Portability: portable
10+-- Types for working with JSON data.
3module Data.Aeson.Types
12module Data.Aeson.Types
21+ -- * Constructors and accessors
15import Control.Applicative
27import Control.Applicative
16−import Control.DeepSeq
28+import Control.DeepSeq (NFData(..))
17import Data.Map (Map)
29import Data.Map (Map)
18import Data.Text (Text, pack, unpack)
30import Data.Text (Text, pack, unpack)
19import Data.Time.Clock (UTCTime)
31import Data.Time.Clock (UTCTime)
@@ -27,6 +39,7 @@ import qualified Data.Vector as V
27type Object = Map Text Value
39type Object = Map Text Value
28type Array = Vector Value
40type Array = Vector Value
42+-- | A JSON value represented as a Haskell value.
30data Value = Object Object
43data Value = Object Object
31 | Array Array
44 | Array Array
32 | String Text
45 | String Text
@@ -43,23 +56,57 @@ instance NFData Value where
43 rnf (Bool b) = rnf b
56 rnf (Bool b) = rnf b
44 rnf Null = ()
57 rnf Null = ()
59+-- | Construct an 'Object' from a key and a value.
46(.=) :: ToJSON a => Text -> a -> Object
60(.=) :: ToJSON a => Text -> a -> Object
47name .= value = M.singleton name (toJSON value)
61name .= value = M.singleton name (toJSON value)
48{-# INLINE (.=) #-}
62{-# INLINE (.=) #-}
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..
50(.:) :: (Alternative f, FromJSON a) => Object -> Text -> f a
67(.:) :: (Alternative f, FromJSON a) => Object -> Text -> f a
51obj .: key = case M.lookup key obj of
68obj .: key = case M.lookup key obj of
52 Nothing -> empty
69 Nothing -> empty
53 Just v -> fromJSON v
70 Just v -> fromJSON v
54{-# INLINE (.:) #-}
71{-# INLINE (.:) #-}
73+-- | Create a 'Value' from a list of 'Object's. If duplicate
74+-- keys arise, earlier keys and their associated values win.
56object :: [Object] -> Value
75object :: [Object] -> Value
57object = Object . M.unions
76object = Object . M.unions
58{-# INLINE object #-}
77{-# INLINE object #-}
79+-- | A type that can be converted to JSON.
81+-- An example type and instance:
83+-- @data Coord { x :: Double, y :: Double }
85+-- instance ToJSON Coord where
86+-- toJSON (Coord x y) = 'object' [\"x\" '.=' x, \"y\" '.=' y]
60class ToJSON a where
88class ToJSON a where
61 toJSON :: a -> Value
89 toJSON :: a -> Value
91+-- | A type that can be converted from JSON, with the possibility of
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
98+-- An example type and instance:
100+-- @data Coord { x :: Double, y :: Double }
102+-- instance FromJSON Coord where
103+-- fromJSON ('Object' v) = Coord '<$>'
104+-- v '.:' \"x\" '<*>'
107+-- \-- A non-'Object' value is of the wrong type, so use 'empty' to fail.
108+-- fromJSON _ = 'empty'
63class FromJSON a where
110class FromJSON a where
64 fromJSON :: Alternative f => Value -> f a
111 fromJSON :: Alternative f => Value -> f a
@@ -73,6 +120,15 @@ instance (FromJSON a) => FromJSON (Maybe a) where
73 fromJSON a = Just <$> fromJSON a
120 fromJSON a = Just <$> fromJSON a
74 {-# INLINE fromJSON #-}
121 {-# INLINE fromJSON #-}
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 #-}
128+instance (FromJSON a, FromJSON b) => FromJSON (Either a b) where
129+ fromJSON a = Left <$> fromJSON a <|> Right <$> fromJSON a
130+ {-# INLINE fromJSON #-}
76instance ToJSON Bool where
132instance ToJSON Bool where
77 toJSON = Bool
133 toJSON = Bool
78 {-# INLINE toJSON #-}
134 {-# INLINE toJSON #-}
@@ -100,6 +156,15 @@ instance FromJSON Int where
100 fromJSON _ = empty
156 fromJSON _ = empty
101 {-# INLINE fromJSON #-}
157 {-# INLINE fromJSON #-}
159+instance ToJSON Integer where
160+ toJSON = Number . fromIntegral
161+ {-# INLINE toJSON #-}
163+instance FromJSON Integer where
164+ fromJSON (Number n) = pure (floor n)
166+ {-# INLINE fromJSON #-}
103instance ToJSON Text where
168instance ToJSON Text where
104 toJSON = String
169 toJSON = String
105 {-# INLINE toJSON #-}
170 {-# INLINE toJSON #-}