    -- | Encoding and decoding values to formats.
    module Raaz.Core.Encode
           ( -- * Encoding of binary data.
             -- $encodable$
             Encodable(..)
           , Format(..)
           , encode, decode, translate, unsafeDecode
           -- ** The base 16 encoding format
           , Base16
           , fromBase16, showBase16
           -- ** Other binary formats.
           , Base64
           ) where

    import Raaz.Core.Encode.Internal
    import Raaz.Core.Encode.Base16
    import Raaz.Core.Encode.Base64

    -- $encodable$
    --
    -- Often one wants to represent cryptographic hashes, secret keys or
    -- just binary data into various enocoding formats like base64,
    -- hexadecimal etc. This module gives a generic interface for all such
    -- operations. There are two main classes that capture the essence of
    -- encoding.
    --
    -- [`Format`:] The class of all types that are encoding formats to binary
    --     data. They are all instances of `Show` and `Data.String.IsString` for
    --     ease of printing and inclusion in source code.
    --
    -- [`Encodable`:] The class of all types that can be encoded /into/ binary.
    --
    -- The combinators `encode` and `decode` allows encoding any instance of `Encodable` to
    -- any of the instances of `Format`.
    --
    -- == Sample code that makes use of Base16 encoding.
    --
    -- > theAnswer :: LE Word64
    -- > theAnswer = 42
    -- >
    -- > main = do putStr "The answer to life, universe and everything is:"
    -- >           print answserInBase16
    -- >    where answerInBase16 :: Base16
    -- >          answerInBase16 = encode theAnswer
    -- >
    -- > checkAnswer :: Base16 -> Bool
    -- > checkAnswer = maybe False (==theAnswer) . decode
    -- >
    -- > checkAnswerBS :: ByteString -> Bool
    -- > checkAnswerBS = checkAnswer . fromString
    --
    -- In the above example, @`LE` Word64@, which captures 64-bit unsigned
    -- integers is an instance of Encode (but not Word64). The encode
    -- combinator then converts in into the type Base16 that is an
    -- instance of `Format`. The print then uses the `Show` instance of
    -- Base16 to print it as a sequence of hexadecimal
    -- characters. Similarly the decode combinator in @checkAnswer@
    -- decodes a base16 before comparing with the answer.
    --
    -- == Liberal @IsString@ instances
    --
    -- Certain ascii printable formats like Base16 and Base64 have a more
    -- liberal `IsString` instance: they typically allow the use of spaces
    -- and newline in the input to the `fromString` function . This allows
    -- a more readable representation of these types when using the
    -- @OverloadedStrings@ extension. See the documentation of the
    -- corresponding instance declarations to see what characters are
    -- ignored. However, all `Show` instance of formats are strict in the
    -- sense that they do not produce any such extraneous characters.

    -- | Encode in a given format.
    encode :: (Encodable a, Format fmt) => a -> fmt
    encode :: a -> fmt
    encode = ByteString -> fmt
    forall fmt. Format fmt => ByteString -> fmt
    encodeByteString (ByteString -> fmt) -> (a -> ByteString) -> a -> fmt
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . a -> ByteString
    forall a. Encodable a => a -> ByteString
    toByteString

    -- | Decode from a given format. It results in Nothing if there is a
    -- parse error.
    decode :: (Format fmt, Encodable a) => fmt -> Maybe a
    decode :: fmt -> Maybe a
    decode = ByteString -> Maybe a
    forall a. Encodable a => ByteString -> Maybe a
    fromByteString (ByteString -> Maybe a) -> (fmt -> ByteString) -> fmt -> Maybe a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . fmt -> ByteString
    forall fmt. Format fmt => fmt -> ByteString
    decodeFormat

    -- | The unsafe version of `decode`.
    unsafeDecode :: (Format fmt, Encodable a) => fmt -> a
    unsafeDecode :: fmt -> a
    unsafeDecode = ByteString -> a
    forall a. Encodable a => ByteString -> a
    unsafeFromByteString (ByteString -> a) -> (fmt -> ByteString) -> fmt -> a
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . fmt -> ByteString
    forall fmt. Format fmt => fmt -> ByteString
    decodeFormat

    -- | Translate from one format to another.
    translate :: (Format fmt1, Format fmt2) => fmt1 -> fmt2
    translate :: fmt1 -> fmt2
    translate = ByteString -> fmt2
    forall fmt. Format fmt => ByteString -> fmt
    encodeByteString (ByteString -> fmt2) -> (fmt1 -> ByteString) -> fmt1 -> fmt2
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . fmt1 -> ByteString
    forall fmt. Format fmt => fmt -> ByteString
    decodeFormat