ggen_cli_lib/runtime.rs
1//! Runtime utilities for bridging async/sync boundaries
2//!
3//! This module provides utilities for executing async code in sync contexts,
4//! particularly for CLI commands that need to call async domain functions.
5
6use ggen_utils::error::Result;
7use std::future::Future;
8
9/// Execute an async function in a sync context
10///
11/// This creates a new Tokio runtime and blocks on the provided future.
12/// Used by CLI commands to bridge to async domain functions.
13///
14/// # Examples
15///
16/// ```no_run
17/// use ggen_utils::error::Result;
18///
19/// fn sync_command() -> Result<()> {
20/// crate::runtime::execute(async {
21/// // Async domain logic here
22/// Ok(())
23/// })
24/// }
25/// ```
26pub fn execute<F>(future: F) -> Result<()>
27where
28 F: Future<Output = Result<()>>,
29{
30 let runtime = tokio::runtime::Runtime::new().map_err(|e| {
31 ggen_utils::error::Error::new_fmt(format_args!("Failed to create Tokio runtime: {}", e))
32 })?;
33
34 runtime.block_on(future)
35}
36
37/// Block on an async function with a generic return type
38///
39/// Similar to `execute` but supports any return type, not just Result<()>.
40/// Used for domain functions that return values.
41///
42/// # Examples
43///
44/// ```no_run
45/// use ggen_utils::error::Result;
46///
47/// fn get_data() -> Result<String> {
48/// crate::runtime::block_on(async {
49/// Ok("data".to_string())
50/// })
51/// }
52/// ```
53pub fn block_on<F, T>(future: F) -> T
54where
55 F: Future<Output = T> + Send,
56 T: Send,
57{
58 // Check if we're already in a runtime
59 match tokio::runtime::Handle::try_current() {
60 Ok(_) => {
61 // Already in runtime - spawn new thread with new runtime to avoid nesting
62 std::thread::scope(|s| {
63 s.spawn(move || {
64 let rt =
65 tokio::runtime::Runtime::new().expect("Failed to create Tokio runtime");
66 rt.block_on(future)
67 })
68 .join()
69 .expect("Runtime thread panicked")
70 })
71 }
72 Err(_) => {
73 // Not in runtime - create one on current thread
74 let runtime = tokio::runtime::Runtime::new().expect("Failed to create Tokio runtime");
75 runtime.block_on(future)
76 }
77 }
78}