Skip to main content

scientific_workflow/
reporting.rs

1//! Centralized, parallel-safe progress and terminal reporting.
2//!
3//! [`ProgressReporter`] registers every project task under an exact
4//! parameter-derived [`TaskIdentity`], assigns ordering from configuration, and
5//! becomes the sole human-facing terminal writer for its lifetime. Worker
6//! threads receive non-clone [`TaskProgress`] handles and synchronize absolute
7//! iteration from their authoritative scientific state.
8//!
9//! Iteration updates use per-task atomics. One renderer thread polls them at a
10//! bounded frequency, so numerical workers never draw progress bars or contend
11//! on terminal locks. Interactive stderr receives a multi-progress display;
12//! redirected stderr receives stable lifecycle lines. Tests and embedding
13//! applications may retain tracking while selecting hidden output.
14//!
15//! # Minimal parallel use
16//!
17//! ```no_run
18//! use scientific_workflow::prelude::*;
19//!
20//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
21//! let project = ScientificProject::load("project-root")?;
22//! let reporter = ProgressReporter::for_project(&project)
23//!     .identify_tasks_by(["temperature", "seed"])
24//!     .start()?;
25//! # let task = project.task_config(0)?;
26//! let progress = reporter.start_task(&task, 0, Some(1_000))?;
27//! progress.set_iteration(1_000)?;
28//! progress.complete()?;
29//! # for task in project.task_configs().skip(1) {
30//! #     reporter.start_task(&task, 0, Some(0))?.complete()?;
31//! # }
32//! let summary = reporter.complete("scientific work completed")?;
33//! assert!(summary.is_success());
34//! # Ok(())
35//! # }
36//! ```
37
38mod error;
39mod progress;
40
41pub use error::ReportingError;
42pub use progress::{
43    ProgressReporter, ProgressReporterBuilder, ProgressSummary, TaskIdentity, TaskProgress,
44    TaskStatus,
45};