use std::{mem, slice};
use std::borrow::Borrow;
use std::marker::PhantomData;
use std::os::raw::c_void;
use conv::ConvUtil;
use super::{Address, Count};
use ffi;
use ffi::MPI_Datatype;
use raw::traits::*;
pub mod traits {
pub use super::{Equivalence, Datatype, AsDatatype, Collection, Pointer, PointerMut, Buffer,
BufferMut, Partitioned, PartitionedBuffer, PartitionedBufferMut};
}
#[derive(Copy, Clone, Debug)]
pub struct DatatypeRef<'a> {
datatype: MPI_Datatype,
phantom: PhantomData<&'a ()>,
}
unsafe impl<'a> AsRaw for DatatypeRef<'a> {
type Raw = MPI_Datatype;
fn as_raw(&self) -> Self::Raw {
self.datatype
}
}
impl<'a> Datatype for DatatypeRef<'a> {}
impl<'a> DatatypeRef<'a> {
pub unsafe fn from_raw(datatype: MPI_Datatype) -> Self {
Self { datatype, phantom: PhantomData }
}
}
pub type SystemDatatype = DatatypeRef<'static>;
pub unsafe trait Equivalence {
type Out: Datatype;
fn equivalent_datatype() -> Self::Out;
}
macro_rules! equivalent_system_datatype {
($rstype:path, $mpitype:path) => (
unsafe impl Equivalence for $rstype {
type Out = SystemDatatype;
fn equivalent_datatype() -> Self::Out {
unsafe { DatatypeRef::from_raw($mpitype) }
}
}
)
}
equivalent_system_datatype!(f32, ffi::RSMPI_FLOAT);
equivalent_system_datatype!(f64, ffi::RSMPI_DOUBLE);
equivalent_system_datatype!(i8, ffi::RSMPI_INT8_T);
equivalent_system_datatype!(i16, ffi::RSMPI_INT16_T);
equivalent_system_datatype!(i32, ffi::RSMPI_INT32_T);
equivalent_system_datatype!(i64, ffi::RSMPI_INT64_T);
equivalent_system_datatype!(u8, ffi::RSMPI_UINT8_T);
equivalent_system_datatype!(u16, ffi::RSMPI_UINT16_T);
equivalent_system_datatype!(u32, ffi::RSMPI_UINT32_T);
equivalent_system_datatype!(u64, ffi::RSMPI_UINT64_T);
#[cfg(target_pointer_width = "32")]
equivalent_system_datatype!(usize, ffi::RSMPI_UINT32_T);
#[cfg(target_pointer_width = "32")]
equivalent_system_datatype!(isize, ffi::RSMPI_INT32_T);
#[cfg(target_pointer_width = "64")]
equivalent_system_datatype!(usize, ffi::RSMPI_UINT64_T);
#[cfg(target_pointer_width = "64")]
equivalent_system_datatype!(isize, ffi::RSMPI_INT64_T);
pub struct UserDatatype(MPI_Datatype);
impl UserDatatype {
pub fn contiguous<D>(count: Count, oldtype: &D) -> UserDatatype
where D: Datatype
{
let mut newtype: MPI_Datatype = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Type_contiguous(count, oldtype.as_raw(), &mut newtype);
ffi::MPI_Type_commit(&mut newtype);
}
UserDatatype(newtype)
}
pub fn vector<D>(count: Count, blocklength: Count, stride: Count, oldtype: &D) -> UserDatatype
where D: Datatype
{
let mut newtype: MPI_Datatype = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Type_vector(count, blocklength, stride, oldtype.as_raw(), &mut newtype);
ffi::MPI_Type_commit(&mut newtype);
}
UserDatatype(newtype)
}
pub fn heterogeneous_vector<D>(count: Count,
blocklength: Count,
stride: Address,
oldtype: &D)
-> UserDatatype
where D: Datatype
{
let mut newtype: MPI_Datatype = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Type_hvector(count, blocklength, stride, oldtype.as_raw(), &mut newtype);
ffi::MPI_Type_commit(&mut newtype);
}
UserDatatype(newtype)
}
pub fn indexed<D>(blocklengths: &[Count], displacements: &[Count], oldtype: &D) -> UserDatatype
where D: Datatype
{
assert_eq!(blocklengths.len(), displacements.len());
let mut newtype: MPI_Datatype = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Type_indexed(blocklengths.count(),
blocklengths.as_ptr(),
displacements.as_ptr(),
oldtype.as_raw(),
&mut newtype);
ffi::MPI_Type_commit(&mut newtype);
}
UserDatatype(newtype)
}
pub fn heterogeneous_indexed<D>(blocklengths: &[Count],
displacements: &[Address],
oldtype: &D)
-> UserDatatype
where D: Datatype
{
assert_eq!(blocklengths.len(), displacements.len());
let mut newtype: MPI_Datatype = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Type_create_hindexed(blocklengths.count(),
blocklengths.as_ptr(),
displacements.as_ptr(),
oldtype.as_raw(),
&mut newtype);
ffi::MPI_Type_commit(&mut newtype);
}
UserDatatype(newtype)
}
pub fn indexed_block<D>(blocklength: Count,
displacements: &[Count],
oldtype: &D)
-> UserDatatype
where D: Datatype
{
let mut newtype: MPI_Datatype = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Type_create_indexed_block(displacements.count(),
blocklength,
displacements.as_ptr(),
oldtype.as_raw(),
&mut newtype);
ffi::MPI_Type_commit(&mut newtype);
}
UserDatatype(newtype)
}
pub fn heterogeneous_indexed_block<D>(blocklength: Count,
displacements: &[Address],
oldtype: &D)
-> UserDatatype
where D: Datatype
{
let mut newtype: MPI_Datatype = unsafe { mem::uninitialized() };
unsafe {
ffi::MPI_Type_create_hindexed_block(displacements.count(),
blocklength,
displacements.as_ptr(),
oldtype.as_raw(),
&mut newtype);
ffi::MPI_Type_commit(&mut newtype);
}
UserDatatype(newtype)
}
pub fn structured(count: Count, blocklengths: &[Count], displacements: &[Address],
types: &[&Datatype<Raw = MPI_Datatype>]) -> UserDatatype
{
let mut newtype: MPI_Datatype = unsafe { mem::uninitialized() };
let types = types.iter().map(|t| t.as_raw()).collect::<Vec<_>>();
unsafe {
ffi::MPI_Type_create_struct(count, blocklengths.as_ptr(), displacements.as_ptr(),
types.as_ptr(), &mut newtype);
ffi::MPI_Type_commit(&mut newtype);
}
UserDatatype(newtype)
}
}
impl Drop for UserDatatype {
fn drop(&mut self) {
unsafe {
ffi::MPI_Type_free(&mut self.0);
}
assert_eq!(self.0, unsafe_extern_static!(ffi::RSMPI_DATATYPE_NULL));
}
}
unsafe impl AsRaw for UserDatatype {
type Raw = MPI_Datatype;
fn as_raw(&self) -> Self::Raw {
self.0
}
}
impl Datatype for UserDatatype {}
pub trait Datatype: AsRaw<Raw = MPI_Datatype> { }
impl<'a, D> Datatype for &'a D where D: 'a + Datatype
{}
pub unsafe trait AsDatatype {
type Out: Datatype;
fn as_datatype(&self) -> Self::Out;
}
unsafe impl<T> AsDatatype for T where T: Equivalence
{
type Out = <T as Equivalence>::Out;
fn as_datatype(&self) -> Self::Out {
<T as Equivalence>::equivalent_datatype()
}
}
unsafe impl<T> AsDatatype for [T] where T: Equivalence
{
type Out = <T as Equivalence>::Out;
fn as_datatype(&self) -> Self::Out {
<T as Equivalence>::equivalent_datatype()
}
}
pub unsafe trait Collection {
fn count(&self) -> Count;
}
unsafe impl<T> Collection for T where T: Equivalence
{
fn count(&self) -> Count {
1
}
}
unsafe impl<T> Collection for [T] where T: Equivalence
{
fn count(&self) -> Count {
self.len().value_as().expect("Length of slice cannot be expressed as an MPI Count.")
}
}
pub unsafe trait Pointer {
unsafe fn pointer(&self) -> *const c_void;
}
unsafe impl<T> Pointer for T where T: Equivalence
{
unsafe fn pointer(&self) -> *const c_void {
let p: *const T = self;
p as *const c_void
}
}
unsafe impl<T> Pointer for [T] where T: Equivalence
{
unsafe fn pointer(&self) -> *const c_void {
mem::transmute(self.as_ptr())
}
}
pub unsafe trait PointerMut {
unsafe fn pointer_mut(&mut self) -> *mut c_void;
}
unsafe impl<T> PointerMut for T where T: Equivalence
{
unsafe fn pointer_mut(&mut self) -> *mut c_void {
let p: *mut T = self;
p as *mut c_void
}
}
unsafe impl<T> PointerMut for [T] where T: Equivalence
{
unsafe fn pointer_mut(&mut self) -> *mut c_void {
mem::transmute(self.as_mut_ptr())
}
}
pub unsafe trait Buffer: Pointer + Collection + AsDatatype { }
unsafe impl<T> Buffer for T where T: Equivalence
{}
unsafe impl<T> Buffer for [T] where T: Equivalence
{}
pub unsafe trait BufferMut: PointerMut + Collection + AsDatatype { }
unsafe impl<T> BufferMut for T where T: Equivalence
{}
unsafe impl<T> BufferMut for [T] where T: Equivalence
{}
#[derive(Copy, Clone, Debug)]
pub struct DynBuffer<'a> {
ptr: *const c_void,
len: Count,
datatype: DatatypeRef<'a>,
}
unsafe impl<'a> Send for DynBuffer<'a> {}
unsafe impl<'a> Sync for DynBuffer<'a> {}
unsafe impl<'a> Collection for DynBuffer<'a> {
fn count(&self) -> Count {
self.len
}
}
unsafe impl<'a> Pointer for DynBuffer<'a> {
unsafe fn pointer(&self) -> *const c_void {
self.ptr
}
}
unsafe impl<'a> AsDatatype for DynBuffer<'a> {
type Out = DatatypeRef<'a>;
fn as_datatype(&self) -> Self::Out {
self.datatype
}
}
unsafe impl<'a> Buffer for DynBuffer<'a> {}
impl<'a> DynBuffer<'a> {
pub fn new<T: Equivalence>(buf: &'a [T]) -> Self {
unsafe {
let datatype = DatatypeRef::from_raw(
T::equivalent_datatype().as_raw());
Self::from_raw(buf.as_ptr(), buf.count(), datatype)
}
}
pub fn is<T: Equivalence>(&self) -> bool {
self.as_datatype().as_raw() == T::equivalent_datatype().as_raw()
}
pub fn downcast<T: Equivalence>(self) -> Option<&'a [T]> {
if self.is::<T>() {
unsafe { Some(slice::from_raw_parts(self.as_ptr() as _, self.len())) }
} else {
None
}
}
pub unsafe fn from_raw<T>(ptr: *const T,
len: Count,
datatype: DatatypeRef<'a>) -> Self {
debug_assert!(!ptr.is_null());
Self { ptr: ptr as _, len, datatype }
}
pub fn len(&self) -> usize {
self.count().value_as().expect("Length of DynBuffer cannot be expressed as a usize")
}
pub fn as_ptr(&self) -> *const c_void {
self.ptr
}
}
#[derive(Debug)]
pub struct DynBufferMut<'a> {
ptr: *mut c_void,
len: Count,
datatype: DatatypeRef<'a>,
}
unsafe impl<'a> Send for DynBufferMut<'a> {}
unsafe impl<'a> Sync for DynBufferMut<'a> {}
unsafe impl<'a> Collection for DynBufferMut<'a> {
fn count(&self) -> Count {
self.len
}
}
unsafe impl<'a> Pointer for DynBufferMut<'a> {
unsafe fn pointer(&self) -> *const c_void {
self.ptr
}
}
unsafe impl<'a> PointerMut for DynBufferMut<'a> {
unsafe fn pointer_mut(&mut self) -> *mut c_void {
self.ptr
}
}
unsafe impl<'a> Buffer for DynBufferMut<'a> {}
unsafe impl<'a> BufferMut for DynBufferMut<'a> {}
unsafe impl<'a> AsDatatype for DynBufferMut<'a> {
type Out = DatatypeRef<'a>;
fn as_datatype(&self) -> Self::Out {
self.datatype
}
}
impl<'a> DynBufferMut<'a> {
pub fn new<T: Equivalence>(buf: &'a mut [T]) -> Self {
unsafe {
let datatype = DatatypeRef::from_raw(T::equivalent_datatype().as_raw());
Self::from_raw(buf.as_mut_ptr(), buf.count(), datatype)
}
}
pub fn is<T: Equivalence>(&self) -> bool {
self.as_datatype().as_raw() == T::equivalent_datatype().as_raw()
}
pub fn downcast<T: Equivalence>(mut self) -> Option<&'a mut [T]> {
if self.is::<T>() {
unsafe { Some(slice::from_raw_parts_mut(self.as_mut_ptr() as _, self.len())) }
} else {
None
}
}
pub unsafe fn from_raw<T>(ptr: *mut T,
len: Count,
datatype: DatatypeRef<'a>) -> Self {
debug_assert!(!ptr.is_null());
Self { ptr: ptr as _, len, datatype }
}
pub fn len(&self) -> usize {
self.count().value_as().expect("Length of DynBufferMut cannot be expressed as a usize")
}
pub fn as_ptr(&self) -> *const c_void {
self.ptr
}
pub fn as_mut_ptr(&mut self) -> *mut c_void {
self.ptr
}
pub fn reborrow(&self) -> DynBuffer {
unsafe { DynBuffer::from_raw(self.as_ptr(),
self.count(),
self.as_datatype()) }
}
pub fn reborrow_mut(&mut self) -> DynBufferMut {
unsafe { DynBufferMut::from_raw(self.as_mut_ptr(),
self.count(),
self.as_datatype()) }
}
pub fn downgrade(self) -> DynBuffer<'a> {
unsafe { DynBuffer::from_raw(self.as_ptr(),
self.count(),
self.as_datatype()) }
}
}
pub struct View<'d, 'b, D, B: ?Sized>
where D: 'd + Datatype,
B: 'b + Pointer
{
datatype: &'d D,
count: Count,
buffer: &'b B
}
impl<'d, 'b, D, B: ?Sized> View<'d, 'b, D, B>
where D: 'd + Datatype,
B: 'b + Pointer
{
pub unsafe fn with_count_and_datatype(buffer: &'b B,
count: Count,
datatype: &'d D)
-> View<'d, 'b, D, B> {
View {
datatype: datatype,
count: count,
buffer: buffer
}
}
}
unsafe impl<'d, 'b, D, B: ?Sized> AsDatatype for View<'d, 'b, D, B>
where D: 'd + Datatype,
B: 'b + Pointer
{
type Out = &'d D;
fn as_datatype(&self) -> Self::Out {
self.datatype
}
}
unsafe impl<'d, 'b, D, B: ?Sized> Collection for View<'d, 'b, D, B>
where D: 'd + Datatype,
B: 'b + Pointer
{
fn count(&self) -> Count {
self.count
}
}
unsafe impl<'d, 'b, D, B: ?Sized> Pointer for View<'d, 'b, D, B>
where D: 'd + Datatype,
B: 'b + Pointer
{
unsafe fn pointer(&self) -> *const c_void {
self.buffer.pointer()
}
}
unsafe impl<'d, 'b, D, B: ?Sized> Buffer for View<'d, 'b, D, B>
where D: 'd + Datatype,
B: 'b + Pointer
{}
pub struct MutView<'d, 'b, D, B: ?Sized>
where D: 'd + Datatype,
B: 'b + PointerMut
{
datatype: &'d D,
count: Count,
buffer: &'b mut B
}
impl<'d, 'b, D, B: ?Sized> MutView<'d, 'b, D, B>
where D: 'd + Datatype,
B: 'b + PointerMut
{
pub unsafe fn with_count_and_datatype(buffer: &'b mut B,
count: Count,
datatype: &'d D)
-> MutView<'d, 'b, D, B> {
MutView {
datatype: datatype,
count: count,
buffer: buffer
}
}
}
unsafe impl<'d, 'b, D, B: ?Sized> AsDatatype for MutView<'d, 'b, D, B>
where D: 'd + Datatype,
B: 'b + PointerMut
{
type Out = &'d D;
fn as_datatype(&self) -> Self::Out {
self.datatype
}
}
unsafe impl<'d, 'b, D, B: ?Sized> Collection for MutView<'d, 'b, D, B>
where D: 'd + Datatype,
B: 'b + PointerMut
{
fn count(&self) -> Count {
self.count
}
}
unsafe impl<'d, 'b, D, B: ?Sized> PointerMut for MutView<'d, 'b, D, B>
where D: 'd + Datatype,
B: 'b + PointerMut
{
unsafe fn pointer_mut(&mut self) -> *mut c_void {
self.buffer.pointer_mut()
}
}
unsafe impl<'d, 'b, D, B: ?Sized> BufferMut for MutView<'d, 'b, D, B>
where D: 'd + Datatype,
B: 'b + PointerMut
{}
pub trait Partitioned {
fn counts(&self) -> &[Count];
fn displs(&self) -> &[Count];
unsafe fn counts_ptr(&self) -> *const Count {
self.counts().as_ptr()
}
unsafe fn displs_ptr(&self) -> *const Count {
self.displs().as_ptr()
}
}
pub trait PartitionedBuffer: Partitioned + Pointer + AsDatatype { }
pub trait PartitionedBufferMut: Partitioned + PointerMut + AsDatatype { }
pub struct Partition<'b, B: 'b + ?Sized, C, D> {
buf: &'b B,
counts: C,
displs: D
}
impl<'b, B: ?Sized, C, D> Partition<'b, B, C, D>
where B: 'b + Buffer,
C: Borrow<[Count]>,
D: Borrow<[Count]>
{
pub fn new(buf: &B, counts: C, displs: D) -> Partition<B, C, D> {
let n = buf.count();
assert!(counts.borrow().iter().zip(displs.borrow().iter()).all(|(&c, &d)| c + d <= n));
Partition {
buf: buf,
counts: counts,
displs: displs
}
}
}
unsafe impl<'b, B: ?Sized, C, D> AsDatatype for Partition<'b, B, C, D> where B: 'b + AsDatatype
{
type Out = <B as AsDatatype>::Out;
fn as_datatype(&self) -> Self::Out {
self.buf.as_datatype()
}
}
unsafe impl<'b, B: ?Sized, C, D> Pointer for Partition<'b, B, C, D> where B: 'b + Pointer
{
unsafe fn pointer(&self) -> *const c_void {
self.buf.pointer()
}
}
impl<'b, B: ?Sized, C, D> Partitioned for Partition<'b, B, C, D>
where B: 'b,
C: Borrow<[Count]>,
D: Borrow<[Count]>
{
fn counts(&self) -> &[Count] {
self.counts.borrow()
}
fn displs(&self) -> &[Count] {
self.displs.borrow()
}
}
impl<'b, B: ?Sized, C, D> PartitionedBuffer for Partition<'b, B, C, D>
where B: 'b + Pointer + AsDatatype,
C: Borrow<[Count]>,
D: Borrow<[Count]>
{}
pub struct PartitionMut<'b, B: 'b + ?Sized, C, D> {
buf: &'b mut B,
counts: C,
displs: D
}
impl<'b, B: ?Sized, C, D> PartitionMut<'b, B, C, D>
where B: 'b + BufferMut,
C: Borrow<[Count]>,
D: Borrow<[Count]>
{
pub fn new(buf: &mut B, counts: C, displs: D) -> PartitionMut<B, C, D> {
let n = buf.count();
assert!(counts.borrow().iter().zip(displs.borrow().iter()).all(|(&c, &d)| c + d <= n));
PartitionMut {
buf: buf,
counts: counts,
displs: displs
}
}
}
unsafe impl<'b, B: ?Sized, C, D> AsDatatype for PartitionMut<'b, B, C, D> where B: 'b + AsDatatype
{
type Out = <B as AsDatatype>::Out;
fn as_datatype(&self) -> Self::Out {
self.buf.as_datatype()
}
}
unsafe impl<'b, B: ?Sized, C, D> PointerMut for PartitionMut<'b, B, C, D> where B: 'b + PointerMut
{
unsafe fn pointer_mut(&mut self) -> *mut c_void {
self.buf.pointer_mut()
}
}
impl<'b, B: ?Sized, C, D> Partitioned for PartitionMut<'b, B, C, D>
where B: 'b,
C: Borrow<[Count]>,
D: Borrow<[Count]>
{
fn counts(&self) -> &[Count] {
self.counts.borrow()
}
fn displs(&self) -> &[Count] {
self.displs.borrow()
}
}
impl<'b, B: ?Sized, C, D> PartitionedBufferMut for PartitionMut<'b, B, C, D>
where B: 'b + PointerMut + AsDatatype,
C: Borrow<[Count]>,
D: Borrow<[Count]>
{}
pub fn address_of<T>(x: &T) -> Address {
let mut address = unsafe { mem::uninitialized() };
let x: *const T = x;
unsafe {
ffi::MPI_Get_address(x as *const c_void, &mut address);
}
address
}