http_handle/
async_runtime.rs1use crate::error::ServerError;
7
8#[cfg(feature = "async")]
10#[cfg_attr(docsrs, doc(cfg(feature = "async")))]
11pub async fn run_blocking<F, T>(operation: F) -> Result<T, ServerError>
33where
34 F: FnOnce() -> Result<T, ServerError> + Send + 'static,
35 T: Send + 'static,
36{
37 match tokio::task::spawn_blocking(operation).await {
38 Ok(result) => result,
39 Err(err) => Err(ServerError::TaskFailed(format!(
40 "blocking task failed: {err}"
41 ))),
42 }
43}
44
45#[cfg(not(feature = "async"))]
47pub fn run_blocking<F, T>(operation: F) -> Result<T, ServerError>
65where
66 F: FnOnce() -> Result<T, ServerError>,
67{
68 operation()
69}
70
71#[cfg(all(test, feature = "async"))]
72mod tests {
73 use super::*;
74
75 #[tokio::test]
76 async fn run_blocking_maps_panic_to_task_failed() {
77 let result = run_blocking(|| -> Result<(), ServerError> {
78 panic!("boom")
79 })
80 .await;
81 let err =
82 result.expect_err("blocking panic must surface as Err");
83 let is_task_failed = matches!(err, ServerError::TaskFailed(_));
87 assert!(is_task_failed, "unexpected variant: {err:?}");
88 }
89
90 #[tokio::test]
91 async fn run_blocking_returns_inner_error() {
92 let result = run_blocking(|| -> Result<(), ServerError> {
93 Err(ServerError::Custom("inner".to_string()))
94 })
95 .await;
96 let err = result.expect_err("inner Err must propagate");
97 let is_custom = matches!(err, ServerError::Custom(_));
98 assert!(is_custom, "unexpected variant: {err:?}");
99 }
100
101 #[tokio::test]
102 async fn run_blocking_returns_success_value() {
103 let result =
104 run_blocking(|| -> Result<usize, ServerError> { Ok(7) })
105 .await
106 .expect("ok");
107 assert_eq!(result, 7);
108 }
109}