packages feed

cinvoke-0.1: Foreign/TreePtr.hs

{- | No Child Left Behind -
    Pointers that won't be freed until all its children have been freed -}
module Foreign.TreePtr (
    TreePtr,
    newTreePtr,
    addNode,
    addLeaf,
    nodePtr,
    withTreePtr,
) where

import Control.Monad
import Foreign.Ptr
import Foreign.ForeignPtr hiding (newForeignPtr, addForeignPtrFinalizer)
import Foreign.Concurrent

import Data.RefCount

data TreePtr a = TreePtr !RefCount !(ForeignPtr a)

instance Show (TreePtr a) where
    showsPrec p (TreePtr _ fp) = showsPrec p fp

newTreePtr :: Ptr a -> IO () -> IO (TreePtr a)
newTreePtr ptr free = do
    refCnt <- newRefCount free
    liftM (TreePtr refCnt)
        $ newForeignPtr ptr
            $ decRefCount refCnt

addWith f ptr free (TreePtr refCnt _) = do
    incRefCount refCnt
    f ptr $ do
        free
        decRefCount refCnt

addNode :: Ptr a -> IO () -> TreePtr b -> IO (TreePtr a)
addNode = addWith newTreePtr

addLeaf :: Ptr a -> IO () -> TreePtr b -> IO (ForeignPtr a)
addLeaf = addWith newForeignPtr

nodePtr :: TreePtr a -> ForeignPtr a
nodePtr (TreePtr _ fp) = fp

withTreePtr :: TreePtr a -> (Ptr a -> IO b) -> IO b
withTreePtr = withForeignPtr . nodePtr