use std::{any::TypeId, collections::HashMap, ffi::c_void, os::raw::c_int, ptr, sync::RwLock};
use once_cell::sync::Lazy;
use crate::{ffi, traits::AsRaw};
pub mod traits {
pub use super::CommAttribute;
}
pub(crate) static COMM_ATTRS: Lazy<RwLock<HashMap<TypeId, AttributeKey>>> =
Lazy::new(|| RwLock::new(HashMap::new()));
pub trait CommAttribute
where
Self: 'static + Sized + Clone,
{
const CLONE_ON_DUP: bool = false;
unsafe extern "C" fn comm_delete_attr_fn(
_comm: ffi::MPI_Comm,
_key: c_int,
val: *mut c_void,
_extra_state: *mut c_void,
) -> c_int {
let _to_drop = Box::from_raw(val as *mut Self);
ffi::MPI_SUCCESS as i32
}
unsafe extern "C" fn comm_copy_attr_fn(
_old_comm: ffi::MPI_Comm,
_key: c_int,
_extra_state: *mut c_void,
val_in: *mut c_void,
val_out: *mut c_void,
flag: *mut c_int,
) -> c_int {
if Self::CLONE_ON_DUP {
let b_in = Box::from_raw(val_in as *mut Self);
let b_out = b_in.clone();
*(val_out as *mut *mut Self) = Box::into_raw(b_out);
Box::into_raw(b_in); *flag = 1;
} else {
*flag = 0;
}
ffi::MPI_SUCCESS as i32
}
fn get_key() -> AttributeKey {
let id = TypeId::of::<Self>();
{
let comm_attrs = COMM_ATTRS.read().expect("COMM_ATTRS RwLock poisoned");
if let Some(key) = comm_attrs.get(&id) {
return key.clone();
}
}
let mut key: i32 = 0;
unsafe {
ffi::MPI_Comm_create_keyval(
Some(Self::comm_copy_attr_fn),
Some(Self::comm_delete_attr_fn),
&mut key,
ptr::null_mut(),
);
}
let key = AttributeKey(key);
let mut comm_attrs = COMM_ATTRS.write().expect("COMM_ATTRS RwLock poisoned");
comm_attrs.insert(id, key.clone());
key
}
}
#[allow(missing_copy_implementations)]
#[derive(Debug, Clone)]
pub struct AttributeKey(i32);
impl AttributeKey {
pub unsafe fn new_unchecked(k: i32) -> Self {
Self(k)
}
}
unsafe impl AsRaw for AttributeKey {
type Raw = c_int;
fn as_raw(&self) -> Self::Raw {
self.0
}
}
#[repr(C)]
#[derive(Clone)]
pub(crate) struct UniverseSize(c_int);
impl CommAttribute for UniverseSize {
fn get_key() -> AttributeKey {
unsafe { AttributeKey::new_unchecked(ffi::MPI_UNIVERSE_SIZE as i32) }
}
}
impl TryFrom<&UniverseSize> for usize {
type Error = std::num::TryFromIntError;
fn try_from(s: &UniverseSize) -> Result<Self, Self::Error> {
usize::try_from(s.0)
}
}
#[repr(C)]
#[derive(Clone)]
pub(crate) struct AppNum(c_int);
impl CommAttribute for AppNum {
fn get_key() -> AttributeKey {
unsafe { AttributeKey::new_unchecked(ffi::MPI_APPNUM as i32) }
}
}
impl From<&AppNum> for isize {
fn from(an: &AppNum) -> Self {
an.0 as isize
}
}