{-# 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)