• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

qubit-ltd / rust-config / ce24969b-a8af-4e5b-a6ab-4137af9b3eca

10 Apr 2026 05:28PM UTC coverage: 96.018%. Remained the same
ce24969b-a8af-4e5b-a6ab-4137af9b3eca

push

circleci

Haixing-Hu
chore(release): bump crate and dependencies

- bump qubit-config crate version to 0.8.1
- refresh the lockfile to pull cc 1.2.60, js-sys 0.3.95, qubit-common 0.5.1, and the wasm-bindgen 0.2.118 family

1302 of 1356 relevant lines covered (96.02%)

42.62 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

96.67
/src/error.rs
1
/*******************************************************************************
2
 *
3
 *    Copyright (c) 2025 - 2026.
4
 *    Haixing Hu, Qubit Co. Ltd.
5
 *
6
 *    All rights reserved.
7
 *
8
 ******************************************************************************/
9
//! # Configuration Error Types
10
//!
11
//! Defines all possible error types in the configuration system.
12
//!
13
//! # Author
14
//!
15
//! Haixing Hu
16

17
use thiserror::Error;
18

19
use qubit_common::DataType;
20
use qubit_value::ValueError;
21

22
/// Configuration error type
23
///
24
/// Defines all possible error scenarios in the configuration system.
25
///
26
/// # Examples
27
///
28
/// ```rust,ignore
29
/// use qubit_config::{Config, ConfigError, ConfigResult};
30
/// fn get_port(config: &Config) -> ConfigResult<i32> { unimplemented!() }
31
/// ```
32
///
33
/// # Author
34
///
35
/// Haixing Hu
36
///
37
#[derive(Debug, Error)]
38
pub enum ConfigError {
39
    /// Property not found
40
    #[error("Property not found: {0}")]
41
    PropertyNotFound(String),
42

43
    /// Property has no value
44
    #[error("Property '{0}' has no value")]
45
    PropertyHasNoValue(String),
46

47
    /// Type mismatch at a specific key/path
48
    #[error("Type mismatch at '{key}': expected {expected}, actual {actual}")]
49
    TypeMismatch {
50
        /// The configuration key/path where the mismatch occurred
51
        key: String,
52
        /// Expected type
53
        expected: DataType,
54
        /// Actual type
55
        actual: DataType,
56
    },
57

58
    /// Type conversion failed at a specific key/path
59
    #[error("Type conversion failed at '{key}': {message}")]
60
    ConversionError {
61
        /// The configuration key/path where the conversion failed
62
        key: String,
63
        /// Error message
64
        message: String,
65
    },
66

67
    /// Index out of bounds
68
    #[error("Index out of bounds: index {index}, length {len}")]
69
    IndexOutOfBounds {
70
        /// Index being accessed
71
        index: usize,
72
        /// Actual length
73
        len: usize,
74
    },
75

76
    /// Variable substitution failed
77
    #[error("Variable substitution failed: {0}")]
78
    SubstitutionError(String),
79

80
    /// Variable substitution depth exceeded
81
    #[error("Variable substitution depth exceeded maximum limit: {0}")]
82
    SubstitutionDepthExceeded(usize),
83

84
    /// Configuration merge failed
85
    #[error("Configuration merge failed: {0}")]
86
    MergeError(String),
87

88
    /// Property is final and cannot be overridden
89
    #[error("Property '{0}' is final and cannot be overridden")]
90
    PropertyIsFinal(String),
91

92
    /// IO error
93
    #[error("IO error: {0}")]
94
    IoError(#[from] std::io::Error),
95

96
    /// Parse error
97
    #[error("Parse error: {0}")]
98
    ParseError(String),
99

100
    /// Deserialization error for structured config mapping
101
    #[error("Deserialization error at '{path}': {message}")]
102
    DeserializeError {
103
        /// The config prefix/path being deserialized
104
        path: String,
105
        /// Error message
106
        message: String,
107
    },
108

109
    /// Other error
110
    #[error("Configuration error: {0}")]
111
    Other(String),
112
}
113

114
/// Result type for configuration operations
115
///
116
/// Used for all operations in the configuration system that may return errors.
117
pub type ConfigResult<T> = Result<T, ConfigError>;
118

119
impl ConfigError {
120
    /// Creates a `TypeMismatch` error with an empty key (for backward
121
    /// compatibility with `ValueError` conversions that lack key context).
122
    ///
123
    /// # Parameters
124
    ///
125
    /// * `expected` - Expected [`DataType`].
126
    /// * `actual` - Actual [`DataType`].
127
    ///
128
    /// # Returns
129
    ///
130
    /// A [`ConfigError::TypeMismatch`] with an empty `key`.
131
    #[inline]
132
    pub(crate) fn type_mismatch_no_key(expected: DataType, actual: DataType) -> Self {
3✔
133
        ConfigError::TypeMismatch {
3✔
134
            key: String::new(),
3✔
135
            expected,
3✔
136
            actual,
3✔
137
        }
3✔
138
    }
3✔
139

140
    /// Creates a `TypeMismatch` error with a specific key.
141
    ///
142
    /// # Parameters
143
    ///
144
    /// * `key` - Configuration key or path.
145
    /// * `expected` - Expected [`DataType`].
146
    /// * `actual` - Actual [`DataType`].
147
    ///
148
    /// # Returns
149
    ///
150
    /// A [`ConfigError::TypeMismatch`].
151
    #[inline]
152
    pub(crate) fn type_mismatch_at(key: &str, expected: DataType, actual: DataType) -> Self {
20✔
153
        ConfigError::TypeMismatch {
20✔
154
            key: key.to_string(),
20✔
155
            expected,
20✔
156
            actual,
20✔
157
        }
20✔
158
    }
20✔
159

160
    /// Creates a `ConversionError` with an empty key.
161
    ///
162
    /// # Parameters
163
    ///
164
    /// * `message` - Human-readable conversion error message.
165
    ///
166
    /// # Returns
167
    ///
168
    /// A [`ConfigError::ConversionError`] with an empty `key`.
169
    #[inline]
170
    pub(crate) fn conversion_error_no_key(message: impl Into<String>) -> Self {
6✔
171
        ConfigError::ConversionError {
6✔
172
            key: String::new(),
6✔
173
            message: message.into(),
6✔
174
        }
6✔
175
    }
6✔
176

177
    /// Creates a `ConversionError` with a specific key.
178
    ///
179
    /// # Parameters
180
    ///
181
    /// * `key` - Configuration key or path.
182
    /// * `message` - Human-readable conversion error message.
183
    ///
184
    /// # Returns
185
    ///
186
    /// A [`ConfigError::ConversionError`].
187
    #[inline]
188
    pub(crate) fn conversion_error_at(key: &str, message: impl Into<String>) -> Self {
1✔
189
        ConfigError::ConversionError {
1✔
190
            key: key.to_string(),
1✔
191
            message: message.into(),
1✔
192
        }
1✔
193
    }
1✔
194
}
195

196
impl From<ValueError> for ConfigError {
197
    fn from(err: ValueError) -> Self {
11✔
198
        match err {
11✔
199
            ValueError::NoValue => ConfigError::PropertyHasNoValue(String::new()),
1✔
200
            ValueError::TypeMismatch { expected, actual } => {
3✔
201
                ConfigError::type_mismatch_no_key(expected, actual)
3✔
202
            }
203
            ValueError::ConversionFailed { from, to } => {
2✔
204
                ConfigError::conversion_error_no_key(format!("From {from} to {to}"))
2✔
205
            }
206
            ValueError::ConversionError(msg) => ConfigError::conversion_error_no_key(msg),
2✔
207
            ValueError::IndexOutOfBounds { index, len } => {
1✔
208
                ConfigError::IndexOutOfBounds { index, len }
1✔
209
            }
210
            ValueError::JsonSerializationError(msg) => {
1✔
211
                ConfigError::conversion_error_no_key(format!("JSON serialization error: {msg}"))
1✔
212
            }
213
            ValueError::JsonDeserializationError(msg) => {
1✔
214
                ConfigError::conversion_error_no_key(format!("JSON deserialization error: {msg}"))
1✔
215
            }
216
        }
217
    }
11✔
218
}
219

220
#[cfg(test)]
221
mod tests {
222
    use super::*;
223

224
    #[test]
225
    fn test_conversion_error_at_creates_correct_error() {
1✔
226
        let err = ConfigError::conversion_error_at("my.key", "test message");
1✔
227
        match err {
1✔
228
            ConfigError::ConversionError { key, message } => {
1✔
229
                assert_eq!(key, "my.key");
1✔
230
                assert_eq!(message, "test message");
1✔
231
            }
232
            _ => panic!("Expected ConversionError"),
×
233
        }
234
    }
1✔
235

236
    #[test]
237
    fn test_type_mismatch_at_creates_correct_error() {
1✔
238
        use qubit_common::DataType;
239
        let err = ConfigError::type_mismatch_at("a.b", DataType::Bool, DataType::Int32);
1✔
240
        match err {
1✔
241
            ConfigError::TypeMismatch {
242
                key,
1✔
243
                expected,
1✔
244
                actual,
1✔
245
            } => {
246
                assert_eq!(key, "a.b");
1✔
247
                assert_eq!(expected, DataType::Bool);
1✔
248
                assert_eq!(actual, DataType::Int32);
1✔
249
            }
250
            _ => panic!("Expected TypeMismatch"),
×
251
        }
252
    }
1✔
253
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc