use std::{mem, ptr};
use std::cmp::Ordering;
use std::string::FromUtf8Error;
use std::os::raw::{c_char, c_int, c_double, c_void};
use conv::ConvUtil;
use ffi;
use topology::SystemCommunicator;
pub struct Universe {
buffer: Option<Vec<u8>>
}
impl Universe {
pub fn world(&self) -> SystemCommunicator {
SystemCommunicator::world()
}
pub fn buffer_size(&self) -> usize {
self.buffer.as_ref().map_or(0, |buffer| buffer.len())
}
pub fn set_buffer_size(&mut self, size: usize) {
self.detach_buffer();
if size > 0 {
let mut buffer = vec![0; size];
unsafe {
ffi::MPI_Buffer_attach(
mem::transmute(buffer.as_mut_ptr()),
buffer.len().value_as().expect("Buffer length exceeds the range of a C int.")
);
}
self.buffer = Some(buffer);
}
}
pub fn detach_buffer(&mut self) {
if let Some(buffer) = self.buffer.take() {
let mut addr: *const c_void = ptr::null();
let addr_ptr: *mut *const c_void = &mut addr;
let mut size: c_int = 0;
unsafe {
ffi::MPI_Buffer_detach(addr_ptr as *mut c_void, &mut size);
assert_eq!(addr, mem::transmute(buffer.as_ptr()));
}
assert_eq!(
size,
buffer.len().value_as().expect("Buffer length exceeds the range of a C int.")
);
}
}
}
impl Drop for Universe {
fn drop(&mut self) {
self.detach_buffer();
unsafe {
ffi::MPI_Finalize();
}
}
}
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Threading {
Single,
Funneled,
Serialized,
Multiple
}
impl Threading {
fn as_raw(&self) -> c_int {
use self::Threading::*;
match *self {
Single => unsafe_extern_static!(ffi::RSMPI_THREAD_SINGLE),
Funneled => unsafe_extern_static!(ffi::RSMPI_THREAD_FUNNELED),
Serialized => unsafe_extern_static!(ffi::RSMPI_THREAD_SERIALIZED),
Multiple => unsafe_extern_static!(ffi::RSMPI_THREAD_MULTIPLE),
}
}
}
impl PartialOrd<Threading> for Threading {
fn partial_cmp(&self, other: &Threading) -> Option<Ordering> {
self.as_raw().partial_cmp(&other.as_raw())
}
}
impl Ord for Threading {
fn cmp(&self, other: &Threading) -> Ordering {
self.as_raw().cmp(&other.as_raw())
}
}
impl From<c_int> for Threading {
fn from(i: c_int) -> Threading {
use self::Threading::*;
if i == unsafe_extern_static!(ffi::RSMPI_THREAD_SINGLE) {
return Single;
} else if i == unsafe_extern_static!(ffi::RSMPI_THREAD_FUNNELED) {
return Funneled;
} else if i == unsafe_extern_static!(ffi::RSMPI_THREAD_SERIALIZED) {
return Serialized;
} else if i == unsafe_extern_static!(ffi::RSMPI_THREAD_MULTIPLE) {
return Multiple;
}
panic!("Unknown threading level: {}", i)
}
}
fn is_initialized() -> bool {
let mut res: c_int = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Initialized(&mut res);
}
res != 0
}
pub fn initialize() -> Option<Universe> {
initialize_with_threading(Threading::Single).map(|x| x.0)
}
pub fn initialize_with_threading(threading: Threading) -> Option<(Universe, Threading)> {
if is_initialized() {
None
} else {
let mut provided: c_int = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Init_thread(ptr::null_mut(),
ptr::null_mut(),
threading.as_raw(),
&mut provided);
}
Some((Universe { buffer: None }, provided.into()))
}
}
pub fn threading_support() -> Threading {
let mut res: c_int = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Query_thread(&mut res);
}
res.into()
}
pub fn version() -> (c_int, c_int) {
let mut version: c_int = unsafe { mem::uninitialized() };
let mut subversion: c_int = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Get_version(&mut version, &mut subversion);
}
(version, subversion)
}
pub fn library_version() -> Result<String, FromUtf8Error> {
let bufsize = unsafe_extern_static!(ffi::RSMPI_MAX_LIBRARY_VERSION_STRING).value_as().expect(
&format!("MPI_MAX_LIBRARY_SIZE ({}) cannot be expressed as a usize.",
unsafe_extern_static!(ffi::RSMPI_MAX_LIBRARY_VERSION_STRING))
);
let mut buf = vec![0u8; bufsize];
let mut len: c_int = 0;
unsafe {
ffi::MPI_Get_library_version(buf.as_mut_ptr() as *mut c_char, &mut len);
}
buf.truncate(len.value_as().expect(&format!("Length of library version string ({}) cannot \
be expressed as a usize.",
len)));
String::from_utf8(buf)
}
pub fn processor_name() -> Result<String, FromUtf8Error> {
let bufsize = unsafe_extern_static!(ffi::RSMPI_MAX_PROCESSOR_NAME).value_as()
.expect(&format!("MPI_MAX_LIBRARY_SIZE ({}) \
cannot be expressed as a \
usize.",
unsafe_extern_static!(ffi::RSMPI_MAX_PROCESSOR_NAME)));
let mut buf = vec![0u8; bufsize];
let mut len: c_int = 0;
unsafe {
ffi::MPI_Get_processor_name(buf.as_mut_ptr() as *mut c_char, &mut len);
}
buf.truncate(len.value_as()
.expect(&format!("Length of processor name string ({}) cannot be \
expressed as a usize.",
len)));
String::from_utf8(buf)
}
pub fn time() -> c_double {
unsafe { ffi::RSMPI_Wtime() }
}
pub fn time_resolution() -> c_double {
unsafe { ffi::RSMPI_Wtick() }
}