{-# LANGUAGE ForeignFunctionInterface #-} module Test.HTestU.Wrapping ( Battery , WrappedCallback , c_createGenerator , c_deleteGenerator , genToWrappedCallback , streamToWrappedCallback , randomStreamActionToWrappedCallback ) where import System.Random (RandomGen) import Data.IORef (IORef, newIORef, readIORef, writeIORef) import Foreign.Ptr (Ptr, FunPtr) import Foreign.C.Types (CUInt(..)) import Foreign.Marshal.Array (pokeArray) import Test.HTestU.Streaming (RandomStream) import Test.HTestU.BatteryResult (BatteryResultStruct(..)) -- | A token type of a C structure of a PRNG, is not used directly data UniformGenerator -- | Result of running a battery - IO action giving the caller a C struct with -- resulting p-values describing the results of run tests type BatteryResult = IO (Ptr BatteryResultStruct) -- | Battery takes a wrapped generator and produces p-values as a result of its testing type Battery = Ptr UniformGenerator -> BatteryResult -- | Function which fills the array with numbers -- given size and a pointer to it type Callback = CUInt -> Ptr CUInt -> IO () -- | Wrapped 'Callback' function for calling from C type WrappedCallback = FunPtr Callback -- | C function allocating a PRNG on C side, given a callback wrapping it foreign import ccall safe "unif01_CreateExternGenBits" c_createGenerator :: WrappedCallback -> IO (Ptr UniformGenerator) -- | Complimentary deallocating function to 'c_createGenerator' foreign import ccall unsafe "unif01_DeleteExternGenBits" c_deleteGenerator :: Ptr UniformGenerator -> IO () -- | Wrapper function for porting callback to C foreign import ccall unsafe "wrapper" mkCallback :: Callback -> IO WrappedCallback -- | Wraps the given RandomGen into a C callback genToWrappedCallback :: RandomGen g => (g -> RandomStream) -> g -> IO WrappedCallback genToWrappedCallback streamer gen = streamToWrappedCallback $ streamer gen -- | Wraps an stream of numbers into a C callback streamToWrappedCallback :: RandomStream -> IO WrappedCallback streamToWrappedCallback stream = newIORef stream >>= mkCallback . nextIntFromStreamRef -- | Wraps an stream of numbers produced by a stream of numbers into a C callback randomStreamActionToWrappedCallback :: IO RandomStream -> IO WrappedCallback randomStreamActionToWrappedCallback action = action >>= streamToWrappedCallback -- | Takes an allocated reference to a stream of numbers produces a Callback -- for passing to C code nextIntFromStreamRef :: IORef RandomStream -> Callback nextIntFromStreamRef streamRef (CUInt values) arrayPtr = do randomNumbers <- readIORef streamRef let (toDump, rest) = splitAt (fromIntegral values) randomNumbers writeIORef streamRef rest pokeArray arrayPtr $ map fromIntegral toDump