packages feed

clr-host-0.2.0: src/Clr/Host/Delegate.hs

module Clr.Host.Delegate where

import Clr.Host.BStr
import Clr.Host.GCHandle
import Clr.Host.DriverEntryPoints

import Clr.Marshal

import Data.Kind
import Foreign.Ptr

-- | @'getDelegateConstructorStub' dt wrapper@ returns an action that, given a
--   function, will return a reference to a .NET delegate object that calls the
--   provided function.  The delegate constructed will be of the type @dt@.
--   The function @wrapper@ will be called in order to wrap the given function
--   as a function pointer for passing into .NET.
getDelegateConstructorStub :: String -> (f -> IO (FunPtr f)) -> IO (f -> IO (GCHandle t))
getDelegateConstructorStub delegateTypeName wrapper = do
  -- Obtain a function pointer to a function that, when called with a
  -- function pointer compatible with the given wrapper function, returns
  -- a reference to a .NET delegate object that calls the function.
  delegateConstructor <- marshal delegateTypeName $
    \delegateTypeName' -> getDelegateConstructorStubRaw >>= \x-> x delegateTypeName'

  -- Returns a function that accepts a function, 'f' implementing the
  -- delegate, converts 'f' to a function pointer, and then wraps it
  -- up as a .NET delegate.
  return $ \f -> do
    fFunPtr <- wrapper f
    (makeDelegateConstructor delegateConstructor) fFunPtr

getDelegateConstructorStubRaw :: IO (GetDelegateConstructorStubDelegate f t)
getDelegateConstructorStubRaw =  unsafeGetPointerToMethod "GetDelegateConstructorStub" >>= return . makeGetDelegateConstructorStubDelegate

type GetDelegateConstructorStubDelegate f t = BStr -> IO (FunPtr (DelegateConstructor f t))
foreign import ccall "dynamic" makeGetDelegateConstructorStubDelegate :: FunPtr (GetDelegateConstructorStubDelegate f t) -> (GetDelegateConstructorStubDelegate f t)

type DelegateConstructor f t = FunPtr f -> IO (GCHandle t)
foreign import ccall "dynamic" makeDelegateConstructor :: FunPtr (DelegateConstructor f t) -> (DelegateConstructor f t)