packages feed

macos-corelibs-0.0.1.0: src/MacSdk/Framework/CoreFoundation/Array.hs

module MacSdk.Framework.CoreFoundation.Array
  ( CFArrayRef
  , CFIndex
  , Array(..)
  , createArray
  , createArray'
  , arrayValues
  , getCFArrayValues
  ) where

import MacSdk.Framework.CoreFoundation.Object
import MacSdk.Framework.CoreFoundation.Allocator
import Foreign.Ptr
import Foreign hiding (with)
import Foreign.C.Types (CInt(..))
import Control.Monad
import Control.Monad.Managed
import Data.Foldable

data CFArray
type CFArrayRef = Ptr CFArray
instance CFClass CFArray
newtype Array a = Array { getArray :: Object CFArray }
instance Functor Array where
  fmap _ (Array a) = Array a

type CFIndex = CInt

foreign import ccall unsafe "Carbon/Carbon.h CFArrayGetValueAtIndex"
  cf_array_get_value_at_index :: CFArrayRef -> CFIndex -> IO (Ptr ())

foreign import ccall unsafe "Carbon/Carbon.h CFArrayGetCount"
  cf_array_get_count :: CFArrayRef -> IO CFIndex

getCFArrayValues :: CFArrayRef -> IO [CFTypeRef]
getCFArrayValues arr = do
  n <- cf_array_get_count arr
  ptrs <- forM [0.. (n-1)] (cf_array_get_value_at_index arr)
  pure (fmap castPtr ptrs)

arrayValues :: (MonadIO m, CFClass a) => Array (Object a) -> m [Object a]
arrayValues arr = liftIO . withCFPtr (getArray arr) $ \cfarr ->
  getCFArrayValues cfarr >>= mapM retainManageCFObj . fmap castPtr

--------------------------------------------------------------------------------
-- Array creation

data ArrayCallbacks

foreign import ccall cfCallbs :: Ptr ArrayCallbacks

foreign import ccall "CFArrayCreate"
  cfArrayCreate :: CFAllocatorRef -> Ptr CFTypeRef -> CFIndex
                -> Ptr ArrayCallbacks -> IO CFArrayRef

-- | Create an array from a denumerable collection of Core Foundation objects,
-- using the specified allocator.
createArray :: (Foldable f, CFClass a) => Allocator -> f (Object a) -> IO (Array (Object a))
createArray allo objs = fmap Array . flip with pure $ do
  allo' <- managed (withCFPtr allo)
  objs' <- managed (withMany withCFPtr (toList objs))
  liftIO $ do
    arr <- newArray (fmap asCFType objs')
    cfArrayCreate allo' arr (fromIntegral (length objs')) cfCallbs
      >>= manageCFObj

-- | Create an array from a denumerable collection of Core Foundation objects,
-- using the default allocator.
createArray' :: (Foldable f, CFClass a) => f (Object a) -> IO (Array (Object a))
createArray' objs = nullAllocator >>= flip createArray objs