module Database.VCache.VGetAux
( getWord8FromEnd
, getWord8
, isEmpty, vgetStateEmpty
, getVarNat
, getVarInt
, consuming
, peekByte
) where
import Control.Applicative
import Data.Word
import Data.Bits
import qualified Data.List as L
import Foreign.Ptr
import Foreign.Storable
import Database.VCache.Types
getWord8 :: VGet Word8
getWord8 = consuming 1 $ VGet $ \ s -> do
let p = vget_target s
r <- peekByte p
let s' = s { vget_target = p `plusPtr` 1 }
return (VGetR r s')
getWord8FromEnd :: VGet Word8
getWord8FromEnd = consuming 1 $ VGet $ \ s -> do
let p = vget_limit s `plusPtr` (1)
r <- peekByte p
let s' = s { vget_limit = p }
return (VGetR r s')
peekByte :: Ptr Word8 -> IO Word8
peekByte = peek
isEmpty :: VGet Bool
isEmpty = VGet $ \ s ->
let bEOF = vgetStateEmpty s in
bEOF `seq` return (VGetR bEOF s)
vgetStateEmpty :: VGetS -> Bool
vgetStateEmpty s = (vget_target s == vget_limit s)
&& (L.null (vget_children s))
getVarInt :: VGet Integer
getVarInt = unZigZag <$> getVarNat
unZigZag :: Integer -> Integer
unZigZag !n =
let (q,r) = n `divMod` 2 in
if (1 == r) then negate q 1
else q
getVarNat :: VGet Integer
getVarNat = getVarNat' 0
getVarNat' :: Integer -> VGet Integer
getVarNat' !n =
getWord8 >>= \ w ->
let n' = (128 * n) + fromIntegral (w .&. 0x7f) in
if (w < 128) then return $! n'
else getVarNat' n'
consuming :: Int -> VGet a -> VGet a
consuming n op = VGet $ \ s ->
let pConsuming = vget_target s `plusPtr` n in
if (pConsuming > vget_limit s) then return (VGetE "not enough data") else
_vget op s