Skip to main content

qubit_progress/
stage.rs

1// =============================================================================
2//    Copyright (c) 2025 - 2026 Haixing Hu.
3//
4//    SPDX-License-Identifier: Apache-2.0
5//
6//    Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Optional operation stage metadata.
9
10use std::sync::Arc;
11
12#[cfg(feature = "serde")]
13use serde::{
14    Deserialize,
15    Deserializer,
16};
17
18#[cfg(feature = "serde")]
19use crate::validation::validate_stage;
20
21/// Human-readable sub-stage attached to subsequently emitted events.
22#[cfg_attr(feature = "serde", derive(serde::Serialize))]
23#[derive(Clone, Debug, Eq, PartialEq)]
24pub struct Stage {
25    /// Machine-readable stage identifier.
26    pub(crate) id: Arc<str>,
27    /// Human-readable stage name.
28    pub(crate) name: Arc<str>,
29    /// One-based stage position when present.
30    pub(crate) position: Option<u64>,
31    /// Number of stages when present.
32    pub(crate) total: Option<u64>,
33}
34
35/// Serializable wire representation used to validate standalone stages.
36#[cfg(feature = "serde")]
37#[derive(Deserialize)]
38struct StageWire {
39    /// Machine-readable stage identifier.
40    id: Arc<str>,
41    /// Human-readable stage name.
42    name: Arc<str>,
43    /// One-based stage position when present.
44    position: Option<u64>,
45    /// Number of stages when present.
46    total: Option<u64>,
47}
48
49#[cfg(feature = "serde")]
50impl<'de> Deserialize<'de> for Stage {
51    /// Deserializes and validates one standalone stage.
52    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
53    where
54        D: Deserializer<'de>,
55    {
56        let wire = StageWire::deserialize(deserializer)?;
57        let stage = Self {
58            id: wire.id,
59            name: wire.name,
60            position: wire.position,
61            total: wire.total,
62        };
63        validate_stage(&stage).map_err(serde::de::Error::custom)?;
64        Ok(stage)
65    }
66}
67
68impl Stage {
69    /// Creates stage metadata without sequence position information.
70    #[must_use]
71    pub fn new(id: &str, name: &str) -> Self {
72        Self {
73            id: Arc::from(id),
74            name: Arc::from(name),
75            position: None,
76            total: None,
77        }
78    }
79    /// Sets one-based stage position and total number of stages.
80    #[must_use]
81    pub const fn position(mut self, position: u64, total: u64) -> Self {
82        self.position = Some(position);
83        self.total = Some(total);
84        self
85    }
86    /// Returns the stage's stable ID.
87    #[must_use]
88    pub fn id(&self) -> &str {
89        &self.id
90    }
91    /// Returns the stage's display name.
92    #[must_use]
93    pub fn name(&self) -> &str {
94        &self.name
95    }
96    /// Returns the one-based position, if present.
97    #[must_use]
98    pub const fn position_value(&self) -> Option<u64> {
99        self.position
100    }
101    /// Returns the stage count, if present.
102    #[must_use]
103    pub const fn total(&self) -> Option<u64> {
104        self.total
105    }
106}