use std::{mem, process};
use std::os::raw::c_int;
use super::Tag;
use ffi;
use ffi::{MPI_Comm, MPI_Group};
use raw::traits::*;
use datatype::traits::*;
pub mod traits {
pub use super::{Communicator, AsCommunicator, Group};
}
pub trait AsCommunicator {
type Out: Communicator;
fn as_communicator(&self) -> &Self::Out;
}
pub type Rank = c_int;
#[derive(Copy, Clone)]
pub struct SystemCommunicator(MPI_Comm);
impl SystemCommunicator {
pub fn world() -> SystemCommunicator {
SystemCommunicator::from_raw_unchecked(unsafe_extern_static!(ffi::RSMPI_COMM_WORLD))
}
#[allow(dead_code)]
fn from_raw(raw: MPI_Comm) -> Option<SystemCommunicator> {
if raw == unsafe_extern_static!(ffi::RSMPI_COMM_NULL) {
None
} else {
Some(SystemCommunicator(raw))
}
}
fn from_raw_unchecked(raw: MPI_Comm) -> SystemCommunicator {
debug_assert_ne!(raw, unsafe_extern_static!(ffi::RSMPI_COMM_NULL));
SystemCommunicator(raw)
}
}
unsafe impl AsRaw for SystemCommunicator {
type Raw = MPI_Comm;
fn as_raw(&self) -> Self::Raw {
self.0
}
}
impl Communicator for SystemCommunicator {}
impl AsCommunicator for SystemCommunicator {
type Out = SystemCommunicator;
fn as_communicator(&self) -> &Self::Out {
self
}
}
pub struct UserCommunicator(MPI_Comm);
impl UserCommunicator {
fn from_raw(raw: MPI_Comm) -> Option<UserCommunicator> {
if raw == unsafe_extern_static!(ffi::RSMPI_COMM_NULL) {
None
} else {
Some(UserCommunicator(raw))
}
}
fn from_raw_unchecked(raw: MPI_Comm) -> UserCommunicator {
debug_assert_ne!(raw, unsafe_extern_static!(ffi::RSMPI_COMM_NULL));
UserCommunicator(raw)
}
}
impl AsCommunicator for UserCommunicator {
type Out = UserCommunicator;
fn as_communicator(&self) -> &Self::Out {
self
}
}
unsafe impl AsRaw for UserCommunicator {
type Raw = MPI_Comm;
fn as_raw(&self) -> Self::Raw {
self.0
}
}
impl Communicator for UserCommunicator {}
impl Drop for UserCommunicator {
fn drop(&mut self) {
unsafe {
ffi::MPI_Comm_free(&mut self.0);
}
assert_eq!(self.0, unsafe_extern_static!(ffi::RSMPI_COMM_NULL));
}
}
#[derive(Copy, Clone, Debug)]
pub struct Color(c_int);
impl Color {
pub fn undefined() -> Color {
Color(unsafe_extern_static!(ffi::RSMPI_UNDEFINED))
}
pub fn with_value(value: c_int) -> Color {
if value < 0 {
panic!("Value of color must be non-negative.")
}
Color(value)
}
fn as_raw(&self) -> c_int {
self.0
}
}
pub type Key = c_int;
pub trait Communicator: AsRaw<Raw = MPI_Comm> {
fn size(&self) -> Rank {
let mut res: Rank = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Comm_size(self.as_raw(), &mut res);
}
res
}
fn rank(&self) -> Rank {
let mut res: Rank = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Comm_rank(self.as_raw(), &mut res);
}
res
}
fn process_at_rank(&self, r: Rank) -> Process<Self>
where Self: Sized
{
assert!(0 <= r && r < self.size());
Process::by_rank_unchecked(self, r)
}
fn any_process(&self) -> AnyProcess<Self>
where Self: Sized
{
AnyProcess(self)
}
fn this_process(&self) -> Process<Self>
where Self: Sized
{
let rank = self.rank();
Process::by_rank_unchecked(self, rank)
}
fn compare<C: ?Sized>(&self, other: &C) -> CommunicatorRelation
where C: Communicator
{
let mut res: c_int = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Comm_compare(self.as_raw(), other.as_raw(), &mut res);
}
res.into()
}
fn duplicate(&self) -> UserCommunicator {
let mut newcomm: MPI_Comm = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Comm_dup(self.as_raw(), &mut newcomm);
}
UserCommunicator::from_raw_unchecked(newcomm)
}
fn split_by_color(&self, color: Color) -> Option<UserCommunicator> {
self.split_by_color_with_key(color, Key::default())
}
fn split_by_color_with_key(&self, color: Color, key: Key) -> Option<UserCommunicator> {
let mut newcomm: MPI_Comm = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Comm_split(self.as_raw(), color.as_raw(), key, &mut newcomm);
}
UserCommunicator::from_raw(newcomm)
}
fn split_by_subgroup_collective<G: ?Sized>(&self, group: &G) -> Option<UserCommunicator>
where G: Group
{
let mut newcomm: MPI_Comm = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Comm_create(self.as_raw(), group.as_raw(), &mut newcomm);
}
UserCommunicator::from_raw(newcomm)
}
fn split_by_subgroup<G: ?Sized>(&self, group: &G) -> Option<UserCommunicator>
where G: Group
{
self.split_by_subgroup_with_tag(group, Tag::default())
}
fn split_by_subgroup_with_tag<G: ?Sized>(&self, group: &G, tag: Tag) -> Option<UserCommunicator>
where G: Group
{
let mut newcomm: MPI_Comm = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Comm_create_group(self.as_raw(), group.as_raw(), tag, &mut newcomm);
}
UserCommunicator::from_raw(newcomm)
}
fn group(&self) -> UserGroup {
let mut group: MPI_Group = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Comm_group(self.as_raw(), &mut group);
}
UserGroup(group)
}
fn abort(&self, errorcode: c_int) -> ! {
unsafe {
ffi::MPI_Abort(self.as_raw(), errorcode);
}
process::abort();
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum CommunicatorRelation {
Identical,
Congruent,
Similar,
Unequal
}
impl From<c_int> for CommunicatorRelation {
fn from(i: c_int) -> CommunicatorRelation {
use self::CommunicatorRelation::*;
if i == unsafe_extern_static!(ffi::RSMPI_IDENT) {
return Identical;
} else if i == unsafe_extern_static!(ffi::RSMPI_CONGRUENT) {
return Congruent;
} else if i == unsafe_extern_static!(ffi::RSMPI_SIMILAR) {
return Similar;
} else if i == unsafe_extern_static!(ffi::RSMPI_UNEQUAL) {
return Unequal;
}
panic!("Unknown communicator relation: {}", i)
}
}
#[derive(Copy, Clone)]
pub struct Process<'a, C>
where C: 'a + Communicator
{
comm: &'a C,
rank: Rank
}
impl<'a, C> Process<'a, C> where C: 'a + Communicator
{
#[allow(dead_code)]
fn by_rank(c: &'a C, r: Rank) -> Option<Self> {
if r != unsafe_extern_static!(ffi::RSMPI_PROC_NULL) {
Some(Process { comm: c, rank: r })
} else {
None
}
}
fn by_rank_unchecked(c: &'a C, r: Rank) -> Self {
Process { comm: c, rank: r }
}
pub fn rank(&self) -> Rank {
self.rank
}
}
impl<'a, C> AsCommunicator for Process<'a, C> where C: 'a + Communicator
{
type Out = C;
fn as_communicator(&self) -> &Self::Out {
self.comm
}
}
pub struct AnyProcess<'a, C>(&'a C) where C: 'a + Communicator;
impl<'a, C> AsCommunicator for AnyProcess<'a, C> where C: 'a + Communicator
{
type Out = C;
fn as_communicator(&self) -> &Self::Out {
self.0
}
}
#[derive(Copy, Clone)]
pub struct SystemGroup(MPI_Group);
impl SystemGroup {
pub fn empty() -> SystemGroup {
SystemGroup(unsafe_extern_static!(ffi::RSMPI_GROUP_EMPTY))
}
}
unsafe impl AsRaw for SystemGroup {
type Raw = MPI_Group;
fn as_raw(&self) -> Self::Raw {
self.0
}
}
impl Group for SystemGroup {}
pub struct UserGroup(MPI_Group);
impl Drop for UserGroup {
fn drop(&mut self) {
unsafe {
ffi::MPI_Group_free(&mut self.0);
}
assert_eq!(self.0, unsafe_extern_static!(ffi::RSMPI_GROUP_NULL));
}
}
unsafe impl AsRaw for UserGroup {
type Raw = MPI_Group;
fn as_raw(&self) -> Self::Raw {
self.0
}
}
impl Group for UserGroup {}
pub trait Group: AsRaw<Raw = MPI_Group> {
fn union<G>(&self, other: &G) -> UserGroup
where G: Group
{
let mut newgroup: MPI_Group = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Group_union(self.as_raw(), other.as_raw(), &mut newgroup);
}
UserGroup(newgroup)
}
fn intersection<G>(&self, other: &G) -> UserGroup
where G: Group
{
let mut newgroup: MPI_Group = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Group_intersection(self.as_raw(), other.as_raw(), &mut newgroup);
}
UserGroup(newgroup)
}
fn difference<G>(&self, other: &G) -> UserGroup
where G: Group
{
let mut newgroup: MPI_Group = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Group_difference(self.as_raw(), other.as_raw(), &mut newgroup);
}
UserGroup(newgroup)
}
fn include(&self, ranks: &[Rank]) -> UserGroup {
let mut newgroup: MPI_Group = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Group_incl(self.as_raw(), ranks.count(), ranks.as_ptr(), &mut newgroup);
}
UserGroup(newgroup)
}
fn exclude(&self, ranks: &[Rank]) -> UserGroup {
let mut newgroup: MPI_Group = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Group_excl(self.as_raw(), ranks.count(), ranks.as_ptr(), &mut newgroup);
}
UserGroup(newgroup)
}
fn size(&self) -> Rank {
let mut res: Rank = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Group_size(self.as_raw(), &mut res);
}
res
}
fn rank(&self) -> Option<Rank> {
let mut res: Rank = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Group_rank(self.as_raw(), &mut res);
}
if res == unsafe_extern_static!(ffi::RSMPI_UNDEFINED) {
None
} else {
Some(res)
}
}
fn translate_rank<G>(&self, rank: Rank, other: &G) -> Option<Rank>
where G: Group
{
let mut res: Rank = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Group_translate_ranks(self.as_raw(), 1, &rank, other.as_raw(), &mut res);
}
if res == unsafe_extern_static!(ffi::RSMPI_UNDEFINED) {
None
} else {
Some(res)
}
}
fn translate_ranks<G>(&self, ranks: &[Rank], other: &G) -> Vec<Option<Rank>>
where G: Group
{
ranks.iter().map(|&r| self.translate_rank(r, other)).collect()
}
fn compare<G>(&self, other: &G) -> GroupRelation
where G: Group
{
let mut relation: c_int = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Group_compare(self.as_raw(), other.as_raw(), &mut relation);
}
relation.into()
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum GroupRelation {
Identical,
Similar,
Unequal
}
impl From<c_int> for GroupRelation {
fn from(i: c_int) -> GroupRelation {
use self::GroupRelation::*;
if i == unsafe_extern_static!(ffi::RSMPI_IDENT) {
return Identical;
} else if i == unsafe_extern_static!(ffi::RSMPI_SIMILAR) {
return Similar;
} else if i == unsafe_extern_static!(ffi::RSMPI_UNEQUAL) {
return Unequal;
}
panic!("Unknown group relation: {}", i)
}
}