{-# LANGUAGE CPP #-}

module WGPU.Raw.Dynamic
  ( -- * Functions
    withWGPU,
  )
where

import WGPU.Raw.Generated.Fun (WGPUHsInstance, loadDynamicInstance)

#ifdef WGPUHS_UNIX
import System.Posix.DynamicLinker (withDL, dlsym)

-- | Load WGPU from a dynamic library and run a program using an instance.
withWGPU ::
  -- | Path to the wgpu-native dynamic library to load.
  FilePath ->
  -- | IO action using an instance of the WGPUHsInstance.
  (WGPUHsInstance -> IO a) ->
  -- | Completed IO action.
  IO a
withWGPU :: FilePath -> (WGPUHsInstance -> IO a) -> IO a
withWGPU FilePath
dynlibFile WGPUHsInstance -> IO a
action = do
  FilePath -> [RTLDFlags] -> (DL -> IO a) -> IO a
forall a. FilePath -> [RTLDFlags] -> (DL -> IO a) -> IO a
withDL FilePath
dynlibFile [] ((DL -> IO a) -> IO a) -> (DL -> IO a) -> IO a
forall a b. (a -> b) -> a -> b
$ \DL
dl -> (forall a. FilePath -> IO (FunPtr a)) -> IO WGPUHsInstance
loadDynamicInstance (DL -> FilePath -> IO (FunPtr a)
forall a. DL -> FilePath -> IO (FunPtr a)
dlsym DL
dl) IO WGPUHsInstance -> (WGPUHsInstance -> IO a) -> IO a
forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= WGPUHsInstance -> IO a
action
#endif

#ifdef WGPUHS_WINDOWS
import Foreign (FunPtr, castPtrToFunPtr)
import System.Win32.DLL (loadLibrary, freeLibrary, getProcAddress)

-- | Load WGPU from a dynamic library and run a program using an instance.
withWGPU ::
  -- | Path to the wgpu-native dynamic library to load.
  FilePath ->
  -- | IO action using an instance of the WGPUHsInstance.
  (WGPUHsInstance -> IO a) ->
  -- | Completed IO action.
  IO a
withWGPU dynlibFile action = do
  -- TODO: safer bracketing
  hInstance <- loadLibrary dynlibFile
  let load :: String -> IO (FunPtr a)
      load = fmap castPtrToFunPtr . getProcAddress hInstance
  wgpuHsInstance <- loadDynamicInstance load
  result <- action wgpuHsInstance
  freeLibrary hInstance
  pure result
#endif