use std::ops::{BitOr, BitOrAssign};
use std::ptr::NonNull;
use std::sync::OnceLock;
use crate::error::{Error, Result};
use crate::ffi;
use crate::group::Group;
use crate::request::Request;
use crate::Communicator;
use crate::MpiDatatype;
use crate::ReduceOp;
#[derive(Debug, Clone, Copy, Default)]
pub struct WinFenceAssert(i32);
static FENCE_MODE_VALUES: OnceLock<[i32; 4]> = OnceLock::new();
fn fence_mode_values() -> [i32; 4] {
*FENCE_MODE_VALUES.get_or_init(|| {
let mut out = [0i32; 4];
let ret = unsafe { ffi::ferrompi_win_fence_mode_values(out.as_mut_ptr()) };
if ret != 0 {
[0i32; 4]
} else {
out
}
})
}
impl WinFenceAssert {
#[inline]
pub fn none() -> Self {
WinFenceAssert(0)
}
#[inline]
pub fn no_store() -> Self {
WinFenceAssert(fence_mode_values()[0])
}
#[inline]
pub fn no_put() -> Self {
WinFenceAssert(fence_mode_values()[1])
}
#[inline]
pub fn no_precede() -> Self {
WinFenceAssert(fence_mode_values()[2])
}
#[inline]
pub fn no_succeed() -> Self {
WinFenceAssert(fence_mode_values()[3])
}
#[inline]
pub fn bits(self) -> i32 {
self.0
}
#[cfg(test)]
pub(crate) fn from_bits_for_test(v: i32) -> Self {
WinFenceAssert(v)
}
}
impl BitOr for WinFenceAssert {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self {
WinFenceAssert(self.0 | rhs.0)
}
}
impl BitOrAssign for WinFenceAssert {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct WinPscwAssert(i32);
static PSCW_MODE_VALUES: OnceLock<[i32; 3]> = OnceLock::new();
fn pscw_mode_values() -> [i32; 3] {
*PSCW_MODE_VALUES.get_or_init(|| {
let mut out = [0i32; 3];
let ret = unsafe { ffi::ferrompi_win_pscw_mode_values(out.as_mut_ptr()) };
if ret != 0 {
[0i32; 3]
} else {
out
}
})
}
impl WinPscwAssert {
#[inline]
pub fn none() -> Self {
WinPscwAssert(0)
}
#[inline]
pub fn no_check() -> Self {
WinPscwAssert(pscw_mode_values()[0])
}
#[inline]
pub fn no_store() -> Self {
WinPscwAssert(pscw_mode_values()[1])
}
#[inline]
pub fn no_put() -> Self {
WinPscwAssert(pscw_mode_values()[2])
}
#[inline]
pub fn bits(self) -> i32 {
self.0
}
#[cfg(test)]
pub(crate) fn from_bits_for_test(v: i32) -> Self {
WinPscwAssert(v)
}
}
impl BitOr for WinPscwAssert {
type Output = Self;
#[inline]
fn bitor(self, rhs: Self) -> Self {
WinPscwAssert(self.0 | rhs.0)
}
}
impl BitOrAssign for WinPscwAssert {
#[inline]
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LockType {
Exclusive,
Shared,
}
pub struct SharedWindow<T: MpiDatatype> {
win_handle: i32,
local_ptr: NonNull<T>,
local_len: usize,
comm_size: i32,
}
impl<T: MpiDatatype> SharedWindow<T> {
pub fn allocate(comm: &Communicator, local_count: usize) -> Result<Self> {
let byte_size = local_count
.checked_mul(std::mem::size_of::<T>())
.ok_or(Error::InvalidBuffer)?;
let size = i64::try_from(byte_size).map_err(|_| Error::InvalidBuffer)?;
let disp_unit = std::mem::size_of::<T>() as i32;
let mut baseptr: *mut std::ffi::c_void = std::ptr::null_mut();
let mut win_handle: i32 = 0;
let ret = unsafe {
ffi::ferrompi_win_allocate_shared(
size,
disp_unit,
-1, comm.raw_handle(),
&mut baseptr,
&mut win_handle,
)
};
Error::check_with_op(ret, "win_allocate_shared")?;
let local_ptr = NonNull::new(baseptr.cast::<T>())
.ok_or_else(|| Error::Internal("Win_allocate_shared returned null".into()))?;
Ok(SharedWindow {
win_handle,
local_ptr,
local_len: local_count,
comm_size: comm.size(),
})
}
pub fn local_slice(&self) -> &[T] {
unsafe { std::slice::from_raw_parts(self.local_ptr.as_ptr(), self.local_len) }
}
pub fn local_slice_mut(&mut self) -> &mut [T] {
unsafe { std::slice::from_raw_parts_mut(self.local_ptr.as_ptr(), self.local_len) }
}
pub fn remote_slice(&self, rank: i32) -> Result<&[T]> {
let mut size: i64 = 0;
let mut disp_unit: i32 = 0;
let mut baseptr: *mut std::ffi::c_void = std::ptr::null_mut();
let ret = unsafe {
ffi::ferrompi_win_shared_query(
self.win_handle,
rank,
&mut size,
&mut disp_unit,
&mut baseptr,
)
};
Error::check_with_op(ret, "win_shared_query")?;
let count = size as usize / std::mem::size_of::<T>();
if baseptr.is_null() {
if count == 0 {
return Ok(unsafe {
std::slice::from_raw_parts(NonNull::<T>::dangling().as_ptr(), 0)
});
}
return Err(Error::Internal(
"MPI_Win_shared_query returned null for non-zero size".into(),
));
}
Ok(unsafe { std::slice::from_raw_parts(baseptr.cast::<T>(), count) })
}
pub fn fence(&self) -> Result<()> {
let ret = unsafe { ffi::ferrompi_win_fence(0, self.win_handle) };
Error::check_with_op(ret, "win_fence")
}
pub fn lock(&self, lock_type: LockType, rank: i32) -> Result<LockGuard<'_, T>> {
let lt = match lock_type {
LockType::Exclusive => ffi::FERROMPI_LOCK_EXCLUSIVE,
LockType::Shared => ffi::FERROMPI_LOCK_SHARED,
};
let ret = unsafe { ffi::ferrompi_win_lock(lt, rank, 0, self.win_handle) };
Error::check_with_op(ret, "win_lock")?;
Ok(LockGuard { window: self, rank })
}
pub fn lock_all(&self) -> Result<LockAllGuard<'_, T>> {
let ret = unsafe { ffi::ferrompi_win_lock_all(0, self.win_handle) };
Error::check_with_op(ret, "win_lock_all")?;
Ok(LockAllGuard { window: self })
}
pub fn raw_handle(&self) -> i32 {
self.win_handle
}
pub fn comm_size(&self) -> i32 {
self.comm_size
}
}
impl<T: MpiDatatype> Drop for SharedWindow<T> {
fn drop(&mut self) {
unsafe { ffi::ferrompi_win_free(self.win_handle) };
}
}
pub struct PendingFetchResult<T> {
_origin: Box<T>,
_compare: Option<Box<T>>,
result: Box<std::mem::MaybeUninit<T>>,
}
impl<T: Copy> PendingFetchResult<T> {
#[inline]
pub unsafe fn resolve(self) -> T {
(*self.result).assume_init()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum WinKind {
Created,
Allocated,
}
pub struct Win<'a, T: MpiDatatype> {
win_handle: i32,
local_ptr: NonNull<T>,
local_len: usize,
comm_size: i32,
#[allow(dead_code)]
kind: WinKind,
_marker: std::marker::PhantomData<&'a mut [T]>,
}
impl<'a, T: MpiDatatype> Win<'a, T> {
pub fn create(comm: &Communicator, buf: &'a mut [T]) -> crate::error::Result<Self> {
let byte_size = buf
.len()
.checked_mul(std::mem::size_of::<T>())
.ok_or(Error::InvalidBuffer)?;
let size = i64::try_from(byte_size).map_err(|_| Error::InvalidBuffer)?;
let disp_unit = std::mem::size_of::<T>() as i32;
let mut win_handle: i32 = 0;
let ret = unsafe {
ffi::ferrompi_win_create(
buf.as_mut_ptr().cast::<std::ffi::c_void>(),
size,
disp_unit,
-1, comm.raw_handle(),
&mut win_handle,
)
};
Error::check_with_op(ret, "win_create")?;
let local_ptr = if buf.is_empty() {
NonNull::<T>::dangling()
} else {
unsafe { NonNull::new_unchecked(buf.as_mut_ptr()) }
};
Ok(Win {
win_handle,
local_ptr,
local_len: buf.len(),
comm_size: comm.size(),
kind: WinKind::Created,
_marker: std::marker::PhantomData,
})
}
}
impl<T: MpiDatatype> Win<'static, T> {
pub fn allocate(comm: &Communicator, local_count: usize) -> crate::error::Result<Self> {
let byte_size = local_count
.checked_mul(std::mem::size_of::<T>())
.ok_or(Error::InvalidBuffer)?;
let size = i64::try_from(byte_size).map_err(|_| Error::InvalidBuffer)?;
let disp_unit = std::mem::size_of::<T>() as i32;
let mut baseptr: *mut std::ffi::c_void = std::ptr::null_mut();
let mut win_handle: i32 = 0;
let ret = unsafe {
ffi::ferrompi_win_allocate(
size,
disp_unit,
-1, comm.raw_handle(),
&mut baseptr,
&mut win_handle,
)
};
Error::check_with_op(ret, "win_allocate")?;
let local_ptr = if local_count == 0 {
NonNull::<T>::dangling()
} else {
NonNull::new(baseptr.cast::<T>()).ok_or_else(|| {
Error::Internal("Win_allocate returned null base pointer for non-zero count".into())
})?
};
Ok(Win {
win_handle,
local_ptr,
local_len: local_count,
comm_size: comm.size(),
kind: WinKind::Allocated,
_marker: std::marker::PhantomData,
})
}
}
impl<T: MpiDatatype> Win<'_, T> {
pub fn local_slice(&self) -> &[T] {
unsafe { std::slice::from_raw_parts(self.local_ptr.as_ptr(), self.local_len) }
}
pub fn local_slice_mut(&mut self) -> &mut [T] {
unsafe { std::slice::from_raw_parts_mut(self.local_ptr.as_ptr(), self.local_len) }
}
pub fn raw_handle(&self) -> i32 {
self.win_handle
}
pub fn comm_size(&self) -> i32 {
self.comm_size
}
pub fn fence(&self, assert: WinFenceAssert) -> Result<()> {
let ret = unsafe { ffi::ferrompi_win_fence(assert.bits(), self.win_handle) };
Error::check_with_op(ret, "win_fence")
}
pub fn post(&self, group: &Group, assert: WinPscwAssert) -> Result<()> {
let ret =
unsafe { ffi::ferrompi_win_post(group.raw_handle(), assert.bits(), self.win_handle) };
Error::check_with_op(ret, "win_post")
}
pub fn start(&self, group: &Group, assert: WinPscwAssert) -> Result<()> {
let ret =
unsafe { ffi::ferrompi_win_start(group.raw_handle(), assert.bits(), self.win_handle) };
Error::check_with_op(ret, "win_start")
}
pub fn complete(&self) -> Result<()> {
let ret = unsafe { ffi::ferrompi_win_complete(self.win_handle) };
Error::check_with_op(ret, "win_complete")
}
pub fn wait_exposure(&self) -> Result<()> {
let ret = unsafe { ffi::ferrompi_win_wait(self.win_handle) };
Error::check_with_op(ret, "win_wait")
}
pub fn test_exposure(&self) -> Result<bool> {
let mut flag: i32 = 0;
let ret = unsafe { ffi::ferrompi_win_test(self.win_handle, &mut flag) };
Error::check_with_op(ret, "win_test")?;
Ok(flag != 0)
}
}
impl<T: MpiDatatype> Win<'_, T> {
pub fn lock(&self, lock_type: LockType, rank: i32) -> Result<WinLockGuard<'_, '_, T>> {
let lt = match lock_type {
LockType::Exclusive => ffi::FERROMPI_LOCK_EXCLUSIVE,
LockType::Shared => ffi::FERROMPI_LOCK_SHARED,
};
let ret = unsafe { ffi::ferrompi_win_lock(lt, rank, 0, self.win_handle) };
Error::check_with_op(ret, "win_lock")?;
Ok(WinLockGuard { window: self, rank })
}
pub fn lock_all(&self) -> Result<WinLockAllGuard<'_, '_, T>> {
let ret = unsafe { ffi::ferrompi_win_lock_all(0, self.win_handle) };
Error::check_with_op(ret, "win_lock_all")?;
Ok(WinLockAllGuard { window: self })
}
}
impl<T: MpiDatatype> Win<'_, T> {
pub fn flush_local(&self, rank: i32) -> Result<()> {
let ret = unsafe { ffi::ferrompi_win_flush_local(rank, self.win_handle) };
Error::check_with_op(ret, "win_flush_local")
}
pub fn flush_local_all(&self) -> Result<()> {
let ret = unsafe { ffi::ferrompi_win_flush_local_all(self.win_handle) };
Error::check_with_op(ret, "win_flush_local_all")
}
pub fn sync(&self) -> Result<()> {
let ret = unsafe { ffi::ferrompi_win_sync(self.win_handle) };
Error::check_with_op(ret, "win_sync")
}
}
impl<T: MpiDatatype> Win<'_, T> {
pub fn put(
&self,
origin: &[T],
target_rank: i32,
target_disp: i64,
target_count: i64,
) -> Result<()> {
let origin_count = i64::try_from(origin.len()).map_err(|_| Error::InvalidBuffer)?;
let ret = unsafe {
ffi::ferrompi_put(
origin.as_ptr().cast::<std::ffi::c_void>(),
origin_count,
T::TAG as i32,
target_rank,
target_disp,
target_count,
T::TAG as i32,
self.win_handle,
)
};
Error::check_with_op(ret, "put")
}
pub fn rput(
&self,
origin: &[T],
target_rank: i32,
target_disp: i64,
target_count: i64,
) -> Result<Request> {
let origin_count = i64::try_from(origin.len()).map_err(|_| Error::InvalidBuffer)?;
let mut request_handle: i64 = 0;
let ret = unsafe {
ffi::ferrompi_rput(
origin.as_ptr().cast::<std::ffi::c_void>(),
origin_count,
T::TAG as i32,
target_rank,
target_disp,
target_count,
T::TAG as i32,
self.win_handle,
&mut request_handle,
)
};
Error::check_with_op(ret, "rput")?;
Ok(Request::new(request_handle))
}
pub fn get(
&self,
origin: &mut [T],
target_rank: i32,
target_disp: i64,
target_count: i64,
) -> Result<()> {
let origin_count = i64::try_from(origin.len()).map_err(|_| Error::InvalidBuffer)?;
let ret = unsafe {
ffi::ferrompi_get(
origin.as_mut_ptr().cast::<std::ffi::c_void>(),
origin_count,
T::TAG as i32,
target_rank,
target_disp,
target_count,
T::TAG as i32,
self.win_handle,
)
};
Error::check_with_op(ret, "get")
}
pub fn rget(
&self,
origin: &mut [T],
target_rank: i32,
target_disp: i64,
target_count: i64,
) -> Result<Request> {
let origin_count = i64::try_from(origin.len()).map_err(|_| Error::InvalidBuffer)?;
let mut request_handle: i64 = 0;
let ret = unsafe {
ffi::ferrompi_rget(
origin.as_mut_ptr().cast::<std::ffi::c_void>(),
origin_count,
T::TAG as i32,
target_rank,
target_disp,
target_count,
T::TAG as i32,
self.win_handle,
&mut request_handle,
)
};
Error::check_with_op(ret, "rget")?;
Ok(Request::new(request_handle))
}
pub fn accumulate(
&self,
origin: &[T],
target_rank: i32,
target_disp: i64,
target_count: i64,
op: ReduceOp,
) -> Result<()> {
let origin_count = i64::try_from(origin.len()).map_err(|_| Error::InvalidBuffer)?;
let ret = unsafe {
ffi::ferrompi_accumulate(
origin.as_ptr().cast::<std::ffi::c_void>(),
origin_count,
T::TAG as i32,
target_rank,
target_disp,
target_count,
T::TAG as i32,
op as i32,
self.win_handle,
)
};
Error::check_with_op(ret, "accumulate")
}
pub fn raccumulate(
&self,
origin: &[T],
target_rank: i32,
target_disp: i64,
target_count: i64,
op: ReduceOp,
) -> Result<Request> {
let origin_count = i64::try_from(origin.len()).map_err(|_| Error::InvalidBuffer)?;
let mut request_handle: i64 = 0;
let ret = unsafe {
ffi::ferrompi_raccumulate(
origin.as_ptr().cast::<std::ffi::c_void>(),
origin_count,
T::TAG as i32,
target_rank,
target_disp,
target_count,
T::TAG as i32,
op as i32,
self.win_handle,
&mut request_handle,
)
};
Error::check_with_op(ret, "raccumulate")?;
Ok(Request::new(request_handle))
}
pub fn get_accumulate(
&self,
origin: &[T],
result: &mut [T],
target_rank: i32,
target_disp: i64,
target_count: i64,
op: ReduceOp,
) -> Result<()> {
let origin_count = i64::try_from(origin.len()).map_err(|_| Error::InvalidBuffer)?;
let result_count = i64::try_from(result.len()).map_err(|_| Error::InvalidBuffer)?;
let ret = unsafe {
ffi::ferrompi_get_accumulate(
origin.as_ptr().cast::<std::ffi::c_void>(),
origin_count,
T::TAG as i32,
result.as_mut_ptr().cast::<std::ffi::c_void>(),
result_count,
T::TAG as i32,
target_rank,
target_disp,
target_count,
T::TAG as i32,
op as i32,
self.win_handle,
)
};
Error::check_with_op(ret, "get_accumulate")
}
pub fn fetch_and_op(
&self,
origin: T,
target_rank: i32,
target_disp: i64,
op: ReduceOp,
) -> Result<PendingFetchResult<T>> {
use std::mem::MaybeUninit;
let origin_box: Box<T> = Box::new(origin);
let result_box: Box<MaybeUninit<T>> = Box::new(MaybeUninit::uninit());
let ret = unsafe {
ffi::ferrompi_fetch_and_op(
(origin_box.as_ref() as *const T).cast::<std::ffi::c_void>(),
(result_box.as_ref() as *const MaybeUninit<T> as *mut MaybeUninit<T>)
.cast::<std::ffi::c_void>(),
T::TAG as i32,
target_rank,
target_disp,
op as i32,
self.win_handle,
)
};
Error::check_with_op(ret, "fetch_and_op")?;
Ok(PendingFetchResult {
_origin: origin_box,
_compare: None,
result: result_box,
})
}
}
impl<'a, T: crate::AtomicMpiDatatype + MpiDatatype> Win<'a, T> {
pub fn compare_and_swap(
&self,
origin: T,
compare: T,
target_rank: i32,
target_disp: i64,
) -> crate::error::Result<PendingFetchResult<T>> {
use std::mem::MaybeUninit;
let origin_box: Box<T> = Box::new(origin);
let compare_box: Box<T> = Box::new(compare);
let result_box: Box<MaybeUninit<T>> = Box::new(MaybeUninit::uninit());
let ret = unsafe {
ffi::ferrompi_compare_and_swap(
(origin_box.as_ref() as *const T).cast::<std::ffi::c_void>(),
(compare_box.as_ref() as *const T).cast::<std::ffi::c_void>(),
(result_box.as_ref() as *const MaybeUninit<T> as *mut MaybeUninit<T>)
.cast::<std::ffi::c_void>(),
T::TAG as i32,
target_rank,
target_disp,
self.win_handle,
)
};
Error::check_with_op(ret, "compare_and_swap")?;
Ok(PendingFetchResult {
_origin: origin_box,
_compare: Some(compare_box),
result: result_box,
})
}
}
impl<T: MpiDatatype> Drop for Win<'_, T> {
fn drop(&mut self) {
unsafe { ffi::ferrompi_win_free(self.win_handle) };
}
}
pub struct LockGuard<'a, T: MpiDatatype> {
window: &'a SharedWindow<T>,
rank: i32,
}
impl<T: MpiDatatype> LockGuard<'_, T> {
pub fn flush(&self) -> Result<()> {
let ret = unsafe { ffi::ferrompi_win_flush(self.rank, self.window.win_handle) };
Error::check_with_op(ret, "win_flush")
}
}
impl<T: MpiDatatype> Drop for LockGuard<'_, T> {
fn drop(&mut self) {
unsafe { ffi::ferrompi_win_unlock(self.rank, self.window.win_handle) };
}
}
pub struct LockAllGuard<'a, T: MpiDatatype> {
window: &'a SharedWindow<T>,
}
impl<T: MpiDatatype> LockAllGuard<'_, T> {
pub fn flush_all(&self) -> Result<()> {
let ret = unsafe { ffi::ferrompi_win_flush_all(self.window.win_handle) };
Error::check_with_op(ret, "win_flush_all")
}
pub fn flush(&self, rank: i32) -> Result<()> {
let ret = unsafe { ffi::ferrompi_win_flush(rank, self.window.win_handle) };
Error::check_with_op(ret, "win_flush")
}
}
impl<T: MpiDatatype> Drop for LockAllGuard<'_, T> {
fn drop(&mut self) {
unsafe { ffi::ferrompi_win_unlock_all(self.window.win_handle) };
}
}
pub struct WinLockGuard<'g, 'a, T: MpiDatatype> {
window: &'g Win<'a, T>,
rank: i32,
}
impl<T: MpiDatatype> WinLockGuard<'_, '_, T> {
pub fn flush(&self) -> Result<()> {
let ret = unsafe { ffi::ferrompi_win_flush(self.rank, self.window.win_handle) };
Error::check_with_op(ret, "win_flush")
}
}
impl<T: MpiDatatype> Drop for WinLockGuard<'_, '_, T> {
fn drop(&mut self) {
unsafe { ffi::ferrompi_win_unlock(self.rank, self.window.win_handle) };
}
}
pub struct WinLockAllGuard<'g, 'a, T: MpiDatatype> {
window: &'g Win<'a, T>,
}
impl<T: MpiDatatype> WinLockAllGuard<'_, '_, T> {
pub fn flush_all(&self) -> Result<()> {
let ret = unsafe { ffi::ferrompi_win_flush_all(self.window.win_handle) };
Error::check_with_op(ret, "win_flush_all")
}
pub fn flush(&self, rank: i32) -> Result<()> {
let ret = unsafe { ffi::ferrompi_win_flush(rank, self.window.win_handle) };
Error::check_with_op(ret, "win_flush")
}
}
impl<T: MpiDatatype> Drop for WinLockAllGuard<'_, '_, T> {
fn drop(&mut self) {
unsafe { ffi::ferrompi_win_unlock_all(self.window.win_handle) };
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn lock_type_equality() {
assert_eq!(LockType::Exclusive, LockType::Exclusive);
assert_eq!(LockType::Shared, LockType::Shared);
assert_ne!(LockType::Exclusive, LockType::Shared);
}
#[test]
fn lock_type_debug() {
assert_eq!(format!("{:?}", LockType::Exclusive), "Exclusive");
assert_eq!(format!("{:?}", LockType::Shared), "Shared");
}
#[test]
#[allow(clippy::clone_on_copy)]
fn lock_type_clone_copy() {
let original = LockType::Exclusive;
let copied = original; let cloned = original.clone(); assert_eq!(original, copied);
assert_eq!(original, cloned);
let original = LockType::Shared;
let copied = original; let cloned = original.clone(); assert_eq!(original, copied);
assert_eq!(original, cloned);
}
#[test]
fn win_kind_equality() {
assert_eq!(WinKind::Created, WinKind::Created);
assert_eq!(WinKind::Allocated, WinKind::Allocated);
assert_ne!(WinKind::Created, WinKind::Allocated);
}
#[test]
fn win_kind_debug() {
assert_eq!(format!("{:?}", WinKind::Created), "Created");
assert_eq!(format!("{:?}", WinKind::Allocated), "Allocated");
}
#[test]
#[allow(clippy::clone_on_copy)]
fn win_kind_clone_copy() {
let original = WinKind::Created;
let copied = original;
let cloned = original.clone();
assert_eq!(original, copied);
assert_eq!(original, cloned);
}
#[test]
fn win_struct_compiles() {
fn _check<'a, T: MpiDatatype>(_: &Win<'a, T>) {}
}
#[test]
fn win_put_signature_compiles() {
fn _check<'a, T: MpiDatatype>(w: &Win<'a, T>, buf: &[T]) -> Result<()> {
w.put(buf, 0, 0, buf.len() as i64)
}
}
#[test]
fn win_rput_signature_compiles() {
fn _check<'a, T: MpiDatatype>(w: &Win<'a, T>, buf: &[T]) -> Result<Request> {
w.rput(buf, 0, 0, buf.len() as i64)
}
}
#[test]
fn win_get_signature_compiles() {
fn _check<'a, T: MpiDatatype>(w: &Win<'a, T>, buf: &mut [T]) -> Result<()> {
w.get(buf, 0, 0, buf.len() as i64)
}
}
#[test]
fn win_rget_signature_compiles() {
fn _check<'a, T: MpiDatatype>(w: &Win<'a, T>, buf: &mut [T]) -> Result<Request> {
w.rget(buf, 0, 0, buf.len() as i64)
}
}
#[test]
fn win_accumulate_signature_compiles() {
fn _check<'a, T: MpiDatatype>(w: &Win<'a, T>, buf: &[T]) -> Result<()> {
w.accumulate(buf, 0, 0, buf.len() as i64, ReduceOp::Sum)
}
}
#[test]
fn win_raccumulate_signature_compiles() {
fn _check<'a, T: MpiDatatype>(w: &Win<'a, T>, buf: &[T]) -> Result<Request> {
w.raccumulate(buf, 0, 0, buf.len() as i64, ReduceOp::Sum)
}
}
#[test]
fn win_get_accumulate_signature_compiles() {
fn _check<'a, T: MpiDatatype>(w: &Win<'a, T>, o: &[T], r: &mut [T]) -> Result<()> {
w.get_accumulate(o, r, 0, 0, o.len() as i64, ReduceOp::Sum)
}
}
#[test]
fn win_fetch_and_op_signature_compiles() {
fn _check_i32(w: &Win<'_, i32>) -> Result<PendingFetchResult<i32>> {
w.fetch_and_op(1, 0, 0, ReduceOp::Sum)
}
fn _check_u64(w: &Win<'_, u64>) -> Result<PendingFetchResult<u64>> {
w.fetch_and_op(1u64, 0, 0, ReduceOp::Sum)
}
fn _check_f64(w: &Win<'_, f64>) -> Result<PendingFetchResult<f64>> {
w.fetch_and_op(1.0, 0, 0, ReduceOp::Sum)
}
let _ = _check_i32 as fn(&Win<'_, i32>) -> Result<PendingFetchResult<i32>>;
let _ = _check_u64 as fn(&Win<'_, u64>) -> Result<PendingFetchResult<u64>>;
let _ = _check_f64 as fn(&Win<'_, f64>) -> Result<PendingFetchResult<f64>>;
}
#[test]
fn win_compare_and_swap_signature_compiles() {
fn _check_i32(w: &Win<'_, i32>) -> Result<PendingFetchResult<i32>> {
w.compare_and_swap(200, 100, 0, 0)
}
fn _check_i64(w: &Win<'_, i64>) -> Result<PendingFetchResult<i64>> {
w.compare_and_swap(200i64, 100i64, 0, 0)
}
fn _check_u32(w: &Win<'_, u32>) -> Result<PendingFetchResult<u32>> {
w.compare_and_swap(200u32, 100u32, 0, 0)
}
fn _check_u64(w: &Win<'_, u64>) -> Result<PendingFetchResult<u64>> {
w.compare_and_swap(200u64, 100u64, 0, 0)
}
fn _check_u8(w: &Win<'_, u8>) -> Result<PendingFetchResult<u8>> {
w.compare_and_swap(2u8, 1u8, 0, 0)
}
let _ = _check_i32 as fn(&Win<'_, i32>) -> Result<PendingFetchResult<i32>>;
let _ = _check_i64 as fn(&Win<'_, i64>) -> Result<PendingFetchResult<i64>>;
let _ = _check_u32 as fn(&Win<'_, u32>) -> Result<PendingFetchResult<u32>>;
let _ = _check_u64 as fn(&Win<'_, u64>) -> Result<PendingFetchResult<u64>>;
let _ = _check_u8 as fn(&Win<'_, u8>) -> Result<PendingFetchResult<u8>>;
}
#[test]
fn win_forget_does_not_drop() {
let win: Win<'static, i32> = Win {
win_handle: -1,
local_ptr: std::ptr::NonNull::dangling(),
local_len: 0,
comm_size: 1,
kind: WinKind::Created,
_marker: std::marker::PhantomData,
};
std::mem::forget(win);
}
#[test]
fn win_fence_assert_default_is_none() {
let a = WinFenceAssert::default();
assert_eq!(a.bits(), 0);
}
#[test]
fn win_fence_assert_none_constructor_is_zero() {
assert_eq!(WinFenceAssert::none().bits(), 0);
}
#[test]
fn win_fence_assert_or_combines_bits() {
let a = WinFenceAssert::from_bits_for_test(1);
let b = WinFenceAssert::from_bits_for_test(2);
assert_eq!((a | b).bits(), 3);
}
#[test]
fn win_fence_assert_or_assign_combines_bits() {
let mut a = WinFenceAssert::from_bits_for_test(1);
a |= WinFenceAssert::from_bits_for_test(4);
assert_eq!(a.bits(), 5);
}
#[test]
fn win_fence_assert_debug_is_implemented() {
let a = WinFenceAssert::none();
let s = format!("{a:?}");
assert!(!s.is_empty());
}
#[test]
fn win_fence_assert_copy_and_clone() {
let a = WinFenceAssert::from_bits_for_test(7);
let b = a; let c = a; assert_eq!(b.bits(), 7);
assert_eq!(c.bits(), 7);
}
#[test]
fn win_pscw_assert_default_is_none() {
let a = WinPscwAssert::default();
assert_eq!(a.bits(), 0);
}
#[test]
fn win_pscw_assert_none_constructor_is_zero() {
assert_eq!(WinPscwAssert::none().bits(), 0);
}
#[test]
fn win_pscw_assert_or_combines_bits() {
let a = WinPscwAssert::from_bits_for_test(1);
let b = WinPscwAssert::from_bits_for_test(2);
assert_eq!((a | b).bits(), 3);
}
#[test]
fn win_pscw_assert_or_assign_combines_bits() {
let mut a = WinPscwAssert::from_bits_for_test(1);
a |= WinPscwAssert::from_bits_for_test(4);
assert_eq!(a.bits(), 5);
}
#[test]
fn win_pscw_assert_debug_is_implemented() {
let a = WinPscwAssert::none();
let s = format!("{a:?}");
assert!(!s.is_empty());
}
#[test]
fn win_pscw_assert_copy_and_clone() {
let a = WinPscwAssert::from_bits_for_test(7);
let b = a; let c = a; assert_eq!(b.bits(), 7);
assert_eq!(c.bits(), 7);
}
#[test]
fn win_lock_guard_type_compiles() {
fn _check<'g, 'a, T: MpiDatatype>(_: &WinLockGuard<'g, 'a, T>) {}
fn _check_all<'g, 'a, T: MpiDatatype>(_: &WinLockAllGuard<'g, 'a, T>) {}
}
#[test]
fn win_lock_guard_forget_does_not_drop() {
let win: Win<'static, f64> = Win {
win_handle: -1,
local_ptr: std::ptr::NonNull::dangling(),
local_len: 0,
comm_size: 1,
kind: WinKind::Created,
_marker: std::marker::PhantomData,
};
let guard = WinLockGuard {
window: &win,
rank: 0,
};
std::mem::forget(guard);
std::mem::forget(win);
}
#[test]
fn win_lock_all_guard_forget_does_not_drop() {
let win: Win<'static, f64> = Win {
win_handle: -1,
local_ptr: std::ptr::NonNull::dangling(),
local_len: 0,
comm_size: 1,
kind: WinKind::Created,
_marker: std::marker::PhantomData,
};
let guard = WinLockAllGuard { window: &win };
std::mem::forget(guard);
std::mem::forget(win);
}
}