module Database.VCache.VCacheable
( VCacheable(..)
, module Database.VCache.VGet
, module Database.VCache.VPut
) where
import Control.Applicative
import Control.Monad
import Data.Word
import qualified Data.ByteString as BS
import qualified Data.ByteString.Lazy as LBS
import Database.VCache.VGet
import Database.VCache.VPut
import Database.VCache.Types
instance VCacheable Int where
get = fromIntegral <$> getVarInt
put = putVarInt . fromIntegral
instance VCacheable Integer where
get = getVarInt
put = putVarInt
instance VCacheable Bool where
get = getWord8 >>= \ n -> case n of
0 -> return False
1 -> return True
_ -> fail "Boolean expects a 0 or 1 byte"
put False = putWord8 0
put True = putWord8 1
instance VCacheable Char where
get = getc
put = putc
instance VCacheable Word8 where
get = getWord8
put = putWord8
instance VCacheable BS.ByteString where
get = getVarNat >>= getByteString . fromIntegral
put s = putVarNat (fromIntegral $ BS.length s) >> putByteString s
instance VCacheable LBS.ByteString where
get = getVarNat >>= getByteStringLazy . fromIntegral
put s = putVarNat (fromIntegral $ LBS.length s) >> putByteStringLazy s
instance (VCacheable a) => VCacheable (VRef a) where
get = getVRef
put = putVRef
instance (VCacheable a) => VCacheable (PVar a) where
get = getPVar
put = putPVar
instance VCacheable VSpace where
get = getVSpace
put = putVSpace
instance VCacheable () where
get = return ()
put () = return ()
instance (VCacheable a) => VCacheable (Maybe a) where
get = getWord8 >>= \ n -> case n of
0 -> return Nothing
1 -> Just <$> get
_ -> fail "Type `Maybe a` expects prefix byte 0 or 1"
put Nothing = putWord8 0
put (Just a) = putWord8 1 >> put a
instance (VCacheable a, VCacheable b) => VCacheable (Either a b) where
get = getWord8 >>= \ lr -> case lr of
0 -> Left <$> get
1 -> Right <$> get
_ -> fail "Type `Either a b` expects prefix byte 0 or 1"
put (Left a) = putWord8 0 >> put a
put (Right b) = putWord8 1 >> put b
instance (VCacheable a) => VCacheable [a] where
get = do
nCount <- liftM fromIntegral getVarNat
replicateReversed [] nCount get
put ls = do
let (nCount, lsr) = countAndReverse ls
putVarNat (fromIntegral nCount)
mapM_ put lsr
replicateReversed :: (Monad m) => [a] -> Int -> m a -> m [a]
replicateReversed xs 0 _ = return xs
replicateReversed xs n op = op >>= \ x -> replicateReversed (x:xs) (n1) op
countAndReverse :: [a] -> (Int, [a])
countAndReverse = cr [] 0 where
cr l !n (x:xs) = cr (x:l) (n+1) xs
cr l !n [] = (n, l)
instance (VCacheable a, VCacheable b) => VCacheable (a,b) where
get = liftM2 (,) get get
put (a,b) = do { put a; put b }
instance (VCacheable a, VCacheable b, VCacheable c) => VCacheable (a,b,c) where
get = liftM3 (,,) get get get
put (a,b,c) = do { put a; put b; put c }
instance (VCacheable a, VCacheable b, VCacheable c, VCacheable d)
=> VCacheable (a,b,c,d) where
get = liftM4 (,,,) get get get get
put (a,b,c,d) = do { put a; put b; put c; put d }
instance (VCacheable a, VCacheable b, VCacheable c, VCacheable d, VCacheable e)
=> VCacheable (a,b,c,d,e) where
get = liftM5 (,,,,) get get get get get
put (a,b,c,d,e) = do { put a; put b; put c; put d; put e }
instance (VCacheable a, VCacheable b, VCacheable c, VCacheable d, VCacheable e
, VCacheable f) => VCacheable (a,b,c,d,e,f) where
get =
do a <- get; b <- get; c <- get
d <- get; e <- get; f <- get
return (a,b,c,d,e,f)
put (a,b,c,d,e,f) = do { put a; put b; put c; put d; put e; put f }
instance (VCacheable a, VCacheable b, VCacheable c, VCacheable d, VCacheable e
, VCacheable f, VCacheable g) => VCacheable (a,b,c,d,e,f,g) where
get =
do a <- get; b <- get; c <- get
d <- get; e <- get; f <- get; g <- get
return (a,b,c,d,e,f,g)
put (a,b,c,d,e,f,g) = do { put a; put b; put c; put d; put e; put f; put g }