 -- 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)

-- This allows the current process to check for an incoming message and decide
-- how to receive it, based on the information in the 'Status'.
-- This function corresponds to @MPI_Probe@.
probe = {# fun Probe as probe_
           {fromRank `Rank', fromTag `Tag', fromComm `Comm', allocaCast- `Status' peekCast*} -> `()' checkError*- #}
{- probe :: Rank       -- ^ Rank of the sender.
      -> Tag        -- ^ Tag of the sent message.
      -> Comm       -- ^ Communicator.
      -> IO Status  -- ^ Information about the incoming message (but not the content of the message). -}

send = {# fun unsafe Send as send_
          { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm' } -> `()' checkError*- #}
bsend = {# fun unsafe Bsend as bsend_
          { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm' } -> `()' checkError*- #}
ssend = {# fun unsafe Ssend as ssend_
          { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm' } -> `()' checkError*- #}
rsend = {# fun unsafe Rsend as rsend_
          { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm' } -> `()' checkError*- #}
recv = {# fun unsafe Recv as recv_
          { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm', allocaCast- `Status' peekCast* } -> `()' checkError*- #}
isend = {# fun unsafe Isend as isend_
           { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm', alloca- `Request' peekRequest*} -> `()' checkError*- #}
ibsend = {# fun unsafe Ibsend as ibsend_
           { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm', alloca- `Request' peekRequest*} -> `()' checkError*- #}
issend = {# fun unsafe Issend as issend_
           { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm', alloca- `Request' peekRequest*} -> `()' checkError*- #}
isendPtr = {# fun unsafe Isend as isendPtr_
           { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm', castPtr `Ptr Request'} -> `()' checkError*- #}
ibsendPtr = {# fun unsafe Ibsend as ibsendPtr_
           { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm', castPtr `Ptr Request'} -> `()' checkError*- #}
issendPtr = {# fun unsafe Issend as issendPtr_
           { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm', castPtr `Ptr Request'} -> `()' checkError*- #}
irecv = {# fun Irecv as irecv_
           { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm', alloca- `Request' peekRequest*} -> `()' checkError*- #}
irecvPtr = {# fun Irecv as irecvPtr_
           { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromTag `Tag', fromComm `Comm', castPtr `Ptr Request'} -> `()' checkError*- #}
bcast = {# fun unsafe Bcast as bcast_
           { id `BufferPtr', id `Count', fromDatatype `Datatype', fromRank `Rank', fromComm `Comm'} -> `()' checkError*- #}

-- | Blocks until all processes on the communicator call this function.
-- This function corresponds to @MPI_Barrier@.
barrier = {# fun unsafe Barrier as barrier_ {fromComm `Comm'} -> `()' checkError*- #}

-- | Blocking test for the completion of a send of receive.
-- See 'test' for a non-blocking variant.
-- This function corresponds to @MPI_Wait@.
wait = {# fun unsafe Wait as wait_
          {withRequest* `Request', allocaCast- `Status' peekCast*} -> `()' checkError*-  #}

-- TODO: Make this Storable Array instead of Ptr ?
waitall = {# fun unsafe Waitall as waitall_
            { id `Count', castPtr `Ptr Request', castPtr `Ptr Status'} -> `()' checkError*- #}

-- | Non-blocking test for the completion of a send or receive.
-- Returns @Nothing@ if the request is not complete, otherwise
-- it returns @Just status@. See 'wait' for a blocking variant.
-- This function corresponds to @MPI_Test@.
-- | Non-blocking test for the completion of a send or receive.
-- Returns @Nothing@ if the request is not complete, otherwise
-- it returns @Just status@. See 'wait' for a blocking variant.

-- | 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@.
{# fun unsafe Comm_rank as ^
              {fromComm `Comm', alloca- `Rank' peekIntConv* } -> `()' checkError*- #}

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

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