use tokio::runtime::Runtime;
pub fn create_runtime() -> Result<Runtime, String> {
if tokio::runtime::Handle::try_current().is_ok() {
return Err(
"Cannot create runtime from within a runtime. Use Handle::current() instead."
.to_string(),
);
}
Runtime::new().map_err(|e| format!("Failed to create async runtime: {}", e))
}
pub fn execute_async<F, T>(future: F) -> Result<T, String>
where
F: std::future::Future<Output = Result<T, String>> + Send + 'static,
T: Send + 'static,
{
match tokio::runtime::Handle::try_current() {
Ok(_handle) => {
std::thread::scope(|s| {
s.spawn(|| {
let rt = Runtime::new()
.map_err(|e| format!("Failed to create async runtime: {}", e))?;
rt.block_on(future)
})
.join()
.unwrap_or_else(|e| Err(format!("Thread panicked: {:?}", e)))
})
}
Err(_) => {
let rt =
Runtime::new().map_err(|e| format!("Failed to create async runtime: {}", e))?;
rt.block_on(future)
}
}
}
pub fn execute_async_verb<F, T>(future: F) -> clap_noun_verb::Result<T>
where
F: std::future::Future<Output = anyhow::Result<T>> + Send + 'static,
T: Send + 'static,
{
match tokio::runtime::Handle::try_current() {
Ok(_handle) => {
std::thread::scope(|s| {
s.spawn(|| {
let rt = Runtime::new().map_err(|e| {
clap_noun_verb::NounVerbError::execution_error(format!(
"Failed to create async runtime: {}",
e
))
})?;
rt.block_on(future)
.map_err(|e| clap_noun_verb::NounVerbError::execution_error(e.to_string()))
})
.join()
.unwrap_or_else(|e| {
Err(clap_noun_verb::NounVerbError::execution_error(format!(
"Thread panicked: {:?}",
e
)))
})
})
}
Err(_) => {
let rt = Runtime::new().map_err(|e| {
clap_noun_verb::NounVerbError::execution_error(format!(
"Failed to create async runtime: {}",
e
))
})?;
rt.block_on(future)
.map_err(|e| clap_noun_verb::NounVerbError::execution_error(e.to_string()))
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_create_runtime() {
let result = create_runtime();
assert!(result.is_ok(), "Runtime creation should succeed");
}
#[test]
fn test_execute_async_success() {
let result = execute_async(async { Ok::<i32, String>(42) });
assert_eq!(result, Ok(42));
}
#[test]
fn test_execute_async_error() {
let result = execute_async(async { Err::<i32, String>("test error".to_string()) });
assert!(result.is_err());
assert_eq!(result.unwrap_err(), "test error");
}
#[test]
fn test_execute_async_verb_success() {
let result = execute_async_verb(async { Ok::<i32, anyhow::Error>(42) });
assert!(result.is_ok());
}
#[test]
fn test_execute_async_verb_error() {
let result =
execute_async_verb(async { Err::<i32, anyhow::Error>(anyhow::anyhow!("test error")) });
assert!(result.is_err());
}
}