    {-# LANGUAGE ScopedTypeVariables, Unsafe #-}
    {-# OPTIONS_GHC -Wall #-}

    -- | Efficient, but unsafe 'Get' and 'Putter' for
    -- "Data.Vector.Storable" vectors. The serialized format is an 'Int64'
    -- representing the length of the 'Vector', followed by the raw
    -- bytes. Therefore behavior may be unpredictable if serialized data
    -- is transferred between machines with different word size or
    -- endianness.
    module Data.Vector.Storable.UnsafeSerialize (
        unsafeGetVector
      , unsafePutVector
    ) where

    import Control.Monad (when)

    import qualified Data.ByteString.Internal as BS
    import Data.Int (Int64)
    import Data.Serialize (Get, getBytes, putByteString, Putter, Serialize(..))
    import Data.Vector.Storable ( unsafeFromForeignPtr0
                                , unsafeToForeignPtr0
                                , Vector)
    import Data.Vector.Storable.Internal (updPtr)

    import Foreign.ForeignPtr (castForeignPtr)
    import Foreign.Marshal.Array (advancePtr)
    import Foreign.Storable (Storable, sizeOf)

    -- | Get a 'Vector' in host order, endian form, and word width.
    unsafeGetVector :: forall a. Storable a => Get (Vector a)
    {-# INLINE unsafeGetVector #-}
    unsafeGetVector :: forall a. Storable a => Get (Vector a)
    unsafeGetVector = do
      len64 <- Get Int64
    forall t. Serialize t => Get t
    get :: Get Int64
      when (len64 > fromIntegral (maxBound :: Int)) $
        fail "Host can't deserialize a Vector longer than (maxBound :: Int)"
      let len    = Int64 -> Int
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int64
    len64
          nbytes = Int
    len Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * a -> Int
    forall a. Storable a => a -> Int
    sizeOf (a
    forall a. HasCallStack => a
    undefined :: a)
      bs <- getBytes nbytes
      let (fp, off, _)    = BS.toForeignPtr bs
          fp' | Int
    off Int -> Int -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Int
    0  = (Ptr Word8 -> Ptr Word8) -> ForeignPtr Word8 -> ForeignPtr Word8
    forall a. (Ptr a -> Ptr a) -> ForeignPtr a -> ForeignPtr a
    updPtr (Ptr Word8 -> Int -> Ptr Word8
    forall a. Storable a => Ptr a -> Int -> Ptr a
    `advancePtr` Int
    off) ForeignPtr Word8
    fp
              | Bool
    otherwise = ForeignPtr Word8
    fp
      return $ unsafeFromForeignPtr0 (castForeignPtr fp') len

    -- | Put a 'Vector' in host order, endian form, and word width.
    unsafePutVector :: forall a. Storable a => Putter (Vector a)
    {-# INLINE unsafePutVector #-}
    unsafePutVector :: forall a. Storable a => Putter (Vector a)
    unsafePutVector Vector a
    v = do
      let (ForeignPtr a
    fp, Int
    len) = Vector a -> (ForeignPtr a, Int)
    forall a. Vector a -> (ForeignPtr a, Int)
    unsafeToForeignPtr0 Vector a
    v
          nbytes :: Int
    nbytes    = Int
    len Int -> Int -> Int
    forall a. Num a => a -> a -> a
    * a -> Int
    forall a. Storable a => a -> Int
    sizeOf (a
    forall a. HasCallStack => a
    undefined :: a)
          bs :: ByteString
    bs        = ForeignPtr Word8 -> Int -> Int -> ByteString
    BS.fromForeignPtr (ForeignPtr a -> ForeignPtr Word8
    forall a b. ForeignPtr a -> ForeignPtr b
    castForeignPtr ForeignPtr a
    fp) Int
    0 Int
    nbytes
      Putter Int64
    forall t. Serialize t => Putter t
    put (Int -> Int64
    forall a b. (Integral a, Num b) => a -> b
    fromIntegral Int
    len :: Int64)
      Putter ByteString
    putByteString ByteString
    bs