{-# LANGUAGE InstanceSigs        #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Flat.Repr where

import qualified Data.ByteString    as B
import           Flat.Class         (Flat (..))
import           Flat.Decoder.Types (Get)
import           Flat.Run           (flat, unflat)

-- $setup
-- >>> :set -XScopedTypeVariables
-- >>> import Flat.Instances.Base
-- >>> import Flat.Decoder.Types
-- >>> import Flat.Types
-- >>> import Flat.Run
-- >>> import Flat.Class

{- | Flat representation of a value

== Repr 
It is occasionally useful to keep a decoded value, or part of it, in its encoded binary representation and decode it later on demand.

To do so, just decode a value `a` to a `Repr a`.

For example, we encode a list of Ints and then decode it to a list of Repr Int:

>>> unflat (flat [1::Int .. 5]) :: Decoded ([Repr Int])
Right [Repr {repr = "\STX\SOH"},Repr {repr = "\EOT\SOH"},Repr {repr = "\ACK\SOH"},Repr {repr = "\b\SOH"},Repr {repr = "\n\SOH"}]

To decode a `Repr a` to an `a`, we use `unrepr`:

>>> let Right l = unflat (flat [1..5]) :: Decoded [Repr Int] in unrepr (l  !! 2)
3

See "test/FlatRepr.hs" for a test and a longer example of use.

== SizeOf
If a decoded value is not required, it can be skipped completely using `SizeOf a`.

For example, to ignore the second and fourth component of the following tuple, it can be decoded as:

>>> let v = flat ('a',"abc",'z',True) in unflat v :: Decoded (Char,SizeOf String,Char,SizeOf Bool)
Right ('a',SizeOf 28,'z',SizeOf 1)

The unused values have not been decoded and instead their size (in bits) is returned.
-}

newtype Repr a = Repr {forall a. Repr a -> ByteString
repr :: B.ByteString} deriving Int -> Repr a -> ShowS
forall a. Int -> Repr a -> ShowS
forall a. [Repr a] -> ShowS
forall a. Repr a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
showList :: [Repr a] -> ShowS
$cshowList :: forall a. [Repr a] -> ShowS
show :: Repr a -> String
$cshow :: forall a. Repr a -> String
showsPrec :: Int -> Repr a -> ShowS
$cshowsPrec :: forall a. Int -> Repr a -> ShowS
Show

-- Get the underlying value
unrepr :: Flat a => Repr a -> a
unrepr :: forall a. Flat a => Repr a -> a
unrepr (Repr ByteString
bs)=
    case forall a b. (Flat a, AsByteString b) => b -> Decoded a
unflat ByteString
bs of
        Right a
a -> a
a
        Left DecodeException
_  -> forall a. HasCallStack => String -> a
error String
"impossible"

instance Flat a => Flat (Repr a) where
    size :: Repr a -> Int -> Int
size = forall a. HasCallStack => String -> a
error String
"unused"
    encode :: Repr a -> Encoding
encode = forall a. HasCallStack => String -> a
error String
"unused"

    -- To create the representation we just re 'flat' the parsed value (this could be optimised by copying directly the parsed representation)
    decode :: Get (Repr a)
decode = forall a. ByteString -> Repr a
Repr forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. Flat a => a -> ByteString
flat forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (forall a. Flat a => Get a
decode :: Get a)