hojicha-runtime 0.2.2

Event handling and async runtime for Hojicha TUI framework
Documentation
//! Shared Tokio runtime for the entire application
//!
//! This module provides a single shared runtime instance to avoid
//! the anti-pattern of creating multiple runtimes.

use std::sync::{Arc, OnceLock};
use tokio::runtime::{Builder, Runtime};

static SHARED_RUNTIME: OnceLock<Arc<Runtime>> = OnceLock::new();

/// Get or create the shared runtime instance
pub fn shared_runtime() -> Arc<Runtime> {
    SHARED_RUNTIME
        .get_or_init(|| {
            Arc::new(
                Builder::new_multi_thread()
                    .worker_threads(get_cpu_count())
                    .thread_name("hojicha-async")
                    .enable_all()
                    .build()
                    .expect("Failed to create Tokio runtime"),
            )
        })
        .clone()
}

/// Configuration for the shared runtime
#[derive(Debug, Clone)]
pub struct RuntimeConfig {
    /// Number of worker threads (default: number of CPU cores)
    pub worker_threads: Option<usize>,
    /// Thread name prefix (default: "hojicha-async")
    pub thread_name_prefix: String,
    /// Enable I/O driver (default: true)
    pub enable_io: bool,
    /// Enable time driver (default: true)
    pub enable_time: bool,
}

impl Default for RuntimeConfig {
    fn default() -> Self {
        Self {
            worker_threads: None,
            thread_name_prefix: "hojicha-async".to_string(),
            enable_io: true,
            enable_time: true,
        }
    }
}

/// Initialize the shared runtime with custom configuration
pub fn initialize_runtime(config: RuntimeConfig) -> Result<(), std::io::Error> {
    if SHARED_RUNTIME.get().is_some() {
        return Ok(()); // Already initialized
    }

    let mut builder = Builder::new_multi_thread();

    if let Some(threads) = config.worker_threads {
        builder.worker_threads(threads);
    } else {
        builder.worker_threads(get_cpu_count());
    }

    builder.thread_name(&config.thread_name_prefix);

    if config.enable_io && config.enable_time {
        builder.enable_all();
    } else {
        if config.enable_io {
            builder.enable_io();
        }
        if config.enable_time {
            builder.enable_time();
        }
    }

    let runtime = Arc::new(builder.build()?);
    let _ = SHARED_RUNTIME.set(runtime);
    Ok(())
}

/// Get the number of available CPU cores
fn get_cpu_count() -> usize {
    std::thread::available_parallelism()
        .map(|n| n.get())
        .unwrap_or(4)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_shared_runtime_singleton() {
        let rt1 = shared_runtime();
        let rt2 = shared_runtime();
        assert!(Arc::ptr_eq(&rt1, &rt2));
    }
}