use std::cell::Cell;
use std::mem;
use std::marker::PhantomData;
use std::os::raw::c_int;
use ffi;
use ffi::{MPI_Request, MPI_Status};
use point_to_point::Status;
use raw::traits::*;
fn is_null(request: MPI_Request) -> bool {
request == unsafe_extern_static!(ffi::RSMPI_REQUEST_NULL)
}
#[must_use]
#[derive(Debug)]
pub struct Request<'a, S: Scope<'a> = StaticScope> {
request: MPI_Request,
scope: S,
phantom: PhantomData<Cell<&'a ()>>,
}
unsafe impl<'a, S: Scope<'a>> AsRaw for Request<'a, S> {
type Raw = MPI_Request;
fn as_raw(&self) -> Self::Raw {
self.request
}
}
impl<'a, S: Scope<'a>> Drop for Request<'a, S> {
fn drop(&mut self) {
panic!("request was dropped without being completed");
}
}
impl<'a, S: Scope<'a>> Request<'a, S> {
pub unsafe fn from_raw(request: MPI_Request, scope: S) -> Self {
debug_assert!(!is_null(request));
scope.register();
Self {
request: request,
scope: scope,
phantom: Default::default(),
}
}
pub unsafe fn into_raw(mut self) -> (MPI_Request, S) {
let request = mem::replace(&mut self.request, mem::uninitialized());
let scope = mem::replace(&mut self.scope, mem::uninitialized());
let _ = mem::replace(&mut self.phantom, mem::uninitialized());
mem::forget(self);
scope.unregister();
(request, scope)
}
fn wait_with(self, status: Option<&mut MPI_Status>) {
unsafe {
let (mut request, _) = self.into_raw();
let status = match status {
Some(r) => r,
None => ffi::RSMPI_STATUS_IGNORE,
};
ffi::MPI_Wait(&mut request, status);
assert!(is_null(request)); }
}
pub fn wait(self) -> Status {
let mut status: MPI_Status = unsafe { mem::uninitialized() };
self.wait_with(Some(&mut status));
Status::from_raw(status)
}
pub fn wait_without_status(self) {
self.wait_with(None);
}
pub fn test(self) -> Result<Status, Self> {
unsafe {
let mut status: MPI_Status = mem::uninitialized();
let mut flag: c_int = mem::uninitialized();
let mut request = self.as_raw();
ffi::MPI_Test(&mut request, &mut flag, &mut status);
if flag != 0 {
assert!(is_null(request)); self.into_raw();
Ok(Status::from_raw(status))
} else {
Err(self)
}
}
}
pub fn cancel(&self) {
let mut request = self.as_raw();
unsafe {
ffi::MPI_Cancel(&mut request);
}
}
pub fn shrink_scope_to<'b, S2>(self, scope: S2) -> Request<'b, S2>
where 'a: 'b, S2: Scope<'b>
{
unsafe {
let (request, _) = self.into_raw();
Request::from_raw(request, scope)
}
}
}
#[derive(Debug)]
pub struct WaitGuard<'a, S: Scope<'a> = StaticScope>(Option<Request<'a, S>>);
impl<'a, S: Scope<'a>> Drop for WaitGuard<'a, S> {
fn drop(&mut self) {
self.0.take().expect("invalid WaitGuard").wait();
}
}
unsafe impl<'a, S: Scope<'a>> AsRaw for WaitGuard<'a, S> {
type Raw = MPI_Request;
fn as_raw(&self) -> Self::Raw {
self.0.as_ref().expect("invalid WaitGuard").as_raw()
}
}
impl<'a, S: Scope<'a>> From<WaitGuard<'a, S>> for Request<'a, S> {
fn from(mut guard: WaitGuard<'a, S>) -> Self {
guard.0.take().expect("invalid WaitGuard")
}
}
impl<'a, S: Scope<'a>> From<Request<'a, S>> for WaitGuard<'a, S> {
fn from(req: Request<'a, S>) -> Self {
WaitGuard(Some(req))
}
}
impl<'a, S: Scope<'a>> WaitGuard<'a, S> {
fn cancel(&self) {
if let Some(ref req) = self.0 {
req.cancel();
}
}
}
#[derive(Debug)]
pub struct CancelGuard<'a, S: Scope<'a> = StaticScope>(WaitGuard<'a, S>);
impl<'a, S: Scope<'a>> Drop for CancelGuard<'a, S> {
fn drop(&mut self) {
self.0.cancel();
}
}
impl<'a, S: Scope<'a>> From<CancelGuard<'a, S>> for WaitGuard<'a, S> {
fn from(mut guard: CancelGuard<'a, S>) -> Self {
unsafe {
let inner = mem::replace(&mut guard.0, mem::uninitialized());
mem::forget(guard);
inner
}
}
}
impl<'a, S: Scope<'a>> From<WaitGuard<'a, S>> for CancelGuard<'a, S> {
fn from(guard: WaitGuard<'a, S>) -> Self {
CancelGuard(guard)
}
}
impl<'a, S: Scope<'a>> From<Request<'a, S>> for CancelGuard<'a, S> {
fn from(req: Request<'a, S>) -> Self {
CancelGuard(WaitGuard::from(req))
}
}
pub unsafe trait Scope<'a> {
fn register(&self);
unsafe fn unregister(&self);
}
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq, Hash)]
pub struct StaticScope;
unsafe impl Scope<'static> for StaticScope {
fn register(&self) {}
unsafe fn unregister(&self) {}
}
#[derive(Debug)]
pub struct LocalScope<'a> {
num_requests: Cell<usize>,
phantom: PhantomData<Cell<&'a ()>>, }
impl<'a> Drop for LocalScope<'a> {
fn drop(&mut self) {
if self.num_requests.get() != 0 {
panic!("at least one request was dropped without being completed");
}
}
}
unsafe impl<'a, 'b> Scope<'a> for &'b LocalScope<'a> {
fn register(&self) {
self.num_requests.set(self.num_requests.get() + 1)
}
unsafe fn unregister(&self) {
self.num_requests.set(self.num_requests.get().checked_sub(1)
.expect("unregister has been called more times than register"))
}
}
pub fn scope<'a, F, R>(f: F) -> R
where F: FnOnce(&LocalScope<'a>) -> R {
f(&LocalScope {
num_requests: Default::default(),
phantom: Default::default(),
})
}