//! Internal batch mode tracking using tokio task-local storage. //! //! This module provides a way to track whether we're in batch processing mode //! without exposing it in the public API. Extractors check this flag to decide //! whether to use `spawn_blocking` for CPU-intensive work. use std::cell::Cell; use tokio::task_local; task_local! { /// Task-local flag indicating batch processing mode. /// /// When true, extractors use `spawn_blocking` for CPU-intensive work to enable /// parallelism. When false (single-file mode), extractors run directly to avoid /// spawn overhead. static BATCH_MODE: Cell; } /// Check if we're currently in batch processing mode. /// /// Returns `false` if the task-local is not set (single-file mode). #[cfg(any( feature = "pdf", feature = "office", feature = "excel", feature = "excel-wasm", feature = "archives" ))] pub(crate) fn is_batch_mode() -> bool { BATCH_MODE.try_with(|cell| cell.get()).unwrap_or(false) } /// Run a future with batch mode enabled. /// /// This sets the task-local BATCH_MODE flag for the duration of the future. pub(crate) async fn with_batch_mode(future: F) -> T where F: std::future::Future, { BATCH_MODE.scope(Cell::new(true), future).await } #[cfg(all( test, any( feature = "pdf", feature = "office", feature = "excel", feature = "excel-wasm", feature = "archives" ) ))] mod tests { use super::*; #[tokio::test] async fn test_batch_mode_not_set_by_default() { let result = is_batch_mode(); assert!(!result, "batch mode should be false by default"); } #[tokio::test] async fn test_with_batch_mode_sets_flag() { let result = with_batch_mode(async { is_batch_mode() }).await; assert!(result, "batch mode should be true inside with_batch_mode"); } #[tokio::test] async fn test_batch_mode_scoped_to_future() { assert!(!is_batch_mode(), "batch mode should be false before"); with_batch_mode(async { assert!(is_batch_mode(), "batch mode should be true inside"); }) .await; assert!(!is_batch_mode(), "batch mode should be false after future completes"); } #[tokio::test] async fn test_nested_batch_mode_calls() { let result = with_batch_mode(async { let outer = is_batch_mode(); let inner = with_batch_mode(async { is_batch_mode() }).await; (outer, inner) }) .await; assert!(result.0, "outer batch mode should be true"); assert!(result.1, "inner batch mode should be true"); } #[tokio::test] async fn test_batch_mode_unaffected_after_with_batch_mode() { with_batch_mode(async { assert!(is_batch_mode(), "first call should set batch mode"); }) .await; assert!(!is_batch_mode(), "batch mode should be false between calls"); with_batch_mode(async { assert!(is_batch_mode(), "second call should set batch mode"); }) .await; assert!(!is_batch_mode(), "batch mode should be false after all calls"); } }