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::AutoReporter;
62pub use auto_reporter::AutoReporterStatus;
63pub use auto_reporter::ProgressNotifier;
64pub use error::AutoReporterError;
65pub use error::CompletionError;
66pub use error::ConfigurationError;
67pub use error::DeliveryError;
68pub use error::EmissionError;
69pub use error::FinishError;
70pub use error::MetricError;
71pub use error::RecoverableFinishError;
72pub use error::ReporterError;
73pub use error::StartError;
74pub use error::TerminalError;
75pub use error::WorkerPanic;
76#[cfg(all(feature = "json-lines", coverage))]
77#[doc(hidden)]
78pub use event::__coverage_event_serde;
79pub use event::Event;
80pub use event::Phase;
81#[cfg(coverage)]
82#[doc(hidden)]
83pub use internal::__coverage_internal;
84pub use internal::OperationLifecycle;
85pub use metric::Metric;
86pub use metric::MetricDelta;
87pub use metric::MetricHandle;
88pub use metric::MetricSnapshot;
89pub use operation_attributes::OperationAttributes;
90#[cfg(coverage)]
91#[doc(hidden)]
92pub use progress::__coverage_progress_edges;
93pub use progress::Progress;
94pub use progress::ProgressBuilder;
95#[cfg(feature = "json-lines")]
96pub use reporter::JsonLinesReporter;
97#[cfg(feature = "log")]
98pub use reporter::LogReporter;
99pub use reporter::NoopReporter;
100pub use reporter::Reporter;
101pub use reporter::TextReporter;
102pub use stage::Stage;