content: -- | Arguments and return types
  module Foreign.LibFFI.Types (
      -- * Arguments
      -- ** Integral types
      argCInt,
      argCUInt,
      argCLong,
      argCULong,
      argInt,
      argInt8,
      argInt16,
      argInt32,
      argInt64,
      argWord,
      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,
      retInt,
      retInt8,
      retInt16,
      retInt32,
      retInt64,
      retWord,
      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     = mkStorableArg ffi_type_sint
  argCUInt    :: CUInt -> Arg
  argCUInt    = mkStorableArg ffi_type_uint
  argCLong    :: CLong -> Arg
  argCLong    = mkStorableArg ffi_type_slong
  argCULong   :: CULong -> Arg
  argCULong   = mkStorableArg ffi_type_ulong
  
  -- | Note that on e.g. x86_64, Int \/= CInt
  argInt      :: Int -> Arg
  argInt      = mkStorableArg ffi_type_hs_int
  argInt8     :: Int8 -> Arg
  argInt8     = mkStorableArg ffi_type_sint8
  argInt16    :: Int16 -> Arg
  argInt16    = mkStorableArg ffi_type_sint16
  argInt32    :: Int32 -> Arg
  argInt32    = mkStorableArg ffi_type_sint32
  argInt64    :: Int64 -> Arg
  argInt64    = mkStorableArg ffi_type_sint64
  
  argWord     :: Word -> Arg
  argWord     = mkStorableArg ffi_type_hs_word
  argWord8    :: Word8 -> Arg
  argWord8    = mkStorableArg ffi_type_uint8
  argWord16   :: Word16 -> Arg
  argWord16   = mkStorableArg ffi_type_uint16
  argWord32   :: Word32 -> Arg
  argWord32   = mkStorableArg ffi_type_uint32
  argWord64   :: Word64 -> Arg
  argWord64   = mkStorableArg ffi_type_uint64
  
  argCFloat   :: CFloat -> Arg
  argCFloat   = mkStorableArg ffi_type_float
  argCDouble  :: CDouble -> Arg
  argCDouble  = mkStorableArg ffi_type_double
  
  argCSize    :: CSize -> Arg
  argCSize    = mkStorableArg ffi_type_size
  argCTime    :: CTime -> Arg
  argCTime    = mkStorableArg ffi_type_size
  
  argCChar    :: CChar -> Arg
  argCChar    = mkStorableArg ffi_type_schar
  argCUChar   :: CUChar -> Arg
  argCUChar   = mkStorableArg ffi_type_uchar
  
  argCWchar   :: CWchar -> Arg
  argCWchar   = mkStorableArg ffi_type_schar
  
  argPtr      :: Ptr a -> Arg
  argPtr      = mkStorableArg ffi_type_pointer
  
  argFunPtr   :: FunPtr a -> Arg
  argFunPtr   = mkStorableArg 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   = customPointerArg newCString free
  
  -- | Like argString, but for ByteString's.
  argByteString  :: BS.ByteString -> Arg
  argByteString  = customPointerArg (flip BS.useAsCString return) (const $ return ())
  
  -- | Like argByteString, but changing the string from C breaks referential transparency.
  argConstByteString  :: BS.ByteString -> Arg
  argConstByteString  = customPointerArg (flip BSU.unsafeUseAsCString return) (const $ return ())
  
  retVoid     :: RetType ()
  retVoid     = RetType ffi_type_void (\write -> write nullPtr >> return ())
  
  retCInt     :: RetType CInt
  retCInt     = mkStorableRetType ffi_type_sint
  retCUInt    :: RetType CUInt
  retCUInt    = mkStorableRetType ffi_type_uint
  retCLong    :: RetType CLong
  retCLong    = mkStorableRetType ffi_type_slong
  retCULong   :: RetType CULong
  retCULong   = mkStorableRetType ffi_type_ulong
  
  retInt      :: RetType Int
  retInt      = mkStorableRetType ffi_type_hs_int
  retInt8     :: RetType Int8
  retInt8     = mkStorableRetType ffi_type_sint8
  retInt16    :: RetType Int16
  retInt16    = mkStorableRetType ffi_type_sint16
  retInt32    :: RetType Int32
  retInt32    = mkStorableRetType ffi_type_sint32
  retInt64    :: RetType Int64
  retInt64    = mkStorableRetType ffi_type_sint64
  
  retWord     :: RetType Word
  retWord     = mkStorableRetType ffi_type_hs_word
  retWord8    :: RetType Word8
  retWord8    = mkStorableRetType ffi_type_uint8
  retWord16   :: RetType Word16
  retWord16   = mkStorableRetType ffi_type_uint16
  retWord32   :: RetType Word32
  retWord32   = mkStorableRetType ffi_type_uint32
  retWord64   :: RetType Word64
  retWord64   = mkStorableRetType ffi_type_uint64
  
  retCFloat   :: RetType CFloat
  retCFloat   = mkStorableRetType ffi_type_float
  retCDouble  :: RetType CDouble
  retCDouble  = mkStorableRetType ffi_type_double
  
  retCSize    :: RetType CSize
  retCSize    = mkStorableRetType ffi_type_size
  retCTime    :: RetType CTime
  retCTime    = mkStorableRetType ffi_type_time
  
  retCChar    :: RetType CChar
  retCChar    = mkStorableRetType ffi_type_schar
  retCUChar   :: RetType CUChar
  retCUChar   = mkStorableRetType ffi_type_uchar
  
  retCWchar   :: RetType CWchar
  retCWchar   = mkStorableRetType ffi_type_schar
  
  retFunPtr   :: RetType a -> RetType (FunPtr a)
  retFunPtr _ = mkStorableRetType ffi_type_pointer
  
  retPtr      :: RetType a -> RetType (Ptr a)
  retPtr _    = mkStorableRetType ffi_type_pointer
  
  retCString          :: RetType CString
  retCString          = retPtr retCChar
  
  {- | Peek a String out of the returned char *. The char * is not freed. -}
  retString           :: RetType String
  retString           = withRetType peekCString (retPtr retCChar)
  
  {- | Like retString, but for ByteString's -}
  retByteString       :: RetType BS.ByteString
  retByteString       = withRetType BS.packCString (retPtr 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 = withRetType BSU.unsafePackMallocCString (retPtr retCChar)
  