 -- it returns the total number of processes available. If the communicator is
 -- and intra-communicator it returns the number of processes in the local group.
 -- This function corresponds to @MPI_Comm_size@.
-commSize = {# fun unsafe Comm_size as commSize_
+{# fun unsafe Comm_size as ^
               {fromComm `Comm', alloca- `Int' peekIntConv* } -> `()' checkError*- #}
 
-commRemoteSize = {# fun unsafe Comm_remote_size as commRemoteSize_
+{# fun unsafe Comm_remote_size as ^
                     {fromComm `Comm', alloca- `Int' peekIntConv* } -> `()' checkError*- #}
 
-commTestInter = {# fun unsafe Comm_test_inter as commTestInter_
+{# fun unsafe Comm_test_inter as ^
                    {fromComm `Comm', alloca- `Bool' peekBool* } -> `()' checkError*- #}
 
 commGetAttr :: Storable e => Comm -> Int -> IO (Maybe e)

-- | Predefined tag value that allows reception of the messages with
--   arbitrary tag values. Corresponds to @MPI_ANY_TAG@.
tagUpperBound :: Int
tagUpperBound = 
  let key = unsafePerformIO (peek tagUB_) 
      in fromMaybe 0 $ unsafePerformIO (commGetAttr commWorld key)

-- | Return the rank of the calling process for the given communicator.
-- This function corresponds to @MPI_Comm_rank@.
commRank = {# fun unsafe Comm_rank as commRank_
              {fromComm `Comm', alloca- `Rank' peekIntConv* } -> `()' checkError*- #}

commCompare = {# fun unsafe Comm_compare as commCompare_
                 {fromComm `Comm', fromComm `Comm', alloca- `ComparisonResult' peekEnum*} -> `()' checkError*- #}

-- | Test for an incomming message, without actually receiving it.


-- | Cancel a pending communication request.
-- This function corresponds to @MPI_Cancel@.
{# fun unsafe Cancel as ^
            {withRequest* `Request'} -> `()' checkError*- #}
withRequest req f = do alloca $ \ptr -> do poke ptr req
                                           f (castPtr ptr)
{# fun unsafe Scatter as ^
             { id `BufferPtr', id `Count', fromDatatype `Datatype',
               id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromRank `Rank', fromComm `Comm'} -> `()' checkError*- #}

{# fun unsafe Gather as ^
             { id `BufferPtr', id `Count', fromDatatype `Datatype',
               id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromRank `Rank', fromComm `Comm'} -> `()' checkError*- #}

-- We pass counts/displs as Ptr CInt so that caller could supply nullPtr here
-- which would be impossible if we marshal arrays ourselves here.
{# fun unsafe Scatterv as ^
             { id `BufferPtr', id `Ptr CInt', id `Ptr CInt', fromDatatype `Datatype',
               id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromRank `Rank', fromComm `Comm'} -> `()' checkError*- #}
{# fun unsafe Gatherv as ^
             { id `BufferPtr', id `Count', fromDatatype `Datatype',
               id `BufferPtr', id `Ptr CInt', id `Ptr CInt', fromDatatype `Datatype',
               fromRank `Rank', fromComm `Comm'} -> `()' checkError*- #}
{# fun unsafe Allgather as ^
             { id `BufferPtr', id `Count', fromDatatype `Datatype',
               id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromComm `Comm'} -> `()' checkError*- #}
{# fun unsafe Allgatherv as ^
             { id `BufferPtr', id `Count', fromDatatype `Datatype',
               id `BufferPtr', id `Ptr CInt', id `Ptr CInt', fromDatatype `Datatype',
               fromComm `Comm'} -> `()' checkError*- #}
{# fun unsafe Alltoall as ^
             { id `BufferPtr', id `Count', fromDatatype `Datatype',
               id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromComm `Comm'} -> `()' checkError*- #}
{# fun unsafe Alltoallv as ^
             { id `BufferPtr', id `Ptr CInt', id `Ptr CInt', fromDatatype `Datatype',
               id `BufferPtr', id `Ptr CInt', id `Ptr CInt', fromDatatype `Datatype',
               fromComm `Comm'} -> `()' checkError*- #}
-- Reduce, allreduce and reduceScatter could call back to Haskell
-- via user-defined ops, so they should be imported in "safe" mode
{# fun Reduce as ^
             { id `BufferPtr', id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromOperation `Operation', fromRank `Rank', fromComm `Comm'} -> `()' checkError*- #}
{# fun Allreduce as ^
             { id `BufferPtr', id `BufferPtr', id `Count', fromDatatype `Datatype',
               fromOperation `Operation', fromComm `Comm'} -> `()' checkError*- #}
{# fun Reduce_scatter as ^
             { id `BufferPtr', id `BufferPtr', id `Ptr CInt', fromDatatype `Datatype',
               fromOperation `Operation', fromComm `Comm'} -> `()' checkError*- #}
{# fun unsafe Op_create as ^
              {castFunPtr `FunPtr (Ptr t -> Ptr t -> Ptr CInt -> Ptr Datatype -> IO ())', cFromEnum `Bool', alloca- `Operation' peekOperation*} -> `()' checkError*- #}
opFree = {# call unsafe Op_free as opFree_ #}
{# fun unsafe Wtime as ^ {} -> `Double' realToFrac #}
{# fun unsafe Wtick as ^ {} -> `Double' realToFrac #}

-- | Return the process group from a communicator.
{# fun unsafe Comm_group as ^
               {fromComm `Comm', alloca- `Group' peekGroup*} -> `()' checkError*- #}

groupRank = unsafePerformIO <$> groupRank'
