packages feed

gpu-vulkan-middle-0.1.0.54: src/Gpu/Vulkan/PNext/Middle/Internal.hs

{-# LANGUAGE ImportQualifiedPost #-}
{-# LANGUAGE BlockArguments #-}
{-# LANGUAGE ScopedTypeVariables, TypeApplications #-}
{-# LANGUAGE MonoLocalBinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE KindSignatures, TypeOperators #-}
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE FlexibleContexts, FlexibleInstances, UndecidableInstances #-}
{-# LANGUAGE PatternSynonyms #-}
{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Gpu.Vulkan.PNext.Middle.Internal (

	-- * STRUCT COMMON

	StructCommon(..), structCommonFromCore,

	-- * SET AND READ CHAIN

	Typeable(..), FindChainAll(..), ReadChain(..), Nextable(..)

	) where

import Foreign.Ptr
import Foreign.Marshal.Alloc
import Foreign.Storable
import Foreign.Storable.PeekPoke
import Data.Kind
import Data.HeteroParList (pattern (:**))
import Data.HeteroParList qualified as HPList

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

import Data.TypeLevel.Maybe qualified as TMaybe

-- STRUCT COMMON

data StructCommon = StructCommon {
	structCommonSType :: StructureType, structCommonPNext :: Ptr () }
	deriving Show

instance Peek StructCommon where
	peek' p = structCommonFromCore <$> peek (castPtr p)

instance Poke StructCommon where
	poke' p = poke (castPtr p) . structCommonToCore

structCommonFromCore :: C.StructCommon -> StructCommon
structCommonFromCore C.StructCommon {
	C.structCommonSType = stp, C.structCommonPNext = pn } = StructCommon {
	structCommonSType = StructureType stp, structCommonPNext = pn }

structCommonToCore :: StructCommon -> C.StructCommon
structCommonToCore StructCommon {
	structCommonSType = StructureType stp,
	structCommonPNext = pn } = C.StructCommon {
	C.structCommonSType = stp, C.structCommonPNext = pn }

-- TYPEABLE

class Peek n => Typeable n where structureType :: StructureType

-- FIND PNEXT CHAIN ALL

class FindChainAll ns where findChainAll :: Ptr () -> IO (HPList.PL Maybe ns)

instance FindChainAll '[] where findChainAll _ = pure HPList.Nil

instance (Typeable n, FindChainAll ns) => FindChainAll (n ': ns) where
	findChainAll p = (:**) <$> findChain p <*> findChainAll p

findChain :: forall n . Typeable n => Ptr () -> IO (Maybe n)
findChain NullPtr = pure Nothing
findChain p = peek' (castPtr p) >>= \sc ->
	if structCommonSType sc == structureType @n
		then Just <$> peek' (castPtr p)
		else findChain $ structCommonPNext sc

-- READ CHAIN

class ReadChain mn where
	clearedChain :: (Ptr () -> IO a) -> IO a
	readChain :: Ptr () -> IO (TMaybe.M mn)

instance ReadChain 'Nothing where
	clearedChain = ($ nullPtr); readChain _ = pure TMaybe.N

instance (Nextable n, ReadChain mnn) => ReadChain ('Just (n (mnn))) where
	clearedChain f = clearedChain @mnn \np -> do
		p <- callocBytes $ nextableSize @n
		poke' p StructCommon {
			structCommonSType = nextableType @n,
			structCommonPNext = np }
		f (castPtr p) <* free p
	readChain p =
		TMaybe.J <$> (createNextable p =<< readChain =<< nextPtr @n p)
	
class Nextable (n :: Maybe Type -> Type) where
	nextableSize :: Int
	nextableType :: StructureType; nextPtr :: Ptr () -> IO (Ptr ())
	createNextable :: Ptr () -> TMaybe.M mn' -> IO (n mn')