{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses, UndecidableInstances #-}
module Data.Binary.BitPut
( BitPut
, BitPutM
, BitPutT
, runBitPut
, runBitPutM
, runBitPutT
, putBit
, putBitT
, putNBits
, putNBitsT
, putBits
, putByteString
, putLeftByteString
) where
import Data.Bits (bitSize, Bits)
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Error
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as BL
import qualified Data.Binary.BitBuilder as BB
newtype BitPutM a = BitPutM { unPut :: (a, BB.BitBuilder) }
type BitPut = BitPutM ()
instance Functor BitPutM where
fmap f m = BitPutM (let (a, w) = unPut m in (f a, w))
instance Applicative BitPutM where
pure = return
(<*>) = ap
instance Monad BitPutM where
return a = BitPutM (a,BB.empty)
m >>= k = BitPutM (let (a, w) = unPut m
(b, w') = unPut (k a)
in (b, w `BB.append` w'))
m >> k = BitPutM (let (_, w) = unPut m
(b, w') = unPut k
in (b, w `BB.append` w'))
{-# INLINE (>>) #-}
newtype BitPutT m a = BitPutT { unPutT :: m (a, BB.BitBuilder) }
putBit :: Bool -> BitPut
putBit bit = BitPutM ((), BB.singleton bit)
putNBits :: (Integral a, Bits a) => Int -> a -> BitPut
putNBits n v = BitPutM ((), BB.fromBits n v)
putBits :: (Integral a, Bits a) => a -> BitPut
putBits v = putNBits (bitSize v) v
putByteString :: B.ByteString -> BitPut
putByteString bs = BitPutM ((), BB.fromByteString (bs, 0))
putLeftByteString :: (B.ByteString, Int) -> BitPut
putLeftByteString bs = BitPutM ((), BB.fromByteString bs)
runBitPut :: BitPut -> BL.ByteString
runBitPut m = let (_, w) = unPut m
in BB.toLazyByteString w
runBitPutM :: BitPutM a -> (a, BL.ByteString)
runBitPutM m = let (x, w) = unPut m
in (x, BB.toLazyByteString w)
instance Monad m => Functor (BitPutT m) where
fmap f m = BitPutT $ do
~(x, w) <- unPutT m
return (f x, w)
instance Monad m => Applicative (BitPutT m) where
pure = return
(<*>) = ap
instance Monad m => Monad (BitPutT m) where
return a = BitPutT $ return (a, BB.empty)
m >>= k = BitPutT $ do
~(a, w) <- unPutT m
~(b, w') <- unPutT (k a)
return (b, w `BB.append` w')
runBitPutT :: Monad m => BitPutT m a -> m (a, BL.ByteString)
runBitPutT m = do
~(x, w) <- unPutT m
return (x, BB.toLazyByteString w)
putBitT :: (Monad m) => Bool -> BitPutT m ()
putBitT bit = BitPutT $ return ((), BB.singleton bit)
putNBitsT :: (Monad m, Integral a, Bits a) => Int -> a -> BitPutT m ()
putNBitsT n v = BitPutT $ return ((), BB.fromBits n v)
instance MonadTrans BitPutT where
lift m = BitPutT $ do
a <- m
return (a, BB.empty)
instance MonadError e m => MonadError e (BitPutT m) where
throwError = lift . throwError
m `catchError` h = BitPutT $ do
unPutT m `catchError` \e -> unPutT (h e)