packages feed

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

{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE KindSignatures #-}

module MacSdk.Framework.CoreFoundation.Number
  ( CFNumberRef
  , Number
  , NumberType(..)
  , numberCreateWithAllocator
  , numberCreate
  , numberGetValue
  ) where

import Control.Monad.Managed
import Control.Monad.IO.Class (MonadIO(..))
import Foreign hiding (with)
import Foreign.C.Types (CInt(..), CBool(..))
import MacSdk.Framework.CoreFoundation.Allocator
import MacSdk.Framework.CoreFoundation.Object

data CFNumber
type CFNumberRef = Ptr CFNumber
instance CFClass CFNumber
type Number = Object CFNumber

type CFNumberType = CInt

data NumberType :: * -> * where
  NumberSigned64Type :: NumberType Int64
  NumberLongType :: NumberType Int64
  NumberIntType :: NumberType Int32
  NumberSInt32Type :: NumberType Int32

storableTy :: NumberType ty -> (Storable ty => b) -> b
storableTy NumberSigned64Type f = f
storableTy NumberLongType f = f
storableTy NumberIntType f = f
storableTy NumberSInt32Type f = f

toCFNumberType :: NumberType ty -> CFNumberType
toCFNumberType NumberSigned64Type = 4
toCFNumberType NumberIntType = 9
toCFNumberType NumberLongType = 10
toCFNumberType NumberSInt32Type = 3

--------------------------------------------------------------------------------

foreign import ccall unsafe "CFNumberCreate"
  cfNumberCreate :: CFAllocatorRef -> CFNumberType -> Ptr a -> IO CFNumberRef

numberCreateWithAllocator :: Allocator -> NumberType ty -> ty -> IO Number
numberCreateWithAllocator allo nty num = flip with pure $ do
  allo' <- managed (withCFPtr allo)
  storableTy nty $ do
    p <- managed alloca
    liftIO $ do
      poke p num
      num' <- cfNumberCreate allo' (toCFNumberType nty) p
      manageCFObj num'

numberCreate :: NumberType ty -> ty -> IO Number
numberCreate nty num = nullAllocator >>= \a -> numberCreateWithAllocator a nty num

--------------------------------------------------------------------------------

foreign import ccall unsafe "CFNumberGetValue"
  cfNumberGetValue :: CFNumberRef -> CFNumberType -> Ptr a -> IO CBool

numberGetValue :: MonadIO m => Number -> NumberType ty -> m (Maybe ty)
numberGetValue num nty = liftIO $ flip with pure $ do
  nptr <- managed (withCFPtr num)
  storableTy nty $ do
    p <- managed alloca
    liftIO $ do
      b <- cfNumberGetValue nptr (toCFNumberType nty) p
      if toBool b then Just <$> peek p else pure Nothing