-
Notifications
You must be signed in to change notification settings - Fork 5
Expand file tree
/
Copy pathCodec.hs
More file actions
54 lines (44 loc) · 1.75 KB
/
Codec.hs
File metadata and controls
54 lines (44 loc) · 1.75 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
module Data.Aeson.Codec
(
-- * JSON codecs
JSONCodec
-- * JSON object codecs
, ObjectParser, ObjectBuilder, ObjectCodec
, entry, pair, obj
) where
import Control.Applicative
import Data.Aeson
import Data.Aeson.Types (Parser, Pair)
import Control.Monad.Reader
import Control.Monad.Writer
import Data.Default.Class
import qualified Data.Text as T
import Data.String
import Data.Codec
-- | JSON codec. This is just a `ToJSON`/`FromJSON` implementation wrapped up in newtypes.
-- Use `def` to get a `JSONCodec` for a `ToJSON`/`FromJSON` instance.
type JSONCodec a = ConcreteCodec Value Parser a
instance (ToJSON a, FromJSON a) => Default (JSONCodec a) where
def = Codec (ReaderT parseJSON) (Const . toJSON)
type ObjectParser = ReaderT Object Parser
type ObjectBuilder = Const (Endo [ Pair ])
-- | A codec that parses values out of a given `Object`, and produces
-- key-value pairs into a new one.
type ObjectCodec a = Codec ObjectParser ObjectBuilder a
-- | Produce a key-value pair.
pair :: ToJSON a => T.Text -> a -> ObjectBuilder b
pair key val = Const $ Endo ((key .= val):)
-- | Read\/write a given value from/to a given key in the current object, using a given sub-codec.
-- ObjectCodec's `IsString` instance is equal to `entry` `def`.
entry :: T.Text -> JSONCodec a -> ObjectCodec a
entry key cd = Codec
{ parse = ReaderT $ \o -> (o .: key) >>= parseVal cd
, produce = pair key . produceVal cd
}
-- | Turn an `ObjectCodec` into a `JSONCodec` with an expected name (see `withObject`).
obj :: String -> ObjectCodec a -> JSONCodec a
obj err (Codec r w) = concrete
(withObject err $ runReaderT r)
(\x -> object $ appEndo (getConst $ w x) [])
instance (ToJSON a, FromJSON a) => IsString (ObjectCodec a) where
fromString s = entry (fromString s) def