----------------------------------------------------------- -- | -- module: C2HS.C.Extra.Marshal -- copyright: (c) 2016 Tao He -- license: MIT -- maintainer: sighingnow@gmail.com -- -- Convenient marshallers for complicate C types. -- {-# LANGUAGE CPP #-} #if __GLASGOW_HASKELL__ >= 709 {-# LANGUAGE Safe #-} #elif __GLASGOW_HASKELL__ >= 701 {-# LANGUAGE Trustworthy #-} #endif module C2HS.C.Extra.Marshal ( peekIntegral , peekString , peekStringArray , withStringArray , peekIntegralArray , withIntegralArray ) where import Foreign.C.String ( peekCString, withCString ) import Foreign.C.Types ( CChar, CInt, CUInt ) import Foreign.Marshal.Array ( peekArray, withArray ) import Foreign.Ptr ( Ptr, nullPtr ) import Foreign.Storable ( Storable, peek ) -- | Peek from pointer then cast to another integral type. peekIntegral :: (Integral a, Storable a, Integral b) => Ptr a -> IO b peekIntegral p = if p == nullPtr then return 0 else fromIntegral <$> peek p {-# SPECIALIZE peekIntegral :: Ptr CInt -> IO Int #-} -- | Peek string from a two-dimension pointer of CChar. peekString :: Ptr (Ptr CChar) -> IO String peekString p = if p == nullPtr then return "" else peek p >>= \p' -> if p' == nullPtr then return "" else peekCString p' -- | Peek an array of String and the result's length is given. peekStringArray :: Integral n => n -> Ptr (Ptr CChar) -> IO [String] peekStringArray 0 _ = return [] peekStringArray n p = if p == nullPtr then return [] else peekArray (fromIntegral n) p >>= mapM (\p' -> if p' == nullPtr then return "" else peekCString p') {-# SPECIALIZE peekStringArray :: Int -> Ptr (Ptr CChar) -> IO [String] #-} {-# SPECIALIZE peekStringArray :: CUInt -> Ptr (Ptr CChar) -> IO [String] #-} -- | Use an array of String as argument, usually used to pass multiple names to C -- functions. withStringArray :: [String] -> (Ptr (Ptr CChar) -> IO a) -> IO a withStringArray [] f = f nullPtr withStringArray ss f = do ps <- mapM (\s -> withCString s return) ss withArray ps f -- | Peek an array of integral values and the result's length is given. peekIntegralArray :: (Integral n, Integral m, Storable m) => Int -> Ptr m -> IO [n] peekIntegralArray n p = (map fromIntegral) <$> peekArray n p {-# SPECIALIZE peekIntegralArray :: Int -> Ptr CInt -> IO [Int] #-} {-# SPECIALIZE peekIntegralArray :: Int -> Ptr CUInt -> IO [Int] #-} -- | Use an array of Integral as argument. withIntegralArray :: (Integral a, Integral b, Storable b) => [a] -> (Ptr b -> IO c) -> IO c withIntegralArray ns f = do let ns' = fmap fromIntegral ns withArray ns' f {-# SPECIALIZE withIntegralArray :: [Int] -> (Ptr CInt -> IO c) -> IO c #-} {-# SPECIALIZE withIntegralArray :: [CInt] -> (Ptr CInt -> IO c) -> IO c #-} {-# SPECIALIZE withIntegralArray :: [CUInt] -> (Ptr CUInt -> IO c) -> IO c #-}