module Data.Repa.Convert.Format.Bytes
(VarBytes (..))
where
import Data.Repa.Convert.Internal.Format
import Data.Repa.Convert.Internal.Packable
import Data.Word
import GHC.Exts
import Prelude hiding (fail)
import Data.ByteString (ByteString)
import qualified Data.ByteString.Char8 as BS
import qualified Data.ByteString.Internal as BS
import qualified Foreign.Marshal.Alloc as F
import qualified Foreign.ForeignPtr as F
import qualified Foreign.Storable as F
import qualified Foreign.Ptr as F
data VarBytes = VarBytes deriving (Eq, Show)
instance Format VarBytes where
type Value VarBytes = ByteString
fieldCount _ = 1
minSize _ = 0
fixedSize VarBytes = Nothing
packedSize VarBytes bs = Just $ BS.length bs
{-# INLINE fieldCount #-}
{-# INLINE minSize #-}
{-# INLINE fixedSize #-}
{-# INLINE packedSize #-}
instance Packable VarBytes where
packer VarBytes (BS.PS fptr start len) dst _fails k
= F.withForeignPtr fptr
$ \ptr_
-> let
!ptr = F.plusPtr ptr_ start
packer_VarBytes !ix
| ix >= len
= let !(Ptr dst') = F.plusPtr (Ptr dst) ix
in k dst'
| otherwise
= do !(x :: Word8) <- F.peekByteOff ptr ix
F.pokeByteOff (Ptr dst) ix x
packer_VarBytes (ix + 1)
{-# INLINE packer_VarBytes #-}
in packer_VarBytes 0
instance Unpackable VarBytes where
unpacker VarBytes start end stop _fail eat
= checkLen 0
where
!lenBuf = F.minusPtr (pw8 end) (pw8 start)
checkLen !ix
| ix >= lenBuf
= copy lenBuf
| otherwise
= do !(x :: Word8) <- F.peekByteOff (pw8 start) ix
if stop x
then copy ix
else checkLen (ix + 1)
{-# INLINE checkLen #-}
copy !len
= F.mallocBytes len >>= \ptr
-> let
unpacker_VarBytes !ix
| ix >= len
= do fptr <- F.newForeignPtr F.finalizerFree ptr
let bs = BS.PS fptr 0 len
let !(Ptr start') = F.plusPtr (pw8 start) len
eat start' bs
| otherwise
= do x :: Word8 <- F.peekByteOff (pw8 start) ix
F.pokeByteOff ptr ix x
unpacker_VarBytes (ix + 1)
in unpacker_VarBytes 0
{-# INLINE copy #-}
{-# INLINE unpacker #-}
pw8 :: Addr# -> Ptr Word8
pw8 addr = Ptr addr
{-# INLINE pw8 #-}