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
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)
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)
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
pw8 :: Addr# -> Ptr Word8
pw8 addr = Ptr addr