Skip to main content

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}