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}