module Rattletrap.BitGet where

import qualified Control.Exception as Exception
import qualified Control.Monad as Monad
import qualified Data.Bits as Bits
import qualified Data.ByteString as ByteString
import qualified Data.Functor.Identity as Identity
import qualified Rattletrap.BitString as BitString
import qualified Rattletrap.ByteGet as ByteGet
import qualified Rattletrap.Exception.NotEnoughInput as NotEnoughInput
import qualified Rattletrap.Get as Get

type BitGet = Get.Get BitString.BitString Identity.Identity

toByteGet :: BitGet a -> ByteGet.ByteGet a
toByteGet g = do
  s1 <- Get.get
  case Identity.runIdentity . Get.run g $ BitString.fromByteString s1 of
    Left (ls, e) -> Get.labels ls $ ByteGet.throw e
    Right (s2, x) -> do
      Get.put $ BitString.byteString s2
      pure x

fromByteGet :: ByteGet.ByteGet a -> Int -> BitGet a
fromByteGet f n = do
  x <- byteString n
  Get.embed f x

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

bool :: BitGet Bool
bool = do
  s1 <- Get.get
  case BitString.pop s1 of
    Nothing -> throw NotEnoughInput.NotEnoughInput
    Just (x, s2) -> do
      Get.put s2
      pure x

byteString :: Int -> BitGet ByteString.ByteString
byteString n = fmap ByteString.pack . Monad.replicateM n $ bits 8

throw :: (Exception.Exception e) => e -> BitGet a
throw = Get.throw

label :: String -> BitGet a -> BitGet a
label = Get.label

module Rattletrap.BitGet where

import qualified Control.Exception as Exception
import qualified Control.Monad as Monad
import qualified Data.Bits as Bits
import qualified Data.ByteString as ByteString
import qualified Data.Functor.Identity as Identity
import qualified Rattletrap.BitString as BitString
import qualified Rattletrap.ByteGet as ByteGet
import qualified Rattletrap.Exception.NotEnoughInput as NotEnoughInput
import qualified Rattletrap.Get as Get

type BitGet = Get.Get BitString.BitString Identity.Identity

toByteGet :: BitGet a -> ByteGet.ByteGet a
toByteGet g = do
  s1 <- Get.get
  case Identity.runIdentity . Get.run g $ BitString.fromByteString s1 of
    Left (ls, e) -> Get.labels ls $ ByteGet.throw e
    Right (s2, x) -> do
      Get.put $ BitString.byteString s2
      pure x

fromByteGet :: ByteGet.ByteGet a -> Int -> BitGet a
fromByteGet f n = do
  x <- byteString n
  Get.embed f x

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

bool :: BitGet Bool
bool = do
  s1 <- Get.get
  case BitString.pop s1 of
    Nothing -> throw NotEnoughInput.NotEnoughInput
    Just (x, s2) -> do
      Get.put s2
      pure x

byteString :: Int -> BitGet ByteString.ByteString
byteString n = fmap ByteString.pack . Monad.replicateM n $ bits 8

throw :: (Exception.Exception e) => e -> BitGet a
throw = Get.throw

label :: String -> BitGet a -> BitGet a
label = Get.label
