repa-convert-4.2.1.1: Data/Repa/Convert/Format/Bytes.hs
-- | Conversions for "Data.ByteString" things.
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
-- | Variable length sequence of bytes, represented as a `Data.ByteString`.
--
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
-- Pointer to active bytes.
!ptr = F.plusPtr ptr_ start
-- Copy bytes from the bytestring to the destination buffer.
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
-- Length of the input buffer.
!lenBuf = F.minusPtr (pw8 end) (pw8 start)
-- Scan through the input to see how long the result will be.
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 the desired bytes into a new buffer.
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 #-}