Skip to main content

qubit_progress/model/
progress_counters.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 ******************************************************************************/
10/// Generic progress counters for a running operation.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12pub struct ProgressCounters {
13    /// Total work-unit count when known.
14    total_count: Option<usize>,
15    /// Completed work-unit count.
16    completed_count: usize,
17    /// Active work-unit count.
18    active_count: usize,
19    /// Successful work-unit count.
20    succeeded_count: usize,
21    /// Failed work-unit count.
22    failed_count: usize,
23}
24
25impl ProgressCounters {
26    /// Creates counters with a known or unknown total count.
27    ///
28    /// # Parameters
29    ///
30    /// * `total_count` - Total work-unit count, or `None` when unknown.
31    ///
32    /// # Returns
33    ///
34    /// Zeroed counters with the supplied total count.
35    #[inline]
36    pub const fn new(total_count: Option<usize>) -> Self {
37        Self {
38            total_count,
39            completed_count: 0,
40            active_count: 0,
41            succeeded_count: 0,
42            failed_count: 0,
43        }
44    }
45
46    /// Returns a copy configured with the known or unknown total count.
47    ///
48    /// # Parameters
49    ///
50    /// * `total_count` - Total work-unit count, or `None` when unknown.
51    ///
52    /// # Returns
53    ///
54    /// This counter set with `total_count` recorded.
55    #[inline]
56    pub const fn with_total_count(mut self, total_count: Option<usize>) -> Self {
57        self.total_count = total_count;
58        self
59    }
60
61    /// Returns a copy configured with the completed count.
62    ///
63    /// # Parameters
64    ///
65    /// * `completed_count` - Number of completed work units.
66    ///
67    /// # Returns
68    ///
69    /// This counter set with `completed_count` recorded.
70    #[inline]
71    pub const fn with_completed_count(mut self, completed_count: usize) -> Self {
72        self.completed_count = completed_count;
73        self
74    }
75
76    /// Returns a copy configured with the active count.
77    ///
78    /// # Parameters
79    ///
80    /// * `active_count` - Number of currently active work units.
81    ///
82    /// # Returns
83    ///
84    /// This counter set with `active_count` recorded.
85    #[inline]
86    pub const fn with_active_count(mut self, active_count: usize) -> Self {
87        self.active_count = active_count;
88        self
89    }
90
91    /// Returns a copy configured with the succeeded count.
92    ///
93    /// # Parameters
94    ///
95    /// * `succeeded_count` - Number of successful work units.
96    ///
97    /// # Returns
98    ///
99    /// This counter set with `succeeded_count` recorded.
100    #[inline]
101    pub const fn with_succeeded_count(mut self, succeeded_count: usize) -> Self {
102        self.succeeded_count = succeeded_count;
103        self
104    }
105
106    /// Returns a copy configured with the failed count.
107    ///
108    /// # Parameters
109    ///
110    /// * `failed_count` - Number of failed work units.
111    ///
112    /// # Returns
113    ///
114    /// This counter set with `failed_count` recorded.
115    #[inline]
116    pub const fn with_failed_count(mut self, failed_count: usize) -> Self {
117        self.failed_count = failed_count;
118        self
119    }
120
121    /// Returns the total work-unit count when known.
122    ///
123    /// # Returns
124    ///
125    /// `Some(total)` for known-total progress, or `None` for open-ended
126    /// progress.
127    #[inline]
128    pub const fn total_count(&self) -> Option<usize> {
129        self.total_count
130    }
131
132    /// Returns the completed work-unit count.
133    ///
134    /// # Returns
135    ///
136    /// The number of completed work units.
137    #[inline]
138    pub const fn completed_count(&self) -> usize {
139        self.completed_count
140    }
141
142    /// Returns the active work-unit count.
143    ///
144    /// # Returns
145    ///
146    /// The number of currently active work units.
147    #[inline]
148    pub const fn active_count(&self) -> usize {
149        self.active_count
150    }
151
152    /// Returns the successful work-unit count.
153    ///
154    /// # Returns
155    ///
156    /// The number of successful work units.
157    #[inline]
158    pub const fn succeeded_count(&self) -> usize {
159        self.succeeded_count
160    }
161
162    /// Returns the failed work-unit count.
163    ///
164    /// # Returns
165    ///
166    /// The number of failed work units.
167    #[inline]
168    pub const fn failed_count(&self) -> usize {
169        self.failed_count
170    }
171
172    /// Returns the remaining work-unit count when the total is known.
173    ///
174    /// # Returns
175    ///
176    /// `Some(total - completed - active)` using saturating arithmetic for
177    /// known-total progress, or `None` when the total is unknown.
178    #[inline]
179    pub const fn remaining_count(&self) -> Option<usize> {
180        match self.total_count {
181            Some(total_count) => {
182                Some(total_count.saturating_sub(self.completed_count + self.active_count))
183            }
184            None => None,
185        }
186    }
187
188    /// Returns completed progress as a fraction in `0.0..=1.0`.
189    ///
190    /// # Returns
191    ///
192    /// `Some(fraction)` for known-total progress, `Some(1.0)` when the known
193    /// total is zero, or `None` when the total is unknown.
194    #[inline]
195    pub fn progress_fraction(&self) -> Option<f64> {
196        self.total_count.map(|total_count| {
197            if total_count == 0 {
198                1.0
199            } else {
200                (self.completed_count as f64 / total_count as f64).clamp(0.0, 1.0)
201            }
202        })
203    }
204
205    /// Returns completed progress as a percentage in `0.0..=100.0`.
206    ///
207    /// # Returns
208    ///
209    /// `Some(percent)` for known-total progress, or `None` when the total is
210    /// unknown.
211    #[inline]
212    pub fn progress_percent(&self) -> Option<f64> {
213        self.progress_fraction().map(|fraction| fraction * 100.0)
214    }
215}