{-# LANGUAGE BangPatterns, OverloadedStrings, CPP #-}
module Network.HPACK.HeaderBlock.Integer (
encode
, encodeInteger
, decode
, decodeInteger
) where
#if __GLASGOW_HASKELL__ < 709
import Control.Applicative ((<$>))
#endif
import Data.Array (Array, listArray)
import Data.Array.Base (unsafeAt)
import Data.Bits ((.&.), shiftR, testBit)
import Data.ByteString (ByteString)
import Data.Word (Word8)
import Network.HPACK.Buffer
powerArray :: Array Int Int
powerArray = listArray (1,8) [1,3,7,15,31,63,127,255]
encodeInteger :: Int -> Int -> IO ByteString
encodeInteger n i = withTemporaryBuffer 4096 $ \wbuf -> encode wbuf id n i
{-# INLINABLE encode #-}
encode :: WorkingBuffer -> (Word8 -> Word8) -> Int -> Int -> IO ()
encode wbuf set n i
| i < p = writeWord8 wbuf $ set $ fromIntegral i
| otherwise = do
writeWord8 wbuf $ set $ fromIntegral p
encode' (i - p)
where
!p = powerArray `unsafeAt` (n - 1)
encode' :: Int -> IO ()
encode' j
| j < 128 = writeWord8 wbuf $ fromIntegral j
| otherwise = do
let !q = j `shiftR` 7
!r = j .&. 0x7f
writeWord8 wbuf $ fromIntegral (r + 128)
encode' q
decodeInteger :: Int -> Word8 -> ByteString -> IO Int
decodeInteger n w bs = withReadBuffer bs $ \rbuf -> decode n w rbuf
{-# INLINABLE decode #-}
decode :: Int -> Word8 -> ReadBuffer -> IO Int
decode n w rbuf
| i < p = return i
| otherwise = decode' 0 i
where
!p = powerArray `unsafeAt` (n - 1)
!i = fromIntegral w
decode' :: Int -> Int -> IO Int
decode' m j = do
!b <- fromIntegral <$> getByte rbuf
let !j' = j + (b .&. 0x7f) * 2 ^ m
!m' = m + 7
!cont = b `testBit` 7
if cont then decode' m' j' else return j'