-- | Arguments and return types

module Foreign.LibFFI.Types (
    -- * Arguments

    -- ** Integral types

    argCInt,
    argCUInt,
    argCLong,
    argCULong,
    argInt8,
    argInt16,
    argInt32,
    argInt64,
    argWord8,
    argWord16,
    argWord32,
    argWord64,
    -- ** Floating point types

    argCFloat,
    argCDouble,
    -- ** Various other C types

    argCSize,
    argCTime,
    argCChar,
    argCUChar,
    argCWchar,
    argPtr,
    argFunPtr,
    -- ** Strings

    argString,
    argByteString,
    argConstByteString,
    -- * Return types

    -- ** Integral types

    retVoid,
    retCInt,
    retCUInt,
    retCLong,
    retCULong,
    retInt8,
    retInt16,
    retInt32,
    retInt64,
    retWord8,
    retWord16,
    retWord32,
    retWord64,
    -- ** Floating point types

    retCFloat,
    retCDouble,
    -- ** Various other C types

    retCSize,
    retCTime,
    retCChar,
    retCUChar,
    retCWchar,
    retPtr,
    retFunPtr,
    -- ** Strings

    retCString,
    retString,
    retByteString,
    retMallocByteString
    ) where

import Control.Monad
import Data.List
import Data.Char
import Data.Int
import Data.Word

import Foreign.C.Types
import Foreign.Ptr
import Foreign.Storable
import Foreign.C.String
import Foreign.Marshal
import qualified Data.ByteString as BS
import qualified Data.ByteString.Unsafe as BSU

import Foreign.LibFFI.Base
import Foreign.LibFFI.FFITypes

argCInt     :: CInt -> Arg
argCInt :: CInt -> Arg
argCInt     = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_sint
argCUInt    :: CUInt -> Arg
argCUInt :: CUInt -> Arg
argCUInt    = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_uint
argCLong    :: CLong -> Arg
argCLong :: CLong -> Arg
argCLong    = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_slong
argCULong   :: CULong -> Arg
argCULong :: CULong -> Arg
argCULong   = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_ulong

-- | Note that on e.g. x86_64, Int \/= CInt

argInt8     :: Int8 -> Arg
argInt8 :: Int8 -> Arg
argInt8     = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_sint8
argInt16    :: Int16 -> Arg
argInt16 :: Int16 -> Arg
argInt16    = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_sint16
argInt32    :: Int32 -> Arg
argInt32 :: Int32 -> Arg
argInt32    = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_sint32
argInt64    :: Int64 -> Arg
argInt64 :: Int64 -> Arg
argInt64    = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_sint64

argWord8    :: Word8 -> Arg
argWord8 :: Word8 -> Arg
argWord8    = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_uint8
argWord16   :: Word16 -> Arg
argWord16 :: Word16 -> Arg
argWord16   = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_uint16
argWord32   :: Word32 -> Arg
argWord32 :: Word32 -> Arg
argWord32   = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_uint32
argWord64   :: Word64 -> Arg
argWord64 :: Word64 -> Arg
argWord64   = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_uint64

argCFloat   :: CFloat -> Arg
argCFloat :: CFloat -> Arg
argCFloat   = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_float
argCDouble  :: CDouble -> Arg
argCDouble :: CDouble -> Arg
argCDouble  = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_double

argCSize    :: CSize -> Arg
argCSize :: CSize -> Arg
argCSize    = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_size
argCTime    :: CTime -> Arg
argCTime :: CTime -> Arg
argCTime    = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_size

argCChar    :: CChar -> Arg
argCChar :: CChar -> Arg
argCChar    = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_schar
argCUChar   :: CUChar -> Arg
argCUChar :: CUChar -> Arg
argCUChar   = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_uchar

argCWchar   :: CWchar -> Arg
argCWchar :: CWchar -> Arg
argCWchar   = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_wchar

argPtr      :: Ptr a -> Arg
argPtr :: forall a. Ptr a -> Arg
argPtr      = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_pointer

argFunPtr   :: FunPtr a -> Arg
argFunPtr :: forall a. FunPtr a -> Arg
argFunPtr   = forall a. Storable a => Ptr CType -> a -> Arg
mkStorableArg Ptr CType
ffi_type_pointer

{- | The string argument is passed to C as a char * pointer, which is freed afterwards.
     The argument should not contain zero-bytes. -}
argString   :: String -> Arg
argString :: String -> Arg
argString   = forall a b. (a -> IO (Ptr b)) -> (Ptr b -> IO ()) -> a -> Arg
customPointerArg String -> IO CString
newCString forall a. Ptr a -> IO ()
free

-- | Like argString, but for ByteString's.

argByteString  :: BS.ByteString -> Arg
argByteString :: ByteString -> Arg
argByteString  = forall a b. (a -> IO (Ptr b)) -> (Ptr b -> IO ()) -> a -> Arg
customPointerArg (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. ByteString -> (CString -> IO a) -> IO a
BS.useAsCString forall (m :: * -> *) a. Monad m => a -> m a
return) (forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => a -> m a
return ())

