mcl-1.0.0: src/MCL/Internal/Prim/Pinned.hs
{-# LANGUAGE MagicHash #-}
{-# LANGUAGE ScopedTypeVariables #-}
module MCL.Internal.Prim.Pinned where
import Data.Functor.Identity
import Data.Primitive.ByteArray
import Foreign.C.Types
import GHC.Exts
import System.IO.Unsafe
import MCL.Internal.Prim.Class
import MCL.Internal.Utils
-- | Pass pinned copy of the object to a safe C function.
{-# INLINABLE withPrimPinned #-}
withPrimPinned :: Prim t => t -> (CC t -> IO r) -> IO r
withPrimPinned fp k = do
ByteArray ba <- pinnedByteArrayCopy $ ByteArray (prim_unwrap fp)
k ba
where
pinnedByteArrayCopy :: ByteArray -> IO ByteArray
pinnedByteArrayCopy src = do
mdest <- newPinnedByteArray srcSize
copyByteArray mdest 0 src 0 srcSize
unsafeFreezeByteArray mdest
where
srcSize = sizeofByteArray src
-- | Use pinned memory to get a result from a safe C function.
{-# INLINABLE newPrimPinned #-}
newPrimPinned
:: forall m t r. Prim t
=> (r -> CC t -> m t)
-> (MC t -> IO r)
-> IO (m t)
newPrimPinned = withPinnedByteArray1 (prim_size (proxy# :: Proxy# t))
{-# INLINABLE newPrimPinned_ #-}
newPrimPinned_ :: forall t. Prim t => (MC t -> IO ()) -> IO t
newPrimPinned_ = unwrap . newPrimPinned (\_ ba -> Identity (prim_wrap ba))
where
unwrap :: IO (Identity t) -> IO t
unwrap = coerce
{-# INLINABLE maybeNewPrimPinned #-}
maybeNewPrimPinned :: Prim t => (MC t -> IO CInt) -> IO (Maybe t)
maybeNewPrimPinned = newPrimPinned $ \success ba ->
if cintToBool success
then Just (prim_wrap ba)
else Nothing
----------------------------------------
{-# INLINABLE safeOp0 #-}
safeOp0 :: IO r -> r
safeOp0 = unsafeDupablePerformIO
{-# INLINABLE safeOp1 #-}
safeOp1
:: Prim t
=> (s -> IO r)
-> (CC t -> s)
-> (t -> r)
safeOp1 k c_fun fa =
safeOp0 . withPrimPinned fa $ \a -> k (c_fun a)
{-# INLINABLE safeOp1_ #-}
safeOp1_
:: (Prim t, Prim r)
=> (CC t -> MC r -> IO ())
-> (t -> r)
safeOp1_ = safeOp1 newPrimPinned_
{-# INLINABLE safeOp2 #-}
safeOp2
:: (Prim t1, Prim t2)
=> (s -> IO r)
-> (CC t1 -> CC t2 -> s)
-> (t1 -> t2 -> r)
safeOp2 k c_fun fa fb =
safeOp0 . withPrimPinned fa $ \a -> withPrimPinned fb $ \b -> k (c_fun a b)
{-# INLINABLE safeOp2_ #-}
safeOp2_
:: (Prim t1, Prim t2, Prim r)
=> (CC t1 -> CC t2 -> MC r -> IO ())
-> (t1 -> t2 -> r)
safeOp2_ = safeOp2 newPrimPinned_
----------------------------------------
-- Utils
{-# INLINABLE withPinnedByteArray1 #-}
withPinnedByteArray1
:: Int
-> (s -> ByteArray# -> r)
-> (MutableByteArray# RealWorld -> IO s)
-> IO r
withPinnedByteArray1 size k c_fun = do
mba@(MutableByteArray umba) <- newPinnedByteArray size
r <- c_fun umba
ByteArray uba <- unpinnedFreezeByteArray mba
return (k r uba)
where
unpinnedFreezeByteArray :: MutableByteArray RealWorld -> IO ByteArray
unpinnedFreezeByteArray src = do
mdest <- newByteArray srcSize
copyMutableByteArray mdest 0 src 0 srcSize
unsafeFreezeByteArray mdest
where
srcSize = sizeofMutableByteArray src