content: {-# LANGUAGE ScopedTypeVariables #-}
  module Ros.Internal.Util.BytesToVector (unsafeBytesToVector, bytesToVectorL, 
                                          bytesToVector, unsafeVectorToBytes, 
                                          vectorToBytes) where
  import qualified Data.ByteString.Lazy as BL
  import qualified Data.ByteString as BS
  import qualified Data.ByteString.Unsafe as BU
  import qualified Data.Vector.Storable as V
  import Foreign.Ptr (castPtr, plusPtr)
  import Foreign.ForeignPtr (newForeignPtr_, withForeignPtr, 
                             mallocForeignPtrBytes)
  import Foreign.Marshal.Utils (copyBytes)
  import Foreign.Storable (sizeOf)
  import System.IO.Unsafe (unsafePerformIO)
  
  -- |Construct a 'V.Vector' with the specified number of elements from
  -- a strict 'BS.ByteString' without copying.
  unsafeBytesToVector :: V.Storable a => Int -> BS.ByteString -> V.Vector a
  unsafeBytesToVector n bs = unsafePerformIO $
                             BU.unsafeUseAsCStringLen bs $
                             (\(p,_) -> do fp <- newForeignPtr_ (castPtr p)
                                           return $ V.unsafeFromForeignPtr fp 0 n)
  
  -- |Construct a 'V.Vector' with the specified number of elements from
  -- a strict 'BS.ByteString' making a copy of the underlying data in
  -- the process.
  bytesToVector :: V.Storable a => Int -> BS.ByteString -> V.Vector a
  bytesToVector n bs = unsafePerformIO $
                       BU.unsafeUseAsCStringLen bs $
                       (\(p,len) -> do fp <- mallocForeignPtrBytes len
                                       withForeignPtr fp $
                                         \dst -> copyBytes (castPtr dst) p len
                                       return $ V.unsafeFromForeignPtr fp 0 n)
  
  -- |Construct a 'V.Vector' with the specified number of elements from
  -- a lazy 'BL.ByteString'.
  bytesToVectorL :: V.Storable a => Int -> BL.ByteString -> V.Vector a
  bytesToVectorL n = bytesToVector n . BS.concat . BL.toChunks
  
  -- |Construct a strict 'BS.ByteString' from a 'V.Vector' without
  -- copying the underlying data.
  unsafeVectorToBytes :: forall a. V.Storable a => V.Vector a -> BS.ByteString
  unsafeVectorToBytes v = 
      unsafePerformIO $
      withForeignPtr fp (\p -> let p' = castPtr $ plusPtr p offset
                               in BU.unsafePackCStringLen (p', len*sz))
      where (fp,offset,len) = V.unsafeToForeignPtr v
            sz = sizeOf (undefined::a)
  
  -- |Construct a strict 'BS.ByteString' from a copy of the data
  -- underlying a 'V.Vector'.
  vectorToBytes :: forall a. V.Storable a => V.Vector a-> BS.ByteString
  vectorToBytes v = 
      unsafePerformIO $
      withForeignPtr fp (\p -> let p' = castPtr $ plusPtr p offset
                               in BS.packCStringLen (p', len*sz))
      where (fp,offset,len) = V.unsafeToForeignPtr v
            sz = sizeOf (undefined::a)
  