qubit_progress/error/configuration_error.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//! Errors found while validating fixed progress configuration.
9// qubit-style: allow source-test-pair
10
11use std::{
12 error::Error,
13 fmt,
14};
15
16/// Invalid fixed metadata supplied to a progress operation.
17#[derive(Clone, Debug, Eq, PartialEq)]
18#[non_exhaustive]
19pub enum ConfigurationError {
20 /// An operation was started without metrics.
21 NoMetrics,
22 /// A metric ID is empty or whitespace only.
23 EmptyMetricId {
24 /// Zero-based metric position in the builder.
25 index: usize,
26 },
27 /// A metric name is empty or whitespace only.
28 EmptyMetricName {
29 /// ID of the malformed metric.
30 metric_id: String,
31 },
32 /// Two configured metrics have the same ID.
33 DuplicateMetricId {
34 /// Duplicated stable metric ID.
35 metric_id: String,
36 },
37 /// An operation attribute key is empty or whitespace only.
38 EmptyAttributeKey {
39 /// Malformed attribute key.
40 key: String,
41 },
42 /// A stage ID is empty or whitespace only.
43 EmptyStageId,
44 /// A stage name is empty or whitespace only.
45 EmptyStageName,
46 /// Stage position and total were not supplied together.
47 IncompleteStagePosition,
48 /// Stage position is outside its one-based total range.
49 InvalidStagePosition {
50 /// Invalid one-based position.
51 position: u64,
52 /// Declared number of stages.
53 total: u64,
54 },
55}
56
57impl fmt::Display for ConfigurationError {
58 /// Formats a concise configuration explanation.
59 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
60 match self {
61 Self::NoMetrics => formatter
62 .write_str("a progress operation requires at least one metric"),
63 Self::EmptyMetricId { index } => {
64 write!(formatter, "metric at index {index} has an empty ID")
65 }
66 Self::EmptyMetricName { metric_id } => {
67 write!(formatter, "metric {metric_id:?} has an empty name")
68 }
69 Self::DuplicateMetricId { metric_id } => {
70 write!(formatter, "metric ID {metric_id:?} is duplicated")
71 }
72 Self::EmptyAttributeKey { key } => {
73 write!(formatter, "operation attribute key {key:?} is empty")
74 }
75 Self::EmptyStageId => formatter.write_str("stage ID is empty"),
76 Self::EmptyStageName => formatter.write_str("stage name is empty"),
77 Self::IncompleteStagePosition => formatter.write_str(
78 "stage position and total must be supplied together",
79 ),
80 Self::InvalidStagePosition { position, total } => write!(
81 formatter,
82 "stage position {position} is outside 1..={total}"
83 ),
84 }
85 }
86}
87
88impl Error for ConfigurationError {}