recoverable_spawn/thread/sync.rs
1use super::{r#trait::*, r#type::*};
2use std::thread::{JoinHandle, spawn};
3
4/// Executes a recoverable function within a panic-safe context.
5///
6/// - `func`: A function implementing the `RecoverableFunction` trait.
7/// - Returns: A `SpawnResult` indicating the success or failure of the function execution.
8pub fn run_function<F: RecoverableFunction>(func: F) -> SpawnResult {
9 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
10 func();
11 }))
12}
13
14/// Executes an error-handling function with a given error message within a panic-safe context.
15///
16/// - `func`: A function implementing the `ErrorHandlerFunction` trait.
17/// - `error`: A string slice representing the error message.
18/// - Returns: A `SpawnResult` indicating the success or failure of the error-handling function execution.
19pub fn run_error_handle_function<E: ErrorHandlerFunction>(func: E, error: &str) -> SpawnResult {
20 std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
21 func(error);
22 }))
23}
24
25/// Converts a panic-captured error value into a string.
26///
27/// - `err`: The captured error value, of type `BoxAnySend`.
28/// - Returns: A string representation of the error value.
29pub fn spawn_error_to_string(err: BoxAnySend) -> String {
30 match err.downcast_ref::<&str>() {
31 Some(str_slice) => str_slice.to_string(),
32 None => match err.downcast_ref::<String>() {
33 Some(string) => string.to_owned(),
34 None => format!("{:?}", err),
35 },
36 }
37}
38
39/// Spawns a new thread to run the provided function `function` in a recoverable manner.
40/// If the function `function` panics during execution, the panic will be caught, and the thread
41/// will terminate without crashing the entire program.
42///
43/// # Parameters
44/// - `function`: A function of type `function` to be executed in the spawned thread. It must implement `FnOnce()`, `Send`, `Sync`, and `'static` traits.
45/// - `FnOnce()`: The function is callable with no arguments and no return value.
46/// - `Send`: The function can be safely transferred across thread boundaries.
47/// - `Sync`: The function can be shared across threads safely.
48/// - `'static`: The function does not contain references to non-static data (i.e., data that lives beyond the function's scope).
49///
50/// # Returns
51/// - A `JoinHandle<()>` representing the spawned thread. The thread can be joined later to wait for its completion.
52///
53///
54/// # Panics
55/// - This function itself will not panic, but the function `function` could panic during execution.
56/// The panic will be caught, preventing the program from crashing.
57pub fn recoverable_spawn<F>(function: F) -> JoinHandle<()>
58where
59 F: RecoverableFunction,
60{
61 spawn(|| {
62 let _: SpawnResult = run_function(function);
63 })
64}
65
66/// Spawns a recoverable function with an error-handling function in a new thread.
67///
68/// - `function`: The primary function to execute, implementing the `RecoverableFunction` trait.
69/// - `error_handle_function`: A function to handle errors, implementing the `ErrorHandlerFunction` trait.
70/// - Returns: A `JoinHandle<()>` that can be used to manage the spawned thread.
71pub fn recoverable_spawn_catch<F, E>(function: F, error_handle_function: E) -> JoinHandle<()>
72where
73 F: RecoverableFunction,
74 E: ErrorHandlerFunction,
75{
76 spawn(|| {
77 let run_result: SpawnResult = run_function(function);
78 if let Err(err) = run_result {
79 let err_string: String = spawn_error_to_string(err);
80 let _: SpawnResult = run_error_handle_function(error_handle_function, &err_string);
81 }
82 })
83}
84
85pub fn recoverable_spawn_catch_finally<F, E, L>(
86 function: F,
87 error_handle_function: E,
88 finally: L,
89) -> JoinHandle<()>
90where
91 F: RecoverableFunction,
92 E: ErrorHandlerFunction,
93 L: RecoverableFunction,
94{
95 spawn(|| {
96 let run_result: SpawnResult = run_function(function);
97 if let Err(err) = run_result {
98 let err_string: String = spawn_error_to_string(err);
99 let _: SpawnResult = run_error_handle_function(error_handle_function, &err_string);
100 }
101 let _: SpawnResult = run_function(finally);
102 })
103}