The codec package

This is a package candidate release! Here you can preview how this package release will appear once published to the main package index (which can be accomplished via the 'maintain' link below). Please note that once a package has been published to the main package index it cannot be undone! Please consult the package uploading documentation for more information.

[maintain]

See the README


[Skip to ReadMe]

Properties

Versions0.1, 0.1.1, 0.2, 0.2.1, 0.2.1
Change logNone available
Dependenciesaeson (>=1.0.0.0), base (>=4.6 && <6), binary, binary-bits, bytestring, mtl, profunctors, template-haskell, text, transformers, unordered-containers, vector [details]
LicenseBSD3
AuthorPatrick Chilton
Maintainerchpatrick@gmail.com
CategoryData
Home pagehttps://github.com/chpatrick/codec
Source repositoryhead: git clone https://github.com/chpatrick/codec.git
UploadedFri Apr 21 18:27:59 UTC 2017 by PatrickChilton

Modules

[Index]

Downloads

Maintainers' corner

For package maintainers and hackage trustees

Readme for codec-0.2.1

Codec Build Status Hackage

Codec makes it simple to write composable bidirectional serializers with a consistent interface.

Just define your data type normally:

data RecordB = RecordB
  { recordBString :: String
  , recordBDouble :: Double
  } deriving (Eq, Ord, Show)

and then associate each field with a codec using the =. operator:

recordBObjCodec :: JSONCodec RecordB
recordBObjCodec = asObject "RecordB" $
  RecordB
    <$> recordBString =. field "string"
    <*> recordBDouble =. field "double"

That's it! If you want, you can now define ToJSON and FromJSON instances, or just use it directly:

instance ToJSON RecordB where
  toJSON = toJSONCodec recordBObjCodec
  toEncoding = toEncodingCodec recordBObjCodec

instance FromJSON RecordB where
  parseJSON = parseJSONCodec recordBObjCodec

Support can be added for almost any serialization library, but aeson and binary support is included.

JSON example:

data RecordA = RecordA
  { recordAInt :: Int
  , recordANestedObj :: RecordB
  , recordANestedArr :: RecordB
  , recordANestedObjs :: [ RecordB ]
  } deriving (Eq, Ord, Show)

data RecordB = RecordB
  { recordBString :: String
  , recordBDouble :: Double
  } deriving (Eq, Ord, Show)

recordACodec :: JSONCodec RecordA
recordACodec = asObject "RecordA" $
  RecordA
    <$> recordAInt =. field "int"
    <*> recordANestedObj =. field' "nestedObj" recordBObjCodec
    <*> recordANestedArr =. field' "nestedArr" recordBArrCodec
    <*> recordANestedObjs =. field' "nestedObjs" (arrayOf' id id recordBObjCodec)

recordBObjCodec :: JSONCodec RecordB
recordBObjCodec = asObject "RecordB" $
  RecordB
    <$> recordBString =. field "string"
    <*> recordBDouble =. field "double"

-- serialize to array elements
recordBArrCodec :: JSONCodec RecordB
recordBArrCodec = asArray "RecordB" $
  RecordB
    <$> recordBString =. element
    <*> recordBDouble =. element

Binary example:

data RecordA = RecordA
  { recordAInt64 :: Int64
  , recordAWord8 :: Word8
  , recordANestedB :: RecordB
  } deriving (Eq, Ord, Show)

data RecordB = RecordB
  { recordBWord16 :: Word16
  , recordBByteString64 :: BS.ByteString
  } deriving (Eq, Ord, Show)

recordACodec :: BinaryCodec RecordA
recordACodec =
  RecordA
    <$> recordAInt64 =. int64le
    <*> recordAWord8 =. word8
    <*> recordANestedB =. recordBCodec

recordBCodec :: BinaryCodec RecordB
recordBCodec =
  RecordB
    <$> recordBWord16 =. word16host
    <*> recordBByteString64 =. byteString 64

A Codec is just a combination of a deserializer r a, and a serializer c -> w a.

data CodecFor r w c a = Codec
  { codecIn :: r a
  , codecOut :: c -> w a
  }
  
type Codec r w a = CodecFor r w a a

With binary for example, r is Get and w is PutM. The reason we have an extra parameter c is so that we can associate a Codec with a particular field using the =. operator:

(=.) :: (c' -> c) -> CodecFor r w c a -> CodecFor r w c' a

Codec is an instance of Functor, Applicative, Monad and Profunctor. You can serialize in any order you like, regardless of field order in the data type:

recordBCodecFlipped :: BinaryCodec RecordB
recordBCodecFlipped = do
  bs64 <- recordBByteString64 =. byteString 64
  RecordB
    <$> recordBWord16 =. word16host
    <*> pure bs64

Contributors

=. operator and Profunctor approach thanks to Xia Li-yao