packages feed

rattletrap-10.0.0: src/lib/Rattletrap/BitGet.hs

module Rattletrap.BitGet where

import qualified Control.Monad as Monad
import qualified Data.Binary.Bits.Get as BinaryBits
import qualified Data.Binary.Get as Binary
import qualified Data.Bits as Bits
import qualified Data.ByteString as ByteString
import qualified Data.ByteString.Lazy as LazyByteString
import qualified Data.Word as Word
import qualified Rattletrap.ByteGet as ByteGet
import qualified Rattletrap.Get as Get
import qualified Rattletrap.Utility.Bytes as Utility

type BitGet = BinaryBits.BitGet

toByteGet :: BitGet a -> ByteGet.ByteGet a
toByteGet = binaryGetToByteGet . BinaryBits.runBitGet

binaryGetToByteGet :: Binary.Get a -> ByteGet.ByteGet a
binaryGetToByteGet g = do
  s1 <- Get.get
  case Binary.runGetOrFail g $ LazyByteString.fromStrict s1 of
    Left (_, _, x) -> fail x
    Right (s2, _, x) -> do
      Get.put $ LazyByteString.toStrict s2
      pure x

fromByteGet :: ByteGet.ByteGet a -> Int -> BitGet a
fromByteGet f n = do
  x <- BinaryBits.getByteString n
  either fail pure . ByteGet.run f $ Utility.reverseBytes x

bits :: Bits.Bits a => Int -> BitGet a
bits n =
  foldr
      (\bit x -> let y = Bits.shiftL x 1 in if bit then Bits.setBit y 0 else y
      )
      Bits.zeroBits
    <$> Monad.replicateM n bool

bool :: BitGet Bool
bool = BinaryBits.getBool

byteString :: Int -> BitGet ByteString.ByteString
byteString = BinaryBits.getByteString

word8 :: Int -> BitGet Word.Word8
word8 = BinaryBits.getWord8