module Bindings.Utilities ( GlobalVariable, writeGlobalVariable, readGlobalVariable, Callback(..) ) where import Foreign import Foreign.C import Data.Int -- | Haskell FFI imports global variables as pointers. To -- ease manipulation of such pointers they are encapsulated -- by 'GlobalVariable' so that values can be reached -- directly, much like in an "Data.IORef". newtype (Storable a) => GlobalVariable a = GlobalVariable (Ptr a) writeGlobalVariable :: (Storable a) => GlobalVariable a -> a -> IO () writeGlobalVariable (GlobalVariable p) v = poke p v readGlobalVariable :: (Storable a) => GlobalVariable a -> IO a readGlobalVariable (GlobalVariable p) = peek p -- | When libraries provide types for functions those -- types are made instances of class 'Callback'. That -- class is used to exchange between Haskell functions -- and a representation (i.e., a hidden pointer) that -- can be used or is provided by foreign code. class (Storable cb) => Callback cb where -- | The associated type is the function type -- as it is used in Haskell. type F cb :: * -- | 'nullCallback' can be used like 'Foreign.Ptr.nullFunPtr'. nullCallback :: cb -- | 'makeCallback' takes a Haskell function and -- gives a representation of it in the form of the -- type expected by foreign code. makeCallback :: F cb -> IO cb -- | 'freeCallback' should be called on all values returned -- by 'makeCallback' after they are no longer going to be -- used. Most of the time this class method will just use -- 'Foreign.Ptr.freeHaskellFunPtr'. freeCallback :: cb -> IO () -- | 'withCallback' just inserts an action between -- calls to 'makeCallback' and 'freeCallback'. -- Of course, it can't be used when foreign code -- will save such action for latter use. withCallback :: F cb -> (cb -> IO a) -> IO a withCallback f c = do made <- makeCallback f result <- c made freeCallback made return result