use crate::error::{Error, Result};
use crate::ffi;
pub struct Request {
handle: i64,
completed: bool,
}
impl Request {
pub(crate) fn new(handle: i64) -> Self {
Request {
handle,
completed: false,
}
}
pub fn raw_handle(&self) -> i64 {
self.handle
}
pub fn is_completed(&self) -> bool {
self.completed
}
pub fn wait(mut self) -> Result<()> {
if self.completed {
return Ok(());
}
let ret = unsafe { ffi::ferrompi_wait(self.handle) };
Error::check(ret)?;
self.completed = true;
Ok(())
}
pub fn test(&mut self) -> Result<bool> {
if self.completed {
return Ok(true);
}
let mut flag: i32 = 0;
let ret = unsafe { ffi::ferrompi_test(self.handle, &mut flag) };
Error::check(ret)?;
if flag != 0 {
self.completed = true;
}
Ok(flag != 0)
}
pub fn wait_all(requests: Vec<Request>) -> Result<()> {
if requests.is_empty() {
return Ok(());
}
let mut handles: Vec<i64> = requests.iter().map(|r| r.handle).collect();
let ret = unsafe { ffi::ferrompi_waitall(handles.len() as i64, handles.as_mut_ptr()) };
if ret == 0 {
for mut req in requests {
req.completed = true;
std::mem::forget(req);
}
Ok(())
} else {
Err(Error::from_code(ret))
}
}
}
impl Drop for Request {
fn drop(&mut self) {
if !self.completed {
unsafe { ffi::ferrompi_wait(self.handle) };
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use std::mem::forget;
#[test]
fn new_request_is_not_completed() {
let req = Request::new(0);
assert!(!req.is_completed());
assert_eq!(req.raw_handle(), 0);
forget(req);
}
#[test]
fn raw_handle_returns_constructor_value() {
let req = Request::new(99);
assert_eq!(req.raw_handle(), 99);
forget(req);
}
#[test]
fn test_when_already_completed_returns_true() {
let mut req = Request {
handle: 0,
completed: true,
};
let result = req.test();
assert!(matches!(result, Ok(true)));
forget(req);
}
#[test]
fn wait_when_already_completed_returns_ok() {
let req = Request {
handle: 0,
completed: true,
};
let result = req.wait();
assert!(result.is_ok());
}
#[test]
fn wait_all_empty_vec_returns_ok() {
let result = Request::wait_all(vec![]);
assert!(result.is_ok());
}
}