qubit_progress/lib.rs
1// =============================================================================
2// Copyright (c) 2025 - 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Immutable, lifecycle-safe progress reporting.
9// qubit-style: allow coverage-cfg
10//!
11//! A [`Progress`] operation owns its metric state, timing and reporter.
12//! Callers configure stable metadata with [`Metric`] and update dynamic counts
13//! through cloneable [`MetricHandle`] values. Every emitted [`Event`] is
14//! complete.
15//!
16//! # Benchmark interpretation
17//!
18//! Run `cargo bench --bench progress_bench -- --noplot` to compare complete
19//! event delivery, scheduling paths, and concurrent [`MetricHandle`] updates
20//! with a mutex-protected counter baseline. The contention benchmarks use
21//! Criterion's batched iteration so setup allocation is excluded from the
22//! measured update path; worker thread creation and joining remain part of the
23//! workload. Throughput is reported in elements per second for 2,048 updates
24//! per worker across 1, 2, 4, 8, 16, 32, and 64 workers.
25//!
26//! These measurements are workload- and hardware-dependent. The CAS-based
27//! metric path is not assumed to beat a mutex at every worker count; measure
28//! on target hardware before changing the synchronization strategy or adding
29//! backoff, yielding, or sharded counters.
30//!
31//! # Examples
32//!
33//! ```
34//! use qubit_progress::{Metric, Progress, TextReporter};
35//!
36//! let reporter = std::sync::Arc::new(TextReporter::new(Vec::new()));
37//! let progress = Progress::builder_arc(reporter)
38//! .metric(Metric::new("tasks", "Tasks").total(1))
39//! .start()?;
40//! let tasks = progress.metric("tasks").expect("configured metric must exist");
41//! tasks.start(1)?;
42//! tasks.succeed(1)?;
43//! progress.finish()?;
44//! # Ok::<(), Box<dyn std::error::Error>>(())
45//! ```
46
47#![deny(missing_docs)]
48#![deny(unsafe_op_in_unsafe_fn)]
49
50mod auto_reporter;
51mod error;
52mod event;
53mod internal;
54mod metric;
55mod operation_attributes;
56mod progress;
57pub mod reporter;
58mod stage;
59mod validation;
60
61pub use auto_reporter::{
62 AutoReporter,
63 AutoReporterStatus,
64 ProgressNotifier,
65};
66pub use error::{
67 AutoReporterError,
68 CompletionError,
69 ConfigurationError,
70 DeliveryError,
71 EmissionError,
72 FinishError,
73 MetricError,
74 RecoverableFinishError,
75 ReporterError,
76 StartError,
77 TerminalError,
78 WorkerPanic,
79};
80#[cfg(all(feature = "json-lines", coverage))]
81#[doc(hidden)]
82pub use event::__coverage_event_serde;
83pub use event::{
84 Event,
85 Phase,
86};
87#[cfg(coverage)]
88#[doc(hidden)]
89pub use internal::__coverage_internal;
90pub use internal::OperationLifecycle;
91pub use metric::{
92 Metric,
93 MetricDelta,
94 MetricHandle,
95 MetricSnapshot,
96};
97pub use operation_attributes::OperationAttributes;
98#[cfg(coverage)]
99#[doc(hidden)]
100pub use progress::__coverage_progress_edges;
101pub use progress::{
102 Progress,
103 ProgressBuilder,
104};
105#[cfg(feature = "json-lines")]
106pub use reporter::JsonLinesReporter;
107#[cfg(feature = "log")]
108pub use reporter::LogReporter;
109pub use reporter::{
110 NoopReporter,
111 Reporter,
112 TextReporter,
113};
114pub use stage::Stage;