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()
31        .map_err(|e| ggen_utils::error::Error::new_fmt(format_args!(
32            "Failed to create Tokio runtime: {}",
33            e
34        )))?;
35
36    runtime.block_on(future)
37}
38
39/// Block on an async function with a generic return type
40///
41/// Similar to `execute` but supports any return type, not just Result<()>.
42/// Used for domain functions that return values.
43///
44/// # Examples
45///
46/// ```no_run
47/// use ggen_utils::error::Result;
48///
49/// fn get_data() -> Result<String> {
50///     crate::runtime::block_on(async {
51///         Ok("data".to_string())
52///     })
53/// }
54/// ```
55pub fn block_on<F, T>(future: F) -> T
56where
57    F: Future<Output = T> + Send,
58    T: Send,
59{
60    // Check if we're already in a runtime
61    match tokio::runtime::Handle::try_current() {
62        Ok(_) => {
63            // Already in runtime - spawn new thread with new runtime to avoid nesting
64            std::thread::scope(|s| {
65                s.spawn(move || {
66                    let rt = tokio::runtime::Runtime::new()
67                        .expect("Failed to create Tokio runtime");
68                    rt.block_on(future)
69                }).join().expect("Runtime thread panicked")
70            })
71        }
72        Err(_) => {
73            // Not in runtime - create one on current thread
74            let runtime = tokio::runtime::Runtime::new()
75                .expect("Failed to create Tokio runtime");
76            runtime.block_on(future)
77        }
78    }
79}