packages feed

hgrib-0.2.0.0: src/Data/Grib/Raw/Marshal.hs

{-
Module      : Data.Grib.Raw.Marshal
Copyright   : (c) Mattias Jakobsson 2015
License     : GPL-3

Maintainer  : mjakob422@gmail.com
Stability   : unstable
Portability : portable

Functions to marshal parameters between C and Haskell.
-}

module Data.Grib.Raw.Marshal
       ( module Data.Grib.Raw.Types

       , checkStatus
       , checkStatusPtr
       , fromFlagList
       , maybeWithCString
       , peekIntegral
       , peekIntegralArray
       , peekReal
       , peekRealArray
       , withIntegral
       , withIntegralArrayLen
       , withJoinedCString
       , withRealArrayLen

       , checkForeignPtr
       , getArray
       ) where

import Control.Exception ( throw, throwIO )
import Control.Monad     ( (>=>) )
import Data.List         ( intercalate )
import Foreign           ( FinalizerPtr, ForeignPtr, Ptr, Storable, (.|.), bit
                         , clearBit, maybeWith, newForeignPtr, nullPtr, peek
                         , peekArray, with, withArrayLen )
import Foreign.C         ( CInt, CString, withCString )

import Data.Grib.Raw.Exception
import Data.Grib.Raw.Types


checkStatus :: CInt -> IO ()
checkStatus 0      = return ()
checkStatus status = throwIO . GribException . toEnum . fromIntegral $ status

checkStatusPtr :: Ptr CInt -> IO ()
checkStatusPtr = peek >=> checkStatus

fromFlagList :: (Enum a, Integral b) => [a] -> b
fromFlagList = fromIntegral . foldr ((.|.) . fromEnum) zeroBits'
  -- Data.Bits.zeroBits is only available since base 4.7.0.0.
  where zeroBits' = clearBit (bit 0) 0

maybeWithCString :: Maybe String -> (CString -> IO a) -> IO a
maybeWithCString = maybeWith withCString

peekIntegral :: (Integral a, Storable a, Num b) => Ptr a -> IO b
peekIntegral = fmap fromIntegral . peek

peekIntegralArray :: (Integral a, Storable a, Num b) => Int -> Ptr a -> IO [b]
peekIntegralArray n = fmap (map fromIntegral) . peekArray n

peekReal :: (Real a, Storable a, Fractional b) => Ptr a -> IO b
peekReal = fmap realToFrac . peek

peekRealArray :: (Real a, Storable a, Fractional b) => Int -> Ptr a -> IO [b]
peekRealArray n = fmap (map realToFrac) . peekArray n

withIntegral :: (Integral a, Num b, Storable b) => a -> (Ptr b -> IO c) -> IO c
withIntegral = with . fromIntegral

withIntegralArrayLen :: (Integral a, Num b, Storable b, Num c)
                     => [a] -> ((Ptr b, c) -> IO d) -> IO d
withIntegralArrayLen xs f =
  withArrayLen (map fromIntegral xs) $ \n xs' -> f (xs', fromIntegral n)

withJoinedCString :: [String] -> (CString -> IO a) -> IO a
withJoinedCString ss = withCString (intercalate "," ss)

withRealArrayLen :: (Real a, Fractional b, Storable b, Num c)
                 => [a] -> ((Ptr b, c) -> IO d) -> IO d
withRealArrayLen xs f =
  withArrayLen (map realToFrac xs) $ \n xs' -> f (xs', fromIntegral n)


checkForeignPtr :: (ForeignPtr a -> a) -> FinalizerPtr a -> Ptr a -> IO a
checkForeignPtr makeA finalizer p
  | p == nullPtr = throw NullPtrReturned
  | otherwise    = fmap makeA $ newForeignPtr finalizer p

getArray :: (Storable a, Integral b, Storable b)
         => (CString -> Ptr a -> Ptr b -> IO CInt)
         -> Key -> Ptr a -> Int -> IO [a]
getArray cCall key xs n =
  withCString key $ \key' -> with (fromIntegral n) $ \n' -> do
    cCall key' xs n' >>= checkStatus
    fmap fromIntegral (peek n') >>= flip peekArray xs