blob: 40fba9d718e0935ebec36cd44a4745f6d0f114fe [file] [log] [blame]
use std::panic;
#[cfg(feature = "async")]
use futures::FutureExt;
use crate::file_lock::make_lock_for_name_and_path;
#[doc(hidden)]
pub fn fs_parallel_core(name: &str, path: Option<&str>, function: fn()) {
make_lock_for_name_and_path(name, path).start_parallel();
let res = panic::catch_unwind(|| {
function();
});
make_lock_for_name_and_path(name, path).end_parallel();
if let Err(err) = res {
panic::resume_unwind(err);
}
}
#[doc(hidden)]
pub fn fs_parallel_core_with_return<E>(
name: &str,
path: Option<&str>,
function: fn() -> Result<(), E>,
) -> Result<(), E> {
make_lock_for_name_and_path(name, path).start_parallel();
let res = panic::catch_unwind(function);
make_lock_for_name_and_path(name, path).end_parallel();
match res {
Ok(ret) => ret,
Err(err) => {
panic::resume_unwind(err);
}
}
}
#[doc(hidden)]
#[cfg(feature = "async")]
pub async fn fs_async_parallel_core_with_return<E>(
name: &str,
path: Option<&str>,
fut: impl std::future::Future<Output = Result<(), E>> + panic::UnwindSafe,
) -> Result<(), E> {
make_lock_for_name_and_path(name, path).start_parallel();
let res = fut.catch_unwind().await;
make_lock_for_name_and_path(name, path).end_parallel();
match res {
Ok(ret) => ret,
Err(err) => {
panic::resume_unwind(err);
}
}
}
#[doc(hidden)]
#[cfg(feature = "async")]
pub async fn fs_async_parallel_core(
name: &str,
path: Option<&str>,
fut: impl std::future::Future<Output = ()> + panic::UnwindSafe,
) {
make_lock_for_name_and_path(name, path).start_parallel();
let res = fut.catch_unwind().await;
make_lock_for_name_and_path(name, path).end_parallel();
if let Err(err) = res {
panic::resume_unwind(err);
}
}
#[cfg(test)]
mod tests {
#[cfg(feature = "async")]
use crate::{fs_async_parallel_core, fs_async_parallel_core_with_return};
use crate::{
file_lock::{path_for_name, Lock},
fs_parallel_core, fs_parallel_core_with_return,
};
use std::{io::Error, panic};
fn unlock_ok(lock_path: &str) {
let lock = Lock::new(lock_path);
assert_eq!(lock.parallel_count, 0);
}
#[test]
fn unlock_on_assert_sync_without_return() {
let lock_path = path_for_name("unlock_on_assert_sync_without_return");
let _ = panic::catch_unwind(|| {
fs_parallel_core(
"unlock_on_assert_sync_without_return",
Some(&lock_path),
|| {
assert!(false);
},
)
});
unlock_ok(&lock_path);
}
#[test]
fn unlock_on_assert_sync_with_return() {
let lock_path = path_for_name("unlock_on_assert_sync_with_return");
let _ = panic::catch_unwind(|| {
fs_parallel_core_with_return(
"unlock_on_assert_sync_with_return",
Some(&lock_path),
|| -> Result<(), Error> {
assert!(false);
Ok(())
},
)
});
unlock_ok(&lock_path);
}
#[tokio::test]
#[cfg(feature = "async")]
async fn unlock_on_assert_async_without_return() {
let lock_path = path_for_name("unlock_on_assert_async_without_return");
async fn demo_assert() {
assert!(false);
}
async fn call_serial_test_fn(lock_path: &str) {
fs_async_parallel_core(
"unlock_on_assert_async_without_return",
Some(&lock_path),
demo_assert(),
)
.await
}
// as per https://stackoverflow.com/a/66529014/320546
let _ = panic::catch_unwind(|| {
let handle = tokio::runtime::Handle::current();
let _enter_guard = handle.enter();
futures::executor::block_on(call_serial_test_fn(&lock_path));
});
unlock_ok(&lock_path);
}
#[tokio::test]
#[cfg(feature = "async")]
async fn unlock_on_assert_async_with_return() {
let lock_path = path_for_name("unlock_on_assert_async_with_return");
async fn demo_assert() -> Result<(), Error> {
assert!(false);
Ok(())
}
#[allow(unused_must_use)]
async fn call_serial_test_fn(lock_path: &str) {
fs_async_parallel_core_with_return(
"unlock_on_assert_async_with_return",
Some(&lock_path),
demo_assert(),
)
.await;
}
// as per https://stackoverflow.com/a/66529014/320546
let _ = panic::catch_unwind(|| {
let handle = tokio::runtime::Handle::current();
let _enter_guard = handle.enter();
futures::executor::block_on(call_serial_test_fn(&lock_path));
});
unlock_ok(&lock_path);
}
}