qubit_progress/model/progress_stage.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/// Describes the current stage of a multi-stage operation.
11///
12/// # Examples
13///
14/// ```
15/// use qubit_progress::ProgressStage;
16///
17/// let stage = ProgressStage::new("verify", "Verify files")
18/// .with_index(2)
19/// .with_total_stages(4)
20/// .with_weight(0.25);
21///
22/// assert_eq!(stage.id(), "verify");
23/// assert_eq!(stage.name(), "Verify files");
24/// assert_eq!(stage.index(), Some(2));
25/// ```
26#[derive(Debug, Clone, PartialEq)]
27pub struct ProgressStage {
28 /// Stable machine-readable stage identifier.
29 id: String,
30 /// Human-readable stage name.
31 name: String,
32 /// Zero-based stage index when known.
33 index: Option<usize>,
34 /// Total number of stages when known.
35 total_stages: Option<usize>,
36 /// Relative stage weight when the caller uses weighted progress.
37 weight: Option<f64>,
38}
39
40impl ProgressStage {
41 /// Creates a stage with a stable id and display name.
42 ///
43 /// # Parameters
44 ///
45 /// * `id` - Stable machine-readable identifier.
46 /// * `name` - Human-readable stage name.
47 ///
48 /// # Returns
49 ///
50 /// A stage with no index, total stage count, or weight.
51 #[inline]
52 pub fn new(id: &str, name: &str) -> Self {
53 Self {
54 id: id.to_owned(),
55 name: name.to_owned(),
56 index: None,
57 total_stages: None,
58 weight: None,
59 }
60 }
61
62 /// Returns a copy configured with a zero-based stage index.
63 ///
64 /// # Parameters
65 ///
66 /// * `index` - Zero-based stage index.
67 ///
68 /// # Returns
69 ///
70 /// This stage with `index` recorded.
71 #[inline]
72 pub const fn with_index(mut self, index: usize) -> Self {
73 self.index = Some(index);
74 self
75 }
76
77 /// Returns a copy configured with the total stage count.
78 ///
79 /// # Parameters
80 ///
81 /// * `total_stages` - Total number of stages in the operation.
82 ///
83 /// # Returns
84 ///
85 /// This stage with `total_stages` recorded.
86 #[inline]
87 pub const fn with_total_stages(mut self, total_stages: usize) -> Self {
88 self.total_stages = Some(total_stages);
89 self
90 }
91
92 /// Returns a copy configured with a relative stage weight.
93 ///
94 /// The weight is intended for caller-side weighted progress calculations.
95 /// Callers should supply finite, non-negative values. This method records
96 /// the supplied value as-is and does not validate `NaN`, infinity, or
97 /// negative input.
98 ///
99 /// # Parameters
100 ///
101 /// * `weight` - Finite, non-negative relative stage weight used by callers
102 /// that compute weighted total progress.
103 ///
104 /// # Returns
105 ///
106 /// This stage with `weight` recorded.
107 #[inline]
108 pub const fn with_weight(mut self, weight: f64) -> Self {
109 self.weight = Some(weight);
110 self
111 }
112
113 /// Returns the stable stage identifier.
114 ///
115 /// # Returns
116 ///
117 /// The machine-readable stage id.
118 #[inline]
119 pub fn id(&self) -> &str {
120 self.id.as_str()
121 }
122
123 /// Returns the human-readable stage name.
124 ///
125 /// # Returns
126 ///
127 /// The display name for this stage.
128 #[inline]
129 pub fn name(&self) -> &str {
130 self.name.as_str()
131 }
132
133 /// Returns the stage index when known.
134 ///
135 /// # Returns
136 ///
137 /// `Some(index)` when a zero-based stage index was supplied, otherwise
138 /// `None`.
139 #[inline]
140 pub const fn index(&self) -> Option<usize> {
141 self.index
142 }
143
144 /// Returns the total stage count when known.
145 ///
146 /// # Returns
147 ///
148 /// `Some(total)` when a total stage count was supplied, otherwise `None`.
149 #[inline]
150 pub const fn total_stages(&self) -> Option<usize> {
151 self.total_stages
152 }
153
154 /// Returns the relative stage weight when known.
155 ///
156 /// # Returns
157 ///
158 /// `Some(weight)` when a weight was supplied, otherwise `None`.
159 #[inline]
160 pub const fn weight(&self) -> Option<f64> {
161 self.weight
162 }
163}