Skip to main content

qubit_progress/model/
progress_event.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 *    SPDX-License-Identifier: Apache-2.0
6 *
7 *    Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10use std::time::Duration;
11
12use super::{
13    ProgressCounters,
14    ProgressEventBuilder,
15    ProgressPhase,
16    ProgressStage,
17};
18
19/// Immutable progress event delivered to reporters.
20///
21/// # Examples
22///
23/// ```
24/// use std::time::Duration;
25///
26/// use qubit_progress::{
27///     ProgressCounters,
28///     ProgressEvent,
29///     ProgressPhase,
30///     ProgressStage,
31/// };
32///
33/// let counters = ProgressCounters::new(Some(5)).with_completed_count(2);
34/// let event = ProgressEvent::from_phase(
35///     ProgressPhase::Running,
36///     counters,
37///     Duration::from_millis(500),
38/// )
39/// .with_stage(ProgressStage::new("load", "Load records"));
40///
41/// assert_eq!(event.phase(), ProgressPhase::Running);
42/// assert_eq!(event.counters().completed_count(), 2);
43/// assert_eq!(event.stage().map(|stage| stage.name()), Some("Load records"));
44/// ```
45#[derive(Debug, Clone, PartialEq)]
46pub struct ProgressEvent {
47    /// Lifecycle phase of the reported operation.
48    phase: ProgressPhase,
49    /// Optional current stage.
50    stage: Option<ProgressStage>,
51    /// Generic counters for the operation.
52    counters: ProgressCounters,
53    /// Monotonic elapsed duration.
54    elapsed: Duration,
55}
56
57impl ProgressEvent {
58    /// Creates a progress event builder.
59    ///
60    /// # Returns
61    ///
62    /// A builder initialized as running, unknown-total progress with zeroed
63    /// counters and zero elapsed time.
64    #[inline]
65    pub const fn builder() -> ProgressEventBuilder {
66        ProgressEventBuilder::new()
67    }
68
69    /// Creates a progress event.
70    ///
71    /// # Parameters
72    ///
73    /// * `builder` - Builder containing configured event fields.
74    ///
75    /// # Returns
76    ///
77    /// A progress event built from `builder`.
78    #[inline]
79    pub fn new(builder: ProgressEventBuilder) -> Self {
80        Self {
81            phase: builder.phase,
82            stage: builder.stage,
83            counters: builder.counters,
84            elapsed: builder.elapsed,
85        }
86    }
87
88    /// Creates a started progress event.
89    ///
90    /// # Parameters
91    ///
92    /// * `counters` - Initial progress counters.
93    /// * `elapsed` - Elapsed duration at start, usually zero.
94    ///
95    /// # Returns
96    ///
97    /// A progress event with [`ProgressPhase::Started`].
98    #[inline]
99    pub const fn started(counters: ProgressCounters, elapsed: Duration) -> Self {
100        Self {
101            phase: ProgressPhase::Started,
102            stage: None,
103            counters,
104            elapsed,
105        }
106    }
107
108    /// Creates a running progress event.
109    ///
110    /// # Parameters
111    ///
112    /// * `counters` - Current progress counters.
113    /// * `elapsed` - Elapsed duration since operation start.
114    ///
115    /// # Returns
116    ///
117    /// A progress event with [`ProgressPhase::Running`].
118    #[inline]
119    pub const fn running(counters: ProgressCounters, elapsed: Duration) -> Self {
120        Self {
121            phase: ProgressPhase::Running,
122            stage: None,
123            counters,
124            elapsed,
125        }
126    }
127
128    /// Creates a finished progress event.
129    ///
130    /// # Parameters
131    ///
132    /// * `counters` - Final progress counters.
133    /// * `elapsed` - Total elapsed duration.
134    ///
135    /// # Returns
136    ///
137    /// A progress event with [`ProgressPhase::Finished`].
138    #[inline]
139    pub const fn finished(counters: ProgressCounters, elapsed: Duration) -> Self {
140        Self {
141            phase: ProgressPhase::Finished,
142            stage: None,
143            counters,
144            elapsed,
145        }
146    }
147
148    /// Creates a failed progress event.
149    ///
150    /// # Parameters
151    ///
152    /// * `counters` - Final or current progress counters.
153    /// * `elapsed` - Elapsed duration at failure.
154    ///
155    /// # Returns
156    ///
157    /// A progress event with [`ProgressPhase::Failed`].
158    #[inline]
159    pub const fn failed(counters: ProgressCounters, elapsed: Duration) -> Self {
160        Self {
161            phase: ProgressPhase::Failed,
162            stage: None,
163            counters,
164            elapsed,
165        }
166    }
167
168    /// Creates a canceled progress event.
169    ///
170    /// # Parameters
171    ///
172    /// * `counters` - Final or current progress counters.
173    /// * `elapsed` - Elapsed duration at cancellation.
174    ///
175    /// # Returns
176    ///
177    /// A progress event with [`ProgressPhase::Canceled`].
178    #[inline]
179    pub const fn canceled(counters: ProgressCounters, elapsed: Duration) -> Self {
180        Self {
181            phase: ProgressPhase::Canceled,
182            stage: None,
183            counters,
184            elapsed,
185        }
186    }
187
188    /// Creates a progress event for the supplied lifecycle phase.
189    ///
190    /// # Parameters
191    ///
192    /// * `phase` - Lifecycle phase for the event.
193    /// * `counters` - Progress counters carried by the event.
194    /// * `elapsed` - Elapsed duration carried by the event.
195    ///
196    /// # Returns
197    ///
198    /// A progress event with `phase`, `counters`, and `elapsed`.
199    #[inline]
200    pub const fn from_phase(
201        phase: ProgressPhase,
202        counters: ProgressCounters,
203        elapsed: Duration,
204    ) -> Self {
205        match phase {
206            ProgressPhase::Started => Self::started(counters, elapsed),
207            ProgressPhase::Running => Self::running(counters, elapsed),
208            ProgressPhase::Finished => Self::finished(counters, elapsed),
209            ProgressPhase::Failed => Self::failed(counters, elapsed),
210            ProgressPhase::Canceled => Self::canceled(counters, elapsed),
211        }
212    }
213
214    /// Returns a copy configured with the current stage.
215    ///
216    /// # Parameters
217    ///
218    /// * `stage` - Current operation stage.
219    ///
220    /// # Returns
221    ///
222    /// This event with `stage` recorded.
223    #[inline]
224    pub fn with_stage(mut self, stage: ProgressStage) -> Self {
225        self.stage = Some(stage);
226        self
227    }
228
229    /// Returns the event phase.
230    ///
231    /// # Returns
232    ///
233    /// The lifecycle phase carried by this event.
234    #[inline]
235    pub const fn phase(&self) -> ProgressPhase {
236        self.phase
237    }
238
239    /// Returns the current stage when known.
240    ///
241    /// # Returns
242    ///
243    /// `Some(stage)` when this event carries stage information, otherwise
244    /// `None`.
245    #[inline]
246    pub const fn stage(&self) -> Option<&ProgressStage> {
247        self.stage.as_ref()
248    }
249
250    /// Returns the progress counters.
251    ///
252    /// # Returns
253    ///
254    /// The counters carried by this event.
255    #[inline]
256    pub const fn counters(&self) -> ProgressCounters {
257        self.counters
258    }
259
260    /// Returns the elapsed duration.
261    ///
262    /// # Returns
263    ///
264    /// The monotonic elapsed duration carried by this event.
265    #[inline]
266    pub const fn elapsed(&self) -> Duration {
267        self.elapsed
268    }
269}