| 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); |
| } |
| } |