packages feed

flat-0.6: src/Flat/Filler.hs

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

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

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

-- |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 (Show, Eq, Ord, Typeable, Generic, NFData)

-- |Use a special encoding for the filler
instance Flat Filler where
  encode _ = eFiller
  size = sFillerMax
  -- use generated decode

-- |A Post aligned value, a value followed by a filler
-- 
-- Useful to complete the encoding of a top-level value
data PostAligned a = PostAligned { postValue :: a, postFiller :: Filler }
#ifdef ETA_VERSION    
  deriving (Show, Eq, Ord, Typeable, Generic, NFData)

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

#else
  deriving (Show, Eq, Ord, Typeable, Generic, NFData,Flat)
#endif
--  deriving (Show, Eq, Ord, Typeable, Generic, NFData,Flat)


-- |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 { preFiller :: Filler, preValue :: a }
  deriving (Show, Eq, Ord, Typeable, Generic, NFData, Flat)

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

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

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

-- |Decode a value assuming that is PostAligned
postAlignedDecoder :: Get b -> Get b
postAlignedDecoder dec = do
  v <- dec
  _::Filler <- decode
  return v

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