-- | Like argByteString, but changing the string from C breaks referential transparency.

argConstByteString  :: BS.ByteString -> Arg
argConstByteString :: ByteString -> Arg
argConstByteString  = forall a b. (a -> IO (Ptr b)) -> (Ptr b -> IO ()) -> a -> Arg
customPointerArg (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall a. ByteString -> (CString -> IO a) -> IO a
BSU.unsafeUseAsCString forall (m :: * -> *) a. Monad m => a -> m a
return) (forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) a. Monad m => a -> m a
return ())

retVoid     :: RetType ()
retVoid :: RetType ()
retVoid     = forall a. ((Ptr CType -> Ptr CValue -> IO ()) -> IO a) -> RetType a
RetType (\Ptr CType -> Ptr CValue -> IO ()
write -> Ptr CType -> Ptr CValue -> IO ()
write Ptr CType
ffi_type_void forall a. Ptr a
nullPtr forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (m :: * -> *) a. Monad m => a -> m a
return ())

retCInt     :: RetType CInt
retCInt :: RetType CInt
retCInt     = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_sint
retCUInt    :: RetType CUInt
retCUInt :: RetType CUInt
retCUInt    = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_uint
retCLong    :: RetType CLong
retCLong :: RetType CLong
retCLong    = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_slong
retCULong   :: RetType CULong
retCULong :: RetType CULong
retCULong   = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_ulong

retInt8     :: RetType Int8
retInt8 :: RetType Int8
retInt8     = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_sint8
retInt16    :: RetType Int16
retInt16 :: RetType Int16
retInt16    = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_sint16
retInt32    :: RetType Int32
retInt32 :: RetType Int32
retInt32    = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_sint32
retInt64    :: RetType Int64
retInt64 :: RetType Int64
retInt64    = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_sint64

retWord8    :: RetType Word8
retWord8 :: RetType Word8
retWord8    = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_uint8
retWord16   :: RetType Word16
retWord16 :: RetType Word16
retWord16   = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_uint16
retWord32   :: RetType Word32
retWord32 :: RetType Word32
retWord32   = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_uint32
retWord64   :: RetType Word64
retWord64 :: RetType Word64
retWord64   = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_uint64

retCFloat   :: RetType CFloat
retCFloat :: RetType CFloat
retCFloat   = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_float
retCDouble  :: RetType CDouble
retCDouble :: RetType CDouble
retCDouble  = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_double

retCSize    :: RetType CSize
retCSize :: RetType CSize
retCSize    = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_size
retCTime    :: RetType CTime
retCTime :: RetType CTime
retCTime    = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_time

retCChar    :: RetType CChar
retCChar :: RetType CChar
retCChar    = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_schar
retCUChar   :: RetType CUChar
retCUChar :: RetType CUChar
retCUChar   = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_uchar

retCWchar   :: RetType CWchar
retCWchar :: RetType CWchar
retCWchar   = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_wchar

retFunPtr   :: RetType a -> RetType (FunPtr a)
retFunPtr :: forall a. RetType a -> RetType (FunPtr a)
retFunPtr RetType a
_ = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_pointer

retPtr      :: RetType a -> RetType (Ptr a)
retPtr :: forall a. RetType a -> RetType (Ptr a)
retPtr RetType a
_    = forall a. Storable a => Ptr CType -> RetType a
mkStorableRetType Ptr CType
ffi_type_pointer

retCString          :: RetType CString
retCString :: RetType CString
retCString          = forall a. RetType a -> RetType (Ptr a)
retPtr RetType CChar
retCChar

{- | Peek a String out of the returned char *. The char * is not freed. -}
retString           :: RetType String
retString :: RetType String
retString           = forall a b. (a -> IO b) -> RetType a -> RetType b
withRetType CString -> IO String
peekCString (forall a. RetType a -> RetType (Ptr a)
retPtr RetType CChar
retCChar)

{- | Like retString, but for ByteString's -}
retByteString       :: RetType BS.ByteString
retByteString :: RetType ByteString
retByteString       = forall a b. (a -> IO b) -> RetType a -> RetType b
withRetType CString -> IO ByteString
BS.packCString (forall a. RetType a -> RetType (Ptr a)
retPtr RetType CChar
retCChar)

{- | Make a ByteString out of the returned char *.
     The char * will be free(3)ed when the ByteString is garbage collected. -}
retMallocByteString :: RetType BS.ByteString
retMallocByteString :: RetType ByteString
retMallocByteString = forall a b. (a -> IO b) -> RetType a -> RetType b
withRetType CString -> IO ByteString
BSU.unsafePackMallocCString (forall a. RetType a -> RetType (Ptr a)
retPtr RetType CChar
retCChar)