-- | Convert between @ByteString@ and @Vector.Storable@
-- without copying.
module Data.Vector.Storable.ByteString
    ( -- | See also the caveats mentioned in the package's
      -- top-level documentation.
      byteStringToVector
    , vectorToByteString
    ) where

import qualified Data.ByteString          as BS
import qualified Data.ByteString.Internal as BS
import qualified Data.Vector.Storable     as V

import Foreign.Storable
import Foreign.ForeignPtr

sizeOfElem :: (Storable a) => V.Vector a -> Int
sizeOfElem :: forall a. Storable a => Vector a -> Int
sizeOfElem Vector a
vec = a -> Int
forall a. Storable a => a -> Int
sizeOf (a
forall a. HasCallStack => a
undefined a -> a -> a
forall a. a -> a -> a
`asTypeOf` Vector a -> a
forall a. Storable a => Vector a -> a
V.head Vector a
vec)

-- | Convert a @'BS.ByteString'@ to a @'V.Vector'@.
--
-- This function can produce @'Vector'@s which do not obey
-- architectural alignment requirements.  On @x86@ this should
-- not be an issue.
byteStringToVector :: (Storable a) => BS.ByteString -> V.Vector a
byteStringToVector :: forall a. Storable a => ByteString -> Vector a
byteStringToVector ByteString
bs = Vector a
vec where
    vec :: Vector a
vec = ForeignPtr a -> Int -> Int -> Vector a
forall a. Storable a => ForeignPtr a -> Int -> Int -> Vector a
V.unsafeFromForeignPtr (ForeignPtr Word8 -> ForeignPtr a
forall a b. ForeignPtr a -> ForeignPtr b
castForeignPtr ForeignPtr Word8
fptr) (Int -> Int
scale Int
off) (Int -> Int
scale Int
len)
    (ForeignPtr Word8
fptr, Int
off, Int
len) = ByteString -> (ForeignPtr Word8, Int, Int)
BS.toForeignPtr ByteString
bs
    scale :: Int -> Int
scale = (Int -> Int -> Int
forall a. Integral a => a -> a -> a
`div` Vector a -> Int
forall a. Storable a => Vector a -> Int
sizeOfElem Vector a
vec)

-- | Convert a @'V.Vector'@ to a @'BS.ByteString'@.
vectorToByteString :: (Storable a) => V.Vector a -> BS.ByteString
vectorToByteString :: forall a. Storable a => Vector a -> ByteString
vectorToByteString Vector a
vec
  = ForeignPtr Word8 -> Int -> Int -> ByteString
BS.fromForeignPtr (ForeignPtr a -> ForeignPtr Word8
forall a b. ForeignPtr a -> ForeignPtr b
castForeignPtr ForeignPtr a
fptr) (Int -> Int
scale Int
off) (Int -> Int
scale Int
len) where
    (ForeignPtr a
fptr, Int
off, Int
len) = Vector a -> (ForeignPtr a, Int, Int)
forall a. Storable a => Vector a -> (ForeignPtr a, Int, Int)
V.unsafeToForeignPtr Vector a
vec
    scale :: Int -> Int
scale = (Int -> Int -> Int
forall a. Num a => a -> a -> a
* Vector a -> Int
forall a. Storable a => Vector a -> Int
sizeOfElem Vector a
vec)