packages feed

gpu-vulkan-middle-0.1.0.77: src/Gpu/Vulkan/AllocationCallbacks/Middle/Internal.hs

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE BlockArguments, LambdaCase #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE DataKinds #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Gpu.Vulkan.AllocationCallbacks.Middle.Internal (

	-- * CREATE AND DESTROY

	create, destroy, Functions, FunctionsInfo(..),

	-- ** Function Types

	FnAllocationFunction, FnReallocationFunction, C.FnFreeFunction,
	FnInternalAllocationNotification, FnInternalFreeNotification,

	-- *** size and alignment

	Size, Alignment,

	-- * APPLY

	apply, A,

	-- * INTERNAL USE

	mToCore, MFromCore(..)

	) where

import Foreign.Marshal.Alloc
import Foreign.Ptr
import Foreign.Storable
import Foreign.Storable.PeekPoke
import Control.Monad
import Data.TypeLevel.ParMaybe qualified as TPMaybe
import Data.Word

import Gpu.Vulkan.Enum
import Gpu.Vulkan.AllocationCallbacks.Core qualified as C

newtype A a = A C.A deriving Show

data Functions a = Functions {
	aPfnAllocation :: C.PfnAllocationFunction,
	aPfnReallocation :: C.PfnReallocationFunction,
	aPfnFree :: C.PfnFreeFunction,
	aPfnInternalAllocation :: C.PfnInternalAllocationNotification,
	aPfnInternalFree :: C.PfnInternalFreeNotification }
	deriving Show

apply :: Functions a -> Ptr a -> A a
apply a p = A C.A {
	C.aPUserData = castPtr p,
	C.aPfnAllocation = aPfnAllocation a,
	C.aPfnReallocation = aPfnReallocation a,
	C.aPfnFree = aPfnFree a,
	C.aPfnInternalAllocation = aPfnInternalAllocation a,
	C.aPfnInternalFree = aPfnInternalFree a }

create :: FunctionsInfo a -> IO (Functions a)
create = mkCallbacksNew

destroy :: Functions a -> IO ()
destroy a = do
	freeHaskellFunPtr allc
	freeHaskellFunPtr rallc
	freeHaskellFunPtr fr
	when (iallc /= nullFunPtr) $ freeHaskellFunPtr iallc
	when (ifr /= nullFunPtr) $ freeHaskellFunPtr ifr
	where
	allc = aPfnAllocation a
	rallc = aPfnReallocation a
	fr = aPfnFree a
	iallc = aPfnInternalAllocation a
	ifr = aPfnInternalFree a

data FunctionsInfo a = FunctionsInfo {
	functionsInfoFnAllocation :: FnAllocationFunction a,
	functionsInfoFnReallocation :: FnReallocationFunction a,
	functionsInfoFnFree :: C.FnFreeFunction a,
	functionsInfoFnInternalAllocationFree :: Maybe (
		FnInternalAllocationNotification a,
		FnInternalFreeNotification a ) }

type Size = Word64
type Alignment = Word64

type FnAllocationFunction a =
	Ptr a -> Size -> Alignment -> SystemAllocationScope -> IO (Ptr ())

fnAllocationFunctionToCore :: FnAllocationFunction a -> C.FnAllocationFunction a
fnAllocationFunctionToCore f pud sz algn ascp =
	f pud sz algn (SystemAllocationScope ascp)

type FnReallocationFunction a = Ptr a ->
	Ptr () -> Size -> Alignment -> SystemAllocationScope -> IO (Ptr ())

fnReallocationFunctionToCore ::
	FnReallocationFunction a -> C.FnReallocationFunction a
fnReallocationFunctionToCore f pud po sz algn ascp =
	f pud po sz algn (SystemAllocationScope ascp)

type FnInternalAllocationNotification a = Ptr a ->
	Size -> InternalAllocationType -> SystemAllocationScope -> IO ()

fnInternalAllocationNotificationToCore ::
	FnInternalAllocationNotification a ->
	C.FnInternalAllocationNotification a
fnInternalAllocationNotificationToCore f pud sz iatp ascp =
	f pud sz (InternalAllocationType iatp) (SystemAllocationScope ascp)

type FnInternalFreeNotification a = Ptr a ->
	Size -> InternalAllocationType -> SystemAllocationScope -> IO ()

fnInternalFreeNotificationToCore ::
	FnInternalFreeNotification a -> C.FnInternalFreeNotification a
fnInternalFreeNotificationToCore f pud sz iatp ascp =
	f pud sz (InternalAllocationType iatp) (SystemAllocationScope ascp)

mToCore :: TPMaybe.M A ma -> (Ptr C.A -> IO b) -> IO ()
mToCore = TPMaybe.maybe ((() <$) . ($ NullPtr)) toCoreNew

toCoreNew :: A a -> (Ptr C.A -> IO b) -> IO ()
toCoreNew (A ac) f = () <$ alloca \p -> poke p ac >> f p

fromCore :: Ptr C.A -> IO (A a)
fromCore pa = A <$> peek pa

class MFromCore ma where
	mFromCore :: Ptr C.A -> IO (TPMaybe.M A ma)

instance MFromCore 'Nothing where
	mFromCore pa
		| pa == nullPtr = pure TPMaybe.N
		| otherwise =
			error "AllocationCallbacks pointer should be nullPtr"

instance MFromCore ('Just a) where
	mFromCore pa
		| pa == nullPtr = error
			"AllocationCallbacks pointer should not be nullPtr"
		| otherwise = TPMaybe.J <$> fromCore pa

mkCallbacksNew :: FunctionsInfo a -> IO (Functions a)
mkCallbacksNew ac = do
	pal <- C.wrapAllocationFunction $ fnAllocationFunctionToCore al
	pral <- C.wrapReallocationFunction $ fnReallocationFunctionToCore ral
	pfr <- C.wrapFreeFunction fr
	(pial, pifr) <- do
		case functionsInfoFnInternalAllocationFree ac of
			Nothing -> pure (nullFunPtr, nullFunPtr)
			Just (ial, ifr) -> do
				wal <- C.wrapInternalAllocationNotification
					$ fnInternalAllocationNotificationToCore ial
				wfr <- C.wrapInternalFreeNotification
					$ fnInternalFreeNotificationToCore ifr
				pure (wal, wfr)
	pure Functions {
		aPfnAllocation = pal,
		aPfnReallocation = pral,
		aPfnFree = pfr,
		aPfnInternalAllocation = pial,
		aPfnInternalFree = pifr }
	where
	al = functionsInfoFnAllocation ac
	ral = functionsInfoFnReallocation ac
	fr = functionsInfoFnFree ac