{-# LANGUAGE CPP #-}
#if __GLASGOW_HASKELL__
{-# LANGUAGE MagicHash #-}
#endif
module Data.ByteString.Unsafe (
unsafeHead,
unsafeTail,
unsafeInit,
unsafeLast,
unsafeIndex,
unsafeTake,
unsafeDrop,
unsafeUseAsCString,
unsafeUseAsCStringLen,
unsafePackCString,
unsafePackCStringLen,
unsafePackMallocCString,
unsafePackMallocCStringLen,
#if defined(__GLASGOW_HASKELL__)
unsafePackAddress,
unsafePackAddressLen,
unsafePackCStringFinalizer,
unsafeFinalize,
#endif
) where
import Data.ByteString.Internal
import Foreign.ForeignPtr (newForeignPtr_, newForeignPtr, withForeignPtr)
import Foreign.Ptr (Ptr, plusPtr, castPtr)
import Foreign.Storable (Storable(..))
import Foreign.C.String (CString, CStringLen)
#ifndef __NHC__
import Control.Exception (assert)
#endif
import Data.Word (Word8)
#if defined(__GLASGOW_HASKELL__)
import qualified Foreign.ForeignPtr as FC (finalizeForeignPtr)
import qualified Foreign.Concurrent as FC (newForeignPtr)
import GHC.Prim (Addr#)
import GHC.Ptr (Ptr(..))
#endif
#ifdef __NHC__
#define assert assertS "__FILE__ : __LINE__"
assertS :: String -> Bool -> a -> a
assertS _ True = id
assertS s False = error ("assertion failed at "++s)
#endif
#define STRICT1(f) f a | a `seq` False = undefined
#define STRICT2(f) f a b | a `seq` b `seq` False = undefined
#define STRICT3(f) f a b c | a `seq` b `seq` c `seq` False = undefined
#define STRICT4(f) f a b c d | a `seq` b `seq` c `seq` d `seq` False = undefined
#define STRICT5(f) f a b c d e | a `seq` b `seq` c `seq` d `seq` e `seq` False = undefined
unsafeHead :: ByteString -> Word8
unsafeHead (PS x s l) = assert (l > 0) $
inlinePerformIO $ withForeignPtr x $ \p -> peekByteOff p s
{-# INLINE unsafeHead #-}
unsafeTail :: ByteString -> ByteString
unsafeTail (PS ps s l) = assert (l > 0) $ PS ps (s+1) (l-1)
{-# INLINE unsafeTail #-}
unsafeInit :: ByteString -> ByteString
unsafeInit (PS ps s l) = assert (l > 0) $ PS ps s (l-1)
{-# INLINE unsafeInit #-}
unsafeLast :: ByteString -> Word8
unsafeLast (PS x s l) = assert (l > 0) $
inlinePerformIO $ withForeignPtr x $ \p -> peekByteOff p (s+l-1)
{-# INLINE unsafeLast #-}
unsafeIndex :: ByteString -> Int -> Word8
unsafeIndex (PS x s l) i = assert (i >= 0 && i < l) $
inlinePerformIO $ withForeignPtr x $ \p -> peekByteOff p (s+i)
{-# INLINE unsafeIndex #-}
unsafeTake :: Int -> ByteString -> ByteString
unsafeTake n (PS x s l) = assert (0 <= n && n <= l) $ PS x s n
{-# INLINE unsafeTake #-}
unsafeDrop :: Int -> ByteString -> ByteString
unsafeDrop n (PS x s l) = assert (0 <= n && n <= l) $ PS x (s+n) (l-n)
{-# INLINE unsafeDrop #-}
#if defined(__GLASGOW_HASKELL__)
unsafePackAddressLen :: Int -> Addr# -> IO ByteString
unsafePackAddressLen len addr# = do
p <- newForeignPtr_ (Ptr addr#)
return $ PS p 0 len
{-# INLINE unsafePackAddressLen #-}
unsafePackCStringFinalizer :: Ptr Word8 -> Int -> IO () -> IO ByteString
unsafePackCStringFinalizer p l f = do
fp <- FC.newForeignPtr p f
return $ PS fp 0 l
unsafeFinalize :: ByteString -> IO ()
unsafeFinalize (PS p _ _) = FC.finalizeForeignPtr p
#endif
unsafePackCString :: CString -> IO ByteString
unsafePackCString cstr = do
fp <- newForeignPtr_ (castPtr cstr)
l <- c_strlen cstr
return $! PS fp 0 (fromIntegral l)
unsafePackCStringLen :: CStringLen -> IO ByteString
unsafePackCStringLen (ptr,len) = do
fp <- newForeignPtr_ (castPtr ptr)
return $! PS fp 0 (fromIntegral len)
unsafePackMallocCString :: CString -> IO ByteString
unsafePackMallocCString cstr = do
fp <- newForeignPtr c_free_finalizer (castPtr cstr)
len <- c_strlen cstr
return $! PS fp 0 (fromIntegral len)
unsafePackMallocCStringLen :: CStringLen -> IO ByteString
unsafePackMallocCStringLen (cstr, len) = do
fp <- newForeignPtr c_free_finalizer (castPtr cstr)
return $! PS fp 0 len
unsafeUseAsCString :: ByteString -> (CString -> IO a) -> IO a
unsafeUseAsCString (PS ps s _) ac = withForeignPtr ps $ \p -> ac (castPtr p `plusPtr` s)
unsafeUseAsCStringLen :: ByteString -> (CStringLen -> IO a) -> IO a
unsafeUseAsCStringLen (PS ps s l) f = withForeignPtr ps $ \p -> f (castPtr p `plusPtr` s,l)