{-# LANGUAGE CPP                 #-}
{-# LANGUAGE DeriveAnyClass      #-}
{-# LANGUAGE DeriveGeneric       #-}
{-# LANGUAGE ScopedTypeVariables #-}

-- |Pre-value and post-value byte alignments
module PlutusCore.Flat.Filler (
    Filler(..),
    fillerLength,
    PreAligned(..),
    preAligned,
    PostAligned(..),
    postAligned,
    preAlignedDecoder,
    postAlignedDecoder
    ) where

import Control.DeepSeq (NFData)
import Data.Typeable (Typeable)
import PlutusCore.Flat.Class (Flat (..), Generic)
import PlutusCore.Flat.Decoder.Types (Get)
import PlutusCore.Flat.Encoder.Strict (eFiller, sFillerMax)

-- |A meaningless sequence of 0 bits terminated with a 1 bit (easier to implement than the reverse)
--
-- Used to align encoded values at byte/word boundaries.
data Filler = FillerBit !Filler
            | FillerEnd
  deriving (Int -> Filler -> ShowS
[Filler] -> ShowS
Filler -> String
(Int -> Filler -> ShowS)
-> (Filler -> String) -> ([Filler] -> ShowS) -> Show Filler
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> Filler -> ShowS
showsPrec :: Int -> Filler -> ShowS
$cshow :: Filler -> String
show :: Filler -> String
$cshowList :: [Filler] -> ShowS
showList :: [Filler] -> ShowS
Show, Filler -> Filler -> Bool
(Filler -> Filler -> Bool)
-> (Filler -> Filler -> Bool) -> Eq Filler
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: Filler -> Filler -> Bool
== :: Filler -> Filler -> Bool
$c/= :: Filler -> Filler -> Bool
/= :: Filler -> Filler -> Bool
Eq, Eq Filler
Eq Filler =>
(Filler -> Filler -> Ordering)
-> (Filler -> Filler -> Bool)
-> (Filler -> Filler -> Bool)
-> (Filler -> Filler -> Bool)
-> (Filler -> Filler -> Bool)
-> (Filler -> Filler -> Filler)
-> (Filler -> Filler -> Filler)
-> Ord Filler
Filler -> Filler -> Bool
Filler -> Filler -> Ordering
Filler -> Filler -> Filler
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
$ccompare :: Filler -> Filler -> Ordering
compare :: Filler -> Filler -> Ordering
$c< :: Filler -> Filler -> Bool
< :: Filler -> Filler -> Bool
$c<= :: Filler -> Filler -> Bool
<= :: Filler -> Filler -> Bool
$c> :: Filler -> Filler -> Bool
> :: Filler -> Filler -> Bool
$c>= :: Filler -> Filler -> Bool
>= :: Filler -> Filler -> Bool
$cmax :: Filler -> Filler -> Filler
max :: Filler -> Filler -> Filler
$cmin :: Filler -> Filler -> Filler
min :: Filler -> Filler -> Filler
Ord, (forall x. Filler -> Rep Filler x)
-> (forall x. Rep Filler x -> Filler) -> Generic Filler
forall x. Rep Filler x -> Filler
forall x. Filler -> Rep Filler x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cfrom :: forall x. Filler -> Rep Filler x
from :: forall x. Filler -> Rep Filler x
$cto :: forall x. Rep Filler x -> Filler
to :: forall x. Rep Filler x -> Filler
Generic, Filler -> ()
(Filler -> ()) -> NFData Filler
forall a. (a -> ()) -> NFData a
$crnf :: Filler -> ()
rnf :: Filler -> ()
NFData)

-- |Use a special encoding for the filler
instance Flat Filler where
  encode :: Filler -> Encoding
encode Filler
_ = Encoding
eFiller
  size :: Filler -> Int -> Int
size = Filler -> Int -> Int
forall a. Size a
sFillerMax
  -- use generated decode

-- |A Post aligned value, a value followed by a filler
--
-- Useful to complete the encoding of a top-level value
#ifdef ETA_VERSION

data PostAligned a = PostAligned { postValue :: a, postFiller :: Filler }
  deriving (Show, Eq, Ord, Generic, NFData)

instance Flat a => Flat (PostAligned a) where
  encode (PostAligned val fill) = trampolineEncoding (encode val) <> encode fill

#else

data PostAligned a = PostAligned { forall a. PostAligned a -> a
postValue :: a, forall a. PostAligned a -> Filler
postFiller :: Filler }
  deriving (Int -> PostAligned a -> ShowS
[PostAligned a] -> ShowS
PostAligned a -> String
(Int -> PostAligned a -> ShowS)
-> (PostAligned a -> String)
-> ([PostAligned a] -> ShowS)
-> Show (PostAligned a)
forall a. Show a => Int -> PostAligned a -> ShowS
forall a. Show a => [PostAligned a] -> ShowS
forall a. Show a => PostAligned a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> PostAligned a -> ShowS
showsPrec :: Int -> PostAligned a -> ShowS
$cshow :: forall a. Show a => PostAligned a -> String
show :: PostAligned a -> String
$cshowList :: forall a. Show a => [PostAligned a] -> ShowS
showList :: [PostAligned a] -> ShowS
Show, PostAligned a -> PostAligned a -> Bool
(PostAligned a -> PostAligned a -> Bool)
-> (PostAligned a -> PostAligned a -> Bool) -> Eq (PostAligned a)
forall a. Eq a => PostAligned a -> PostAligned a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => PostAligned a -> PostAligned a -> Bool
== :: PostAligned a -> PostAligned a -> Bool
$c/= :: forall a. Eq a => PostAligned a -> PostAligned a -> Bool
/= :: PostAligned a -> PostAligned a -> Bool
Eq, Eq (PostAligned a)
Eq (PostAligned a) =>
(PostAligned a -> PostAligned a -> Ordering)
-> (PostAligned a -> PostAligned a -> Bool)
-> (PostAligned a -> PostAligned a -> Bool)
-> (PostAligned a -> PostAligned a -> Bool)
-> (PostAligned a -> PostAligned a -> Bool)
-> (PostAligned a -> PostAligned a -> PostAligned a)
-> (PostAligned a -> PostAligned a -> PostAligned a)
-> Ord (PostAligned a)
PostAligned a -> PostAligned a -> Bool
PostAligned a -> PostAligned a -> Ordering
PostAligned a -> PostAligned a -> PostAligned a
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Ord a => Eq (PostAligned a)
forall a. Ord a => PostAligned a -> PostAligned a -> Bool
forall a. Ord a => PostAligned a -> PostAligned a -> Ordering
forall a. Ord a => PostAligned a -> PostAligned a -> PostAligned a
$ccompare :: forall a. Ord a => PostAligned a -> PostAligned a -> Ordering
compare :: PostAligned a -> PostAligned a -> Ordering
$c< :: forall a. Ord a => PostAligned a -> PostAligned a -> Bool
< :: PostAligned a -> PostAligned a -> Bool
$c<= :: forall a. Ord a => PostAligned a -> PostAligned a -> Bool
<= :: PostAligned a -> PostAligned a -> Bool
$c> :: forall a. Ord a => PostAligned a -> PostAligned a -> Bool
> :: PostAligned a -> PostAligned a -> Bool
$c>= :: forall a. Ord a => PostAligned a -> PostAligned a -> Bool
>= :: PostAligned a -> PostAligned a -> Bool
$cmax :: forall a. Ord a => PostAligned a -> PostAligned a -> PostAligned a
max :: PostAligned a -> PostAligned a -> PostAligned a
$cmin :: forall a. Ord a => PostAligned a -> PostAligned a -> PostAligned a
min :: PostAligned a -> PostAligned a -> PostAligned a
Ord, (forall x. PostAligned a -> Rep (PostAligned a) x)
-> (forall x. Rep (PostAligned a) x -> PostAligned a)
-> Generic (PostAligned a)
forall x. Rep (PostAligned a) x -> PostAligned a
forall x. PostAligned a -> Rep (PostAligned a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (PostAligned a) x -> PostAligned a
forall a x. PostAligned a -> Rep (PostAligned a) x
$cfrom :: forall a x. PostAligned a -> Rep (PostAligned a) x
from :: forall x. PostAligned a -> Rep (PostAligned a) x
$cto :: forall a x. Rep (PostAligned a) x -> PostAligned a
to :: forall x. Rep (PostAligned a) x -> PostAligned a
Generic, PostAligned a -> ()
(PostAligned a -> ()) -> NFData (PostAligned a)
forall a. NFData a => PostAligned a -> ()
forall a. (a -> ()) -> NFData a
$crnf :: forall a. NFData a => PostAligned a -> ()
rnf :: PostAligned a -> ()
NFData,Get (PostAligned a)
PostAligned a -> Encoding
PostAligned a -> Int -> Int
(PostAligned a -> Encoding)
-> Get (PostAligned a)
-> (PostAligned a -> Int -> Int)
-> Flat (PostAligned a)
forall a. Flat a => Get (PostAligned a)
forall a. Flat a => PostAligned a -> Encoding
forall a. Flat a => PostAligned a -> Int -> Int
forall a. (a -> Encoding) -> Get a -> (a -> Int -> Int) -> Flat a
$cencode :: forall a. Flat a => PostAligned a -> Encoding
encode :: PostAligned a -> Encoding
$cdecode :: forall a. Flat a => Get (PostAligned a)
decode :: Get (PostAligned a)
$csize :: forall a. Flat a => PostAligned a -> Int -> Int
size :: PostAligned a -> Int -> Int
Flat)

#endif

-- |A Pre aligned value, a value preceded by a filler
--
-- Useful to prealign ByteArrays, Texts and any structure that can be encoded more efficiently when byte aligned.
data PreAligned a = PreAligned { forall a. PreAligned a -> Filler
preFiller :: Filler, forall a. PreAligned a -> a
preValue :: a }
  deriving (Int -> PreAligned a -> ShowS
[PreAligned a] -> ShowS
PreAligned a -> String
(Int -> PreAligned a -> ShowS)
-> (PreAligned a -> String)
-> ([PreAligned a] -> ShowS)
-> Show (PreAligned a)
forall a. Show a => Int -> PreAligned a -> ShowS
forall a. Show a => [PreAligned a] -> ShowS
forall a. Show a => PreAligned a -> String
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: forall a. Show a => Int -> PreAligned a -> ShowS
showsPrec :: Int -> PreAligned a -> ShowS
$cshow :: forall a. Show a => PreAligned a -> String
show :: PreAligned a -> String
$cshowList :: forall a. Show a => [PreAligned a] -> ShowS
showList :: [PreAligned a] -> ShowS
Show, PreAligned a -> PreAligned a -> Bool
(PreAligned a -> PreAligned a -> Bool)
-> (PreAligned a -> PreAligned a -> Bool) -> Eq (PreAligned a)
forall a. Eq a => PreAligned a -> PreAligned a -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
$c== :: forall a. Eq a => PreAligned a -> PreAligned a -> Bool
== :: PreAligned a -> PreAligned a -> Bool
$c/= :: forall a. Eq a => PreAligned a -> PreAligned a -> Bool
/= :: PreAligned a -> PreAligned a -> Bool
Eq, Eq (PreAligned a)
Eq (PreAligned a) =>
(PreAligned a -> PreAligned a -> Ordering)
-> (PreAligned a -> PreAligned a -> Bool)
-> (PreAligned a -> PreAligned a -> Bool)
-> (PreAligned a -> PreAligned a -> Bool)
-> (PreAligned a -> PreAligned a -> Bool)
-> (PreAligned a -> PreAligned a -> PreAligned a)
-> (PreAligned a -> PreAligned a -> PreAligned a)
-> Ord (PreAligned a)
PreAligned a -> PreAligned a -> Bool
PreAligned a -> PreAligned a -> Ordering
PreAligned a -> PreAligned a -> PreAligned a
forall a.
Eq a =>
(a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
forall a. Ord a => Eq (PreAligned a)
forall a. Ord a => PreAligned a -> PreAligned a -> Bool
forall a. Ord a => PreAligned a -> PreAligned a -> Ordering
forall a. Ord a => PreAligned a -> PreAligned a -> PreAligned a
$ccompare :: forall a. Ord a => PreAligned a -> PreAligned a -> Ordering
compare :: PreAligned a -> PreAligned a -> Ordering
$c< :: forall a. Ord a => PreAligned a -> PreAligned a -> Bool
< :: PreAligned a -> PreAligned a -> Bool
$c<= :: forall a. Ord a => PreAligned a -> PreAligned a -> Bool
<= :: PreAligned a -> PreAligned a -> Bool
$c> :: forall a. Ord a => PreAligned a -> PreAligned a -> Bool
> :: PreAligned a -> PreAligned a -> Bool
$c>= :: forall a. Ord a => PreAligned a -> PreAligned a -> Bool
>= :: PreAligned a -> PreAligned a -> Bool
$cmax :: forall a. Ord a => PreAligned a -> PreAligned a -> PreAligned a
max :: PreAligned a -> PreAligned a -> PreAligned a
$cmin :: forall a. Ord a => PreAligned a -> PreAligned a -> PreAligned a
min :: PreAligned a -> PreAligned a -> PreAligned a
Ord, (forall x. PreAligned a -> Rep (PreAligned a) x)
-> (forall x. Rep (PreAligned a) x -> PreAligned a)
-> Generic (PreAligned a)
forall x. Rep (PreAligned a) x -> PreAligned a
forall x. PreAligned a -> Rep (PreAligned a) x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall a x. Rep (PreAligned a) x -> PreAligned a
forall a x. PreAligned a -> Rep (PreAligned a) x
$cfrom :: forall a x. PreAligned a -> Rep (PreAligned a) x
from :: forall x. PreAligned a -> Rep (PreAligned a) x
$cto :: forall a x. Rep (PreAligned a) x -> PreAligned a
to :: forall x. Rep (PreAligned a) x -> PreAligned a
Generic, PreAligned a -> ()
(PreAligned a -> ()) -> NFData (PreAligned a)
forall a. NFData a => PreAligned a -> ()
forall a. (a -> ()) -> NFData a
$crnf :: forall a. NFData a => PreAligned a -> ()
rnf :: PreAligned a -> ()
NFData, Get (PreAligned a)
PreAligned a -> Encoding
PreAligned a -> Int -> Int
(PreAligned a -> Encoding)
-> Get (PreAligned a)
-> (PreAligned a -> Int -> Int)
-> Flat (PreAligned a)
forall a. Flat a => Get (PreAligned a)
forall a. Flat a => PreAligned a -> Encoding
forall a. Flat a => PreAligned a -> Int -> Int
forall a. (a -> Encoding) -> Get a -> (a -> Int -> Int) -> Flat a
$cencode :: forall a. Flat a => PreAligned a -> Encoding
encode :: PreAligned a -> Encoding
$cdecode :: forall a. Flat a => Get (PreAligned a)
decode :: Get (PreAligned a)
$csize :: forall a. Flat a => PreAligned a -> Int -> Int
size :: PreAligned a -> Int -> Int
Flat)

-- |Length of a filler in bits
fillerLength :: Num a => Filler -> a
fillerLength :: forall a. Num a => Filler -> a
fillerLength Filler
FillerEnd     = a
1
fillerLength (FillerBit Filler
f) = a
1 a -> a -> a
forall a. Num a => a -> a -> a
+ Filler -> a
forall a. Num a => Filler -> a
fillerLength Filler
f

-- |Post align a value
postAligned :: a -> PostAligned a
postAligned :: forall a. a -> PostAligned a
postAligned a
a = a -> Filler -> PostAligned a
forall a. a -> Filler -> PostAligned a
PostAligned a
a Filler
FillerEnd

-- |Pre align a value
preAligned :: a -> PreAligned a
preAligned :: forall a. a -> PreAligned a
preAligned = Filler -> a -> PreAligned a
forall a. Filler -> a -> PreAligned a
PreAligned Filler
FillerEnd

-- |Decode a value assuming that is PostAligned
postAlignedDecoder :: Get b -> Get b
postAlignedDecoder :: forall b. Get b -> Get b
postAlignedDecoder Get b
dec = do
  b
v <- Get b
dec
  Filler
_::Filler <- Get Filler
forall a. Flat a => Get a
decode
  b -> Get b
forall a. a -> Get a
forall (m :: * -> *) a. Monad m => a -> m a
return b
v

-- |Decode a value assuming that is PreAligned
--
-- @since 0.5
preAlignedDecoder :: Get b -> Get b
preAlignedDecoder :: forall b. Get b -> Get b
preAlignedDecoder Get b
dec = do
  Filler
_::Filler <- Get Filler
forall a. Flat a => Get a
decode
  Get b
dec