qubit_config/config.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026.
4 * Haixing Hu, Qubit Co. Ltd.
5 *
6 * All rights reserved.
7 *
8 ******************************************************************************/
9//! # Configuration Manager
10//!
11//! Provides storage, retrieval, and management of configurations.
12//!
13//! # Author
14//!
15//! Haixing Hu
16
17#![allow(private_bounds)]
18
19use serde::de::DeserializeOwned;
20use serde::{Deserialize, Serialize};
21use serde_json::{Map, Value, from_value};
22use std::collections::HashMap;
23
24use crate::ConfigPropertyMut;
25use crate::config_prefix_view::ConfigPrefixView;
26use crate::config_reader::ConfigReader;
27use crate::constants::DEFAULT_MAX_SUBSTITUTION_DEPTH;
28use crate::source::ConfigSource;
29use crate::utils;
30use crate::{ConfigError, ConfigResult, Property};
31use qubit_common::DataType;
32use qubit_value::MultiValues;
33use qubit_value::multi_values::{
34 MultiValuesAddArg, MultiValuesAdder, MultiValuesFirstGetter, MultiValuesGetter,
35 MultiValuesMultiAdder, MultiValuesSetArg, MultiValuesSetter, MultiValuesSetterSlice,
36 MultiValuesSingleSetter,
37};
38
39/// Configuration Manager
40///
41/// Manages a set of configuration properties with type-safe read/write
42/// interfaces.
43///
44/// # Features
45///
46/// - Supports multiple data types
47/// - Supports variable substitution (`${var_name}` format)
48/// - Supports configuration merging
49/// - Supports final value protection
50/// - Thread-safe (when wrapped in `Arc<RwLock<Config>>`)
51///
52/// # Examples
53///
54/// ```rust
55/// use qubit_config::Config;
56///
57/// let mut config = Config::new();
58///
59/// // Set configuration values (type inference)
60/// config.set("port", 8080).unwrap(); // inferred as i32
61/// config.set("host", "localhost").unwrap();
62/// // &str is converted to String
63/// config.set("debug", true).unwrap(); // inferred as bool
64/// config.set("timeout", 30.5).unwrap(); // inferred as f64
65/// config.set("code", 42u8).unwrap(); // inferred as u8
66///
67/// // Set multiple values (type inference)
68/// config.set("ports", vec![8080, 8081, 8082]).unwrap(); // inferred as i32
69/// config.set("hosts", vec!["host1", "host2"]).unwrap();
70/// // &str elements are converted
71///
72/// // Read configuration values (type inference)
73/// let port: i32 = config.get("port").unwrap();
74/// let host: String = config.get("host").unwrap();
75/// let debug: bool = config.get("debug").unwrap();
76/// let code: u8 = config.get("code").unwrap();
77///
78/// // Read configuration values (turbofish)
79/// let port = config.get::<i32>("port").unwrap();
80///
81/// // Read configuration value or use default
82/// let timeout: u64 = config.get_or("timeout", 30);
83/// ```
84///
85/// # Author
86///
87/// Haixing Hu
88///
89#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
90pub struct Config {
91 /// Configuration description
92 description: Option<String>,
93 /// Configuration property mapping
94 pub(crate) properties: HashMap<String, Property>,
95 /// Whether variable substitution is enabled
96 enable_variable_substitution: bool,
97 /// Maximum depth for variable substitution
98 max_substitution_depth: usize,
99}
100
101impl Config {
102 /// Creates a new empty configuration
103 ///
104 /// # Returns
105 ///
106 /// Returns a new configuration instance
107 ///
108 /// # Examples
109 ///
110 /// ```rust
111 /// use qubit_config::Config;
112 ///
113 /// let mut config = Config::new();
114 /// assert!(config.is_empty());
115 /// ```
116 #[inline]
117 pub fn new() -> Self {
118 Self {
119 description: None,
120 properties: HashMap::new(),
121 enable_variable_substitution: true,
122 max_substitution_depth: DEFAULT_MAX_SUBSTITUTION_DEPTH,
123 }
124 }
125
126 /// Creates a configuration with description
127 ///
128 /// # Parameters
129 ///
130 /// * `description` - Configuration description
131 ///
132 /// # Returns
133 ///
134 /// Returns a new configuration instance
135 ///
136 /// # Examples
137 ///
138 /// ```rust
139 /// use qubit_config::Config;
140 ///
141 /// let config = Config::with_description("Server Configuration");
142 /// assert_eq!(config.description(), Some("Server Configuration"));
143 /// ```
144 #[inline]
145 pub fn with_description(description: &str) -> Self {
146 Self {
147 description: Some(description.to_string()),
148 properties: HashMap::new(),
149 enable_variable_substitution: true,
150 max_substitution_depth: DEFAULT_MAX_SUBSTITUTION_DEPTH,
151 }
152 }
153
154 // ========================================================================
155 // Basic Property Access
156 // ========================================================================
157
158 /// Gets the configuration description
159 ///
160 /// # Returns
161 ///
162 /// Returns the configuration description as Option
163 #[inline]
164 pub fn description(&self) -> Option<&str> {
165 self.description.as_deref()
166 }
167
168 /// Sets the configuration description
169 ///
170 /// # Parameters
171 ///
172 /// * `description` - Configuration description
173 ///
174 /// # Returns
175 ///
176 /// Nothing.
177 #[inline]
178 pub fn set_description(&mut self, description: Option<String>) {
179 self.description = description;
180 }
181
182 /// Checks if variable substitution is enabled
183 ///
184 /// # Returns
185 ///
186 /// Returns `true` if variable substitution is enabled
187 #[inline]
188 pub fn is_enable_variable_substitution(&self) -> bool {
189 self.enable_variable_substitution
190 }
191
192 /// Sets whether to enable variable substitution
193 ///
194 /// # Parameters
195 ///
196 /// * `enable` - Whether to enable
197 ///
198 /// # Returns
199 ///
200 /// Nothing.
201 #[inline]
202 pub fn set_enable_variable_substitution(&mut self, enable: bool) {
203 self.enable_variable_substitution = enable;
204 }
205
206 /// Gets the maximum depth for variable substitution
207 ///
208 /// # Returns
209 ///
210 /// Returns the maximum depth value
211 #[inline]
212 pub fn max_substitution_depth(&self) -> usize {
213 self.max_substitution_depth
214 }
215
216 /// Creates a read-only prefix view using [`ConfigPrefixView`].
217 ///
218 /// # Parameters
219 ///
220 /// * `prefix` - Prefix
221 ///
222 /// # Returns
223 ///
224 /// Returns a read-only prefix view
225 ///
226 /// # Examples
227 ///
228 /// ```rust
229 /// use qubit_config::{Config, ConfigReader};
230 ///
231 /// let mut config = Config::new();
232 /// config.set("server.port", 8080).unwrap();
233 /// config.set("server.host", "localhost").unwrap();
234 ///
235 /// let server = config.prefix_view("server");
236 /// assert_eq!(server.get::<i32>("port").unwrap(), 8080);
237 /// assert_eq!(server.get::<String>("host").unwrap(), "localhost");
238 /// ```
239 #[inline]
240 pub fn prefix_view(&self, prefix: &str) -> ConfigPrefixView<'_> {
241 ConfigPrefixView::new(self, prefix)
242 }
243
244 /// Sets the maximum depth for variable substitution
245 ///
246 /// # Parameters
247 ///
248 /// * `depth` - Maximum depth
249 ///
250 /// # Returns
251 ///
252 /// Nothing.
253 #[inline]
254 pub fn set_max_substitution_depth(&mut self, depth: usize) {
255 self.max_substitution_depth = depth;
256 }
257
258 // ========================================================================
259 // Configuration Item Management
260 // ========================================================================
261
262 /// Checks if the configuration contains an item with the specified name
263 ///
264 /// # Parameters
265 ///
266 /// * `name` - Configuration item name
267 ///
268 /// # Returns
269 ///
270 /// Returns `true` if the configuration item exists
271 ///
272 /// # Examples
273 ///
274 /// ```rust
275 /// use qubit_config::Config;
276 ///
277 /// let mut config = Config::new();
278 /// config.set("port", 8080).unwrap();
279 ///
280 /// assert!(config.contains("port"));
281 /// assert!(!config.contains("host"));
282 /// ```
283 #[inline]
284 pub fn contains(&self, name: &str) -> bool {
285 self.properties.contains_key(name)
286 }
287
288 /// Gets a reference to a configuration item
289 ///
290 /// # Parameters
291 ///
292 /// * `name` - Configuration item name
293 ///
294 /// # Returns
295 ///
296 /// Returns Option containing the configuration item
297 #[inline]
298 pub fn get_property(&self, name: &str) -> Option<&Property> {
299 self.properties.get(name)
300 }
301
302 /// Gets guarded mutable access to a non-final configuration item.
303 ///
304 /// # Parameters
305 ///
306 /// * `name` - Configuration item name
307 ///
308 /// # Returns
309 ///
310 /// Returns `Ok(Some(_))` for an existing non-final property, `Ok(None)`
311 /// for a missing property, or [`ConfigError::PropertyIsFinal`] for an
312 /// existing final property. The returned guard re-checks final state before
313 /// each value-changing operation.
314 #[inline]
315 pub fn get_property_mut(&mut self, name: &str) -> ConfigResult<Option<ConfigPropertyMut<'_>>> {
316 self.ensure_property_not_final(name)?;
317 Ok(self.properties.get_mut(name).map(ConfigPropertyMut::new))
318 }
319
320 /// Sets the final flag of an existing configuration item.
321 ///
322 /// A non-final property can be marked final. A property that is already
323 /// final may be marked final again, but cannot be unset through this API.
324 ///
325 /// # Parameters
326 ///
327 /// * `name` - Configuration item name.
328 /// * `is_final` - Whether the property should be final.
329 ///
330 /// # Returns
331 ///
332 /// `Ok(())` on success.
333 ///
334 /// # Errors
335 ///
336 /// - [`ConfigError::PropertyNotFound`] if the key does not exist.
337 /// - [`ConfigError::PropertyIsFinal`] when trying to unset a final
338 /// property.
339 pub fn set_final(&mut self, name: &str, is_final: bool) -> ConfigResult<()> {
340 let property = self
341 .properties
342 .get_mut(name)
343 .ok_or_else(|| ConfigError::PropertyNotFound(name.to_string()))?;
344 if property.is_final() && !is_final {
345 return Err(ConfigError::PropertyIsFinal(name.to_string()));
346 }
347 property.set_final(is_final);
348 Ok(())
349 }
350
351 /// Removes a non-final configuration item.
352 ///
353 /// # Parameters
354 ///
355 /// * `name` - Configuration item name
356 ///
357 /// # Returns
358 ///
359 /// Returns the removed configuration item, or None if it doesn't exist
360 ///
361 /// # Examples
362 ///
363 /// ```rust
364 /// use qubit_config::Config;
365 ///
366 /// let mut config = Config::new();
367 /// config.set("port", 8080).unwrap();
368 ///
369 /// let removed = config.remove("port").unwrap();
370 /// assert!(removed.is_some());
371 /// assert!(!config.contains("port"));
372 /// ```
373 #[inline]
374 pub fn remove(&mut self, name: &str) -> ConfigResult<Option<Property>> {
375 self.ensure_property_not_final(name)?;
376 Ok(self.properties.remove(name))
377 }
378
379 /// Clears all configuration items if none of them are final.
380 ///
381 /// # Examples
382 ///
383 /// ```rust
384 /// use qubit_config::Config;
385 ///
386 /// let mut config = Config::new();
387 /// config.set("port", 8080).unwrap();
388 /// config.set("host", "localhost").unwrap();
389 ///
390 /// config.clear().unwrap();
391 /// assert!(config.is_empty());
392 /// ```
393 ///
394 /// # Returns
395 ///
396 /// `Ok(())` when all properties were removed.
397 #[inline]
398 pub fn clear(&mut self) -> ConfigResult<()> {
399 self.ensure_no_final_properties()?;
400 self.properties.clear();
401 Ok(())
402 }
403
404 /// Gets the number of configuration items
405 ///
406 /// # Returns
407 ///
408 /// Returns the number of configuration items
409 #[inline]
410 pub fn len(&self) -> usize {
411 self.properties.len()
412 }
413
414 /// Checks if the configuration is empty
415 ///
416 /// # Returns
417 ///
418 /// Returns `true` if the configuration contains no items
419 #[inline]
420 pub fn is_empty(&self) -> bool {
421 self.properties.is_empty()
422 }
423
424 /// Gets all configuration item names
425 ///
426 /// # Returns
427 ///
428 /// Returns a Vec of configuration item names
429 ///
430 /// # Examples
431 ///
432 /// ```rust
433 /// use qubit_config::Config;
434 ///
435 /// let mut config = Config::new();
436 /// config.set("port", 8080).unwrap();
437 /// config.set("host", "localhost").unwrap();
438 ///
439 /// let keys = config.keys();
440 /// assert_eq!(keys.len(), 2);
441 /// assert!(keys.contains(&"port".to_string()));
442 /// assert!(keys.contains(&"host".to_string()));
443 /// ```
444 pub fn keys(&self) -> Vec<String> {
445 self.properties.keys().cloned().collect()
446 }
447
448 /// Looks up a property by key for internal read paths.
449 ///
450 /// # Parameters
451 ///
452 /// * `name` - Configuration key
453 ///
454 /// # Returns
455 ///
456 /// `Ok(&Property)` if the key exists, or [`ConfigError::PropertyNotFound`]
457 /// otherwise.
458 #[inline]
459 fn get_property_by_name(&self, name: &str) -> ConfigResult<&Property> {
460 self.properties
461 .get(name)
462 .ok_or_else(|| ConfigError::PropertyNotFound(name.to_string()))
463 }
464
465 /// Ensures the entry for `name` is not marked final before a write.
466 ///
467 /// Missing keys are allowed (writes may create them).
468 ///
469 /// # Parameters
470 ///
471 /// * `name` - Configuration key
472 ///
473 /// # Returns
474 ///
475 /// `Ok(())` if the key is absent or not final, or
476 /// [`ConfigError::PropertyIsFinal`] if an existing property is final.
477 #[inline]
478 fn ensure_property_not_final(&self, name: &str) -> ConfigResult<()> {
479 if let Some(prop) = self.properties.get(name)
480 && prop.is_final()
481 {
482 return Err(ConfigError::PropertyIsFinal(name.to_string()));
483 }
484 Ok(())
485 }
486
487 /// Ensures no property is final before a bulk destructive operation.
488 #[inline]
489 fn ensure_no_final_properties(&self) -> ConfigResult<()> {
490 if let Some((name, _)) = self.properties.iter().find(|(_, prop)| prop.is_final()) {
491 return Err(ConfigError::PropertyIsFinal(name.clone()));
492 }
493 Ok(())
494 }
495
496 /// Shared "optional get" semantics: treat missing or empty properties as
497 /// `None`, otherwise run `read` and wrap the result in `Some`.
498 ///
499 /// Used by [`Self::get_optional`], [`Self::get_optional_list`],
500 /// [`Self::get_optional_string`], and [`Self::get_optional_string_list`].
501 ///
502 /// # Type Parameters
503 ///
504 /// * `T` - Value type produced by `read`
505 ///
506 /// # Parameters
507 ///
508 /// * `name` - Configuration key
509 /// * `read` - Loads `T` when the key exists and is non-empty (typically
510 /// delegates to [`Self::get`], [`Self::get_list`], etc.)
511 ///
512 /// # Returns
513 ///
514 /// `Ok(None)` if the key is missing or the property has no values;
515 /// `Ok(Some(value))` on success; or the error from `read` on failure.
516 fn get_optional_when_present<T>(
517 &self,
518 name: &str,
519 read: impl FnOnce(&Self) -> ConfigResult<T>,
520 ) -> ConfigResult<Option<T>> {
521 match self.properties.get(name) {
522 None => Ok(None),
523 Some(prop) if prop.is_empty() => Ok(None),
524 Some(_) => read(self).map(Some),
525 }
526 }
527
528 // ========================================================================
529 // Core Generic Methods
530 // ========================================================================
531
532 /// Gets a configuration value.
533 ///
534 /// Core read API with type inference.
535 ///
536 /// # Note
537 ///
538 /// This method does not perform variable substitution for string types. If
539 /// you need variable substitution, use [`Self::get_string`].
540 ///
541 /// # Type Parameters
542 ///
543 /// * `T` - Target type, must implement `FromPropertyValue` trait
544 ///
545 /// # Parameters
546 ///
547 /// * `name` - Configuration item name
548 ///
549 /// # Returns
550 ///
551 /// The value of the specified type on success, or a [`ConfigError`] on
552 /// failure.
553 ///
554 /// # Errors
555 ///
556 /// - [`ConfigError::PropertyNotFound`] if the key does not exist
557 /// - [`ConfigError::PropertyHasNoValue`] if the property has no value
558 /// - [`ConfigError::TypeMismatch`] if the type does not match
559 ///
560 /// # Examples
561 ///
562 /// ```rust
563 /// use qubit_config::Config;
564 ///
565 /// let mut config = Config::new();
566 /// config.set("port", 8080).unwrap();
567 /// config.set("host", "localhost").unwrap();
568 ///
569 /// // Method 1: Type inference
570 /// let port: i32 = config.get("port").unwrap();
571 /// let host: String = config.get("host").unwrap();
572 ///
573 /// // Method 2: Turbofish
574 /// let port = config.get::<i32>("port").unwrap();
575 /// let host = config.get::<String>("host").unwrap();
576 ///
577 /// // Method 3: Inference from usage
578 /// fn start_server(port: i32, host: String) { }
579 /// start_server(config.get("port").unwrap(), config.get("host").unwrap());
580 /// ```
581 pub fn get<T>(&self, name: &str) -> ConfigResult<T>
582 where
583 MultiValues: MultiValuesFirstGetter<T>,
584 {
585 let property = self.get_property_by_name(name)?;
586
587 property
588 .get_first::<T>()
589 .map_err(|e| utils::map_value_error(name, e))
590 }
591
592 /// Gets a configuration value or returns a default value
593 ///
594 /// Returns `default` if the key is missing or if reading the value fails.
595 ///
596 /// # Type Parameters
597 ///
598 /// * `T` - Target type, must implement `FromPropertyValue` trait
599 ///
600 /// # Parameters
601 ///
602 /// * `name` - Configuration item name
603 /// * `default` - Default value
604 ///
605 /// # Returns
606 ///
607 /// Returns the configuration value or default value
608 ///
609 /// # Examples
610 ///
611 /// ```rust
612 /// use qubit_config::Config;
613 ///
614 /// let config = Config::new();
615 ///
616 /// let port: i32 = config.get_or("port", 8080);
617 /// let host: String = config.get_or("host", "localhost".to_string());
618 ///
619 /// assert_eq!(port, 8080);
620 /// assert_eq!(host, "localhost");
621 /// ```
622 pub fn get_or<T>(&self, name: &str, default: T) -> T
623 where
624 MultiValues: MultiValuesFirstGetter<T>,
625 {
626 self.get(name).unwrap_or(default)
627 }
628
629 /// Gets a list of configuration values
630 ///
631 /// Gets all values of a configuration item (multi-value configuration).
632 ///
633 /// # Type Parameters
634 ///
635 /// * `T` - Target type, must implement `FromPropertyValue` trait
636 ///
637 /// # Parameters
638 ///
639 /// * `name` - Configuration item name
640 ///
641 /// # Returns
642 ///
643 /// Returns a list of values on success, or an error on failure
644 ///
645 /// # Examples
646 ///
647 /// ```rust
648 /// use qubit_config::Config;
649 ///
650 /// let mut config = Config::new();
651 /// config.set("ports", vec![8080, 8081, 8082]).unwrap();
652 ///
653 /// let ports: Vec<i32> = config.get_list("ports").unwrap();
654 /// assert_eq!(ports, vec![8080, 8081, 8082]);
655 /// ```
656 pub fn get_list<T>(&self, name: &str) -> ConfigResult<Vec<T>>
657 where
658 MultiValues: MultiValuesGetter<T>,
659 {
660 let property = self.get_property_by_name(name)?;
661 if property.is_empty() {
662 return Ok(Vec::new());
663 }
664
665 property
666 .get::<T>()
667 .map_err(|e| utils::map_value_error(name, e))
668 }
669
670 /// Sets a configuration value
671 ///
672 /// This is the core method for setting configuration values, supporting
673 /// type inference.
674 ///
675 /// # Type Parameters
676 ///
677 /// * `T` - Element type, automatically inferred from the `values` parameter
678 ///
679 /// # Parameters
680 ///
681 /// * `name` - Configuration item name
682 /// * `values` - Value to store; supports `T`, `Vec<T>`, `&[T]`, and related
683 /// forms accepted by [`MultiValues`] setters
684 ///
685 /// # Returns
686 ///
687 /// Returns Ok(()) on success, or an error on failure
688 ///
689 /// # Errors
690 ///
691 /// - [`ConfigError::PropertyIsFinal`] if the property is marked final
692 ///
693 /// # Examples
694 ///
695 /// ```rust
696 /// use qubit_config::Config;
697 ///
698 /// let mut config = Config::new();
699 ///
700 /// // Set single values (type auto-inference)
701 /// config.set("port", 8080).unwrap(); // T inferred as i32
702 /// config.set("host", "localhost").unwrap();
703 /// // T inferred as String; &str is converted
704 /// config.set("debug", true).unwrap(); // T inferred as bool
705 /// config.set("timeout", 30.5).unwrap(); // T inferred as f64
706 ///
707 /// // Set multiple values (type auto-inference)
708 /// config.set("ports", vec![8080, 8081, 8082]).unwrap(); // T inferred as i32
709 /// config.set("hosts", vec!["host1", "host2"]).unwrap();
710 /// // T inferred as &str (then converted)
711 /// ```
712 pub fn set<S>(&mut self, name: &str, values: S) -> ConfigResult<()>
713 where
714 S: for<'a> MultiValuesSetArg<'a>,
715 <S as MultiValuesSetArg<'static>>::Item: Clone,
716 MultiValues: MultiValuesSetter<<S as MultiValuesSetArg<'static>>::Item>
717 + MultiValuesSetterSlice<<S as MultiValuesSetArg<'static>>::Item>
718 + MultiValuesSingleSetter<<S as MultiValuesSetArg<'static>>::Item>,
719 {
720 self.ensure_property_not_final(name)?;
721 let property = self
722 .properties
723 .entry(name.to_string())
724 .or_insert_with(|| Property::new(name));
725
726 property.set(values).map_err(ConfigError::from)
727 }
728
729 /// Adds configuration values
730 ///
731 /// Adds values to an existing configuration item (multi-value properties).
732 ///
733 /// # Type Parameters
734 ///
735 /// * `T` - Element type, automatically inferred from the `values` parameter
736 ///
737 /// # Parameters
738 ///
739 /// * `name` - Configuration item name
740 /// * `values` - Values to append; supports the same forms as [`Self::set`]
741 ///
742 /// # Returns
743 ///
744 /// Returns Ok(()) on success, or an error on failure
745 ///
746 /// # Examples
747 ///
748 /// ```rust
749 /// use qubit_config::Config;
750 ///
751 /// let mut config = Config::new();
752 /// config.set("port", 8080).unwrap(); // Set initial value
753 /// config.add("port", 8081).unwrap(); // Add single value
754 /// config.add("port", vec![8082, 8083]).unwrap(); // Add multiple values
755 /// config.add("port", vec![8084, 8085]).unwrap(); // Add slice
756 ///
757 /// let ports: Vec<i32> = config.get_list("port").unwrap();
758 /// assert_eq!(ports, vec![8080, 8081, 8082, 8083, 8084, 8085]);
759 /// ```
760 pub fn add<S>(&mut self, name: &str, values: S) -> ConfigResult<()>
761 where
762 S: for<'a> MultiValuesAddArg<'a, Item = <S as MultiValuesSetArg<'static>>::Item>
763 + for<'a> MultiValuesSetArg<'a>,
764 <S as MultiValuesSetArg<'static>>::Item: Clone,
765 MultiValues: MultiValuesAdder<<S as MultiValuesSetArg<'static>>::Item>
766 + MultiValuesMultiAdder<<S as MultiValuesSetArg<'static>>::Item>
767 + MultiValuesSetter<<S as MultiValuesSetArg<'static>>::Item>
768 + MultiValuesSetterSlice<<S as MultiValuesSetArg<'static>>::Item>
769 + MultiValuesSingleSetter<<S as MultiValuesSetArg<'static>>::Item>,
770 {
771 self.ensure_property_not_final(name)?;
772
773 if let Some(property) = self.properties.get_mut(name) {
774 property.add(values).map_err(ConfigError::from)
775 } else {
776 let mut property = Property::new(name);
777 // Note: property.set() always returns Ok(()) in current MultiValues implementation,
778 // as it unconditionally replaces the entire value without any validation.
779 // We explicitly ignore the result to improve code coverage and avoid unreachable error paths.
780 let _ = property.set(values);
781 self.properties.insert(name.to_string(), property);
782 Ok(())
783 }
784 }
785
786 // ========================================================================
787 // String Special Handling (Variable Substitution)
788 // ========================================================================
789
790 /// Gets a string configuration value (with variable substitution)
791 ///
792 /// If variable substitution is enabled, replaces `${var_name}` placeholders
793 /// in the stored string.
794 ///
795 /// # Parameters
796 ///
797 /// * `name` - Configuration item name
798 ///
799 /// # Returns
800 ///
801 /// Returns the string value on success, or an error on failure
802 ///
803 /// # Examples
804 ///
805 /// ```rust
806 /// use qubit_config::Config;
807 ///
808 /// let mut config = Config::new();
809 /// config.set("base_url", "http://localhost").unwrap();
810 /// config.set("api_url", "${base_url}/api").unwrap();
811 ///
812 /// let api_url = config.get_string("api_url").unwrap();
813 /// assert_eq!(api_url, "http://localhost/api");
814 /// ```
815 pub fn get_string(&self, name: &str) -> ConfigResult<String> {
816 let value: String = self.get(name)?;
817 if self.enable_variable_substitution {
818 utils::substitute_variables(&value, self, self.max_substitution_depth)
819 } else {
820 Ok(value)
821 }
822 }
823
824 /// Gets a string with substitution, or `default` if reading fails.
825 ///
826 /// # Parameters
827 ///
828 /// * `name` - Configuration item name
829 /// * `default` - Default value
830 ///
831 /// # Returns
832 ///
833 /// Returns the string value or default value
834 ///
835 pub fn get_string_or(&self, name: &str, default: &str) -> String {
836 self.get_string(name)
837 .unwrap_or_else(|_| default.to_string())
838 }
839
840 /// Gets a list of string configuration values (with variable substitution)
841 ///
842 /// If variable substitution is enabled, runs it on each list element
843 /// (same `${var_name}` rules as [`Self::get_string`]).
844 ///
845 /// # Parameters
846 ///
847 /// * `name` - Configuration item name
848 ///
849 /// # Returns
850 ///
851 /// Returns a list of strings on success, or an error on failure
852 ///
853 /// # Examples
854 ///
855 /// ```rust
856 /// use qubit_config::Config;
857 ///
858 /// let mut config = Config::new();
859 /// config.set("base_path", "/opt/app").unwrap();
860 /// config.set("paths", vec!["${base_path}/bin", "${base_path}/lib"]).unwrap();
861 ///
862 /// let paths = config.get_string_list("paths").unwrap();
863 /// assert_eq!(paths, vec!["/opt/app/bin", "/opt/app/lib"]);
864 /// ```
865 pub fn get_string_list(&self, name: &str) -> ConfigResult<Vec<String>> {
866 let values: Vec<String> = self.get_list(name)?;
867 if self.enable_variable_substitution {
868 values
869 .into_iter()
870 .map(|v| utils::substitute_variables(&v, self, self.max_substitution_depth))
871 .collect()
872 } else {
873 Ok(values)
874 }
875 }
876
877 /// Gets a list of string configuration values or returns a default value
878 /// (with variable substitution)
879 ///
880 /// # Parameters
881 ///
882 /// * `name` - Configuration item name
883 /// * `default` - Default value (can be array slice or vec)
884 ///
885 /// # Returns
886 ///
887 /// Returns the list of strings or default value
888 ///
889 /// # Examples
890 ///
891 /// ```rust
892 /// use qubit_config::Config;
893 ///
894 /// let config = Config::new();
895 ///
896 /// // Using array slice
897 /// let paths = config.get_string_list_or("paths", &["/default/path"]);
898 /// assert_eq!(paths, vec!["/default/path"]);
899 ///
900 /// // Using vec
901 /// let paths = config.get_string_list_or("paths", &vec!["path1", "path2"]);
902 /// assert_eq!(paths, vec!["path1", "path2"]);
903 /// ```
904 pub fn get_string_list_or(&self, name: &str, default: &[&str]) -> Vec<String> {
905 self.get_string_list(name)
906 .unwrap_or_else(|_| default.iter().map(|s| s.to_string()).collect())
907 }
908
909 // ========================================================================
910 // Configuration Source Integration
911 // ========================================================================
912
913 /// Merges configuration from a `ConfigSource`
914 ///
915 /// Loads all key-value pairs from the given source and merges them into
916 /// this configuration. Existing non-final properties are overwritten;
917 /// final properties are preserved and cause an error if the source tries
918 /// to overwrite them.
919 ///
920 /// # Parameters
921 ///
922 /// * `source` - The configuration source to load from
923 ///
924 /// # Returns
925 ///
926 /// Returns `Ok(())` on success, or a `ConfigError` on failure
927 ///
928 /// # Examples
929 ///
930 /// ```rust
931 /// use qubit_config::Config;
932 /// use qubit_config::source::{
933 /// CompositeConfigSource, ConfigSource,
934 /// EnvConfigSource, TomlConfigSource,
935 /// };
936 ///
937 /// let mut composite = CompositeConfigSource::new();
938 /// let path = std::env::temp_dir().join(format!(
939 /// "qubit-config-doc-{}.toml",
940 /// std::process::id()
941 /// ));
942 /// std::fs::write(&path, "app.name = \"demo\"").unwrap();
943 /// composite.add(TomlConfigSource::from_file(&path));
944 /// composite.add(EnvConfigSource::with_prefix("APP_"));
945 ///
946 /// let mut config = Config::new();
947 /// config.merge_from_source(&composite).unwrap();
948 /// std::fs::remove_file(&path).unwrap();
949 /// ```
950 #[inline]
951 pub fn merge_from_source(&mut self, source: &dyn ConfigSource) -> ConfigResult<()> {
952 source.load(self)
953 }
954
955 // ========================================================================
956 // Prefix Traversal and Sub-tree Extraction (v0.4.0)
957 // ========================================================================
958
959 /// Iterates over all configuration entries as `(key, &Property)` pairs.
960 ///
961 /// # Returns
962 ///
963 /// An iterator yielding `(&str, &Property)` tuples.
964 ///
965 /// # Examples
966 ///
967 /// ```rust
968 /// use qubit_config::Config;
969 ///
970 /// let mut config = Config::new();
971 /// config.set("host", "localhost").unwrap();
972 /// config.set("port", 8080).unwrap();
973 ///
974 /// for (key, prop) in config.iter() {
975 /// println!("{} = {:?}", key, prop);
976 /// }
977 /// ```
978 #[inline]
979 pub fn iter(&self) -> impl Iterator<Item = (&str, &Property)> {
980 self.properties.iter().map(|(k, v)| (k.as_str(), v))
981 }
982
983 /// Iterates over all configuration entries whose key starts with `prefix`.
984 ///
985 /// # Parameters
986 ///
987 /// * `prefix` - The key prefix to filter by (e.g., `"http."`)
988 ///
989 /// # Returns
990 ///
991 /// An iterator of `(&str, &Property)` whose keys start with `prefix`.
992 ///
993 /// # Examples
994 ///
995 /// ```rust
996 /// use qubit_config::Config;
997 ///
998 /// let mut config = Config::new();
999 /// config.set("http.host", "localhost").unwrap();
1000 /// config.set("http.port", 8080).unwrap();
1001 /// config.set("db.host", "dbhost").unwrap();
1002 ///
1003 /// let http_entries: Vec<_> = config.iter_prefix("http.").collect();
1004 /// assert_eq!(http_entries.len(), 2);
1005 /// ```
1006 #[inline]
1007 pub fn iter_prefix<'a>(
1008 &'a self,
1009 prefix: &'a str,
1010 ) -> impl Iterator<Item = (&'a str, &'a Property)> {
1011 self.properties
1012 .iter()
1013 .filter(move |(k, _)| k.starts_with(prefix))
1014 .map(|(k, v)| (k.as_str(), v))
1015 }
1016
1017 /// Returns `true` if any configuration key starts with `prefix`.
1018 ///
1019 /// # Parameters
1020 ///
1021 /// * `prefix` - The key prefix to check
1022 ///
1023 /// # Returns
1024 ///
1025 /// `true` if at least one key starts with `prefix`, `false` otherwise.
1026 ///
1027 /// # Examples
1028 ///
1029 /// ```rust
1030 /// use qubit_config::Config;
1031 ///
1032 /// let mut config = Config::new();
1033 /// config.set("http.host", "localhost").unwrap();
1034 ///
1035 /// assert!(config.contains_prefix("http."));
1036 /// assert!(!config.contains_prefix("db."));
1037 /// ```
1038 #[inline]
1039 pub fn contains_prefix(&self, prefix: &str) -> bool {
1040 self.properties.keys().any(|k| k.starts_with(prefix))
1041 }
1042
1043 /// Extracts a sub-configuration for keys matching `prefix`.
1044 ///
1045 /// # Parameters
1046 ///
1047 /// * `prefix` - The key prefix to extract (e.g., `"http"`)
1048 /// * `strip_prefix` - When `true`, removes `prefix` and the following dot
1049 /// from keys in the result; when `false`, keys are copied unchanged.
1050 ///
1051 /// # Returns
1052 ///
1053 /// A new `Config` containing only the matching entries.
1054 ///
1055 /// # Examples
1056 ///
1057 /// ```rust
1058 /// use qubit_config::Config;
1059 ///
1060 /// let mut config = Config::new();
1061 /// config.set("http.host", "localhost").unwrap();
1062 /// config.set("http.port", 8080).unwrap();
1063 /// config.set("db.host", "dbhost").unwrap();
1064 ///
1065 /// let http_config = config.subconfig("http", true).unwrap();
1066 /// assert!(http_config.contains("host"));
1067 /// assert!(http_config.contains("port"));
1068 /// assert!(!http_config.contains("db.host"));
1069 /// ```
1070 pub fn subconfig(&self, prefix: &str, strip_prefix: bool) -> ConfigResult<Config> {
1071 let mut sub = Config::new();
1072 sub.enable_variable_substitution = self.enable_variable_substitution;
1073 sub.max_substitution_depth = self.max_substitution_depth;
1074
1075 // Empty prefix means "all keys"
1076 if prefix.is_empty() {
1077 for (k, v) in &self.properties {
1078 sub.properties.insert(k.clone(), v.clone());
1079 }
1080 return Ok(sub);
1081 }
1082
1083 let full_prefix = format!("{prefix}.");
1084
1085 for (k, v) in &self.properties {
1086 if k == prefix || k.starts_with(&full_prefix) {
1087 let new_key = if strip_prefix {
1088 if k == prefix {
1089 prefix.to_string()
1090 } else {
1091 k[full_prefix.len()..].to_string()
1092 }
1093 } else {
1094 k.clone()
1095 };
1096 sub.properties.insert(new_key, v.clone());
1097 }
1098 }
1099
1100 Ok(sub)
1101 }
1102
1103 // ========================================================================
1104 // Optional and Null Semantics (v0.4.0)
1105 // ========================================================================
1106
1107 /// Returns `true` if the property exists but has no value (empty / null).
1108 ///
1109 /// This distinguishes between:
1110 /// - Key does not exist → `contains()` returns `false`
1111 /// - Key exists but is empty/null → `is_null()` returns `true`
1112 ///
1113 /// # Parameters
1114 ///
1115 /// * `name` - Configuration item name
1116 ///
1117 /// # Returns
1118 ///
1119 /// `true` if the property exists and has no values (is empty).
1120 ///
1121 /// # Examples
1122 ///
1123 /// ```rust
1124 /// use qubit_config::Config;
1125 /// use qubit_common::DataType;
1126 ///
1127 /// let mut config = Config::new();
1128 /// config.set_null("nullable", DataType::String).unwrap();
1129 ///
1130 /// assert!(config.is_null("nullable"));
1131 /// assert!(!config.is_null("missing"));
1132 /// ```
1133 pub fn is_null(&self, name: &str) -> bool {
1134 self.properties
1135 .get(name)
1136 .map(|p| p.is_empty())
1137 .unwrap_or(false)
1138 }
1139
1140 /// Gets an optional configuration value.
1141 ///
1142 /// Distinguishes between three states:
1143 /// - `Ok(Some(value))` – key exists and has a value
1144 /// - `Ok(None)` – key does not exist, **or** exists but is null/empty
1145 /// - `Err(e)` – key exists and has a value, but conversion failed
1146 ///
1147 /// # Type Parameters
1148 ///
1149 /// * `T` - Target type
1150 ///
1151 /// # Parameters
1152 ///
1153 /// * `name` - Configuration item name
1154 ///
1155 /// # Returns
1156 ///
1157 /// `Ok(Some(value))`, `Ok(None)`, or `Err` as described above.
1158 ///
1159 /// # Examples
1160 ///
1161 /// ```rust
1162 /// use qubit_config::Config;
1163 ///
1164 /// let mut config = Config::new();
1165 /// config.set("port", 8080).unwrap();
1166 ///
1167 /// let port: Option<i32> = config.get_optional("port").unwrap();
1168 /// assert_eq!(port, Some(8080));
1169 ///
1170 /// let missing: Option<i32> = config.get_optional("missing").unwrap();
1171 /// assert_eq!(missing, None);
1172 /// ```
1173 pub fn get_optional<T>(&self, name: &str) -> ConfigResult<Option<T>>
1174 where
1175 MultiValues: MultiValuesFirstGetter<T>,
1176 {
1177 self.get_optional_when_present(name, |c| c.get(name))
1178 }
1179
1180 /// Gets an optional list of configuration values.
1181 ///
1182 /// See also [`Self::get_optional_string_list`] for optional string lists
1183 /// with variable substitution.
1184 ///
1185 /// Distinguishes between three states:
1186 /// - `Ok(Some(vec))` – key exists and has values
1187 /// - `Ok(None)` – key does not exist, **or** exists but is null/empty
1188 /// - `Err(e)` – key exists and has values, but conversion failed
1189 ///
1190 /// # Type Parameters
1191 ///
1192 /// * `T` - Target element type
1193 ///
1194 /// # Parameters
1195 ///
1196 /// * `name` - Configuration item name
1197 ///
1198 /// # Returns
1199 ///
1200 /// `Ok(Some(vec))`, `Ok(None)`, or `Err` as described above.
1201 ///
1202 /// # Examples
1203 ///
1204 /// ```rust
1205 /// use qubit_config::Config;
1206 ///
1207 /// let mut config = Config::new();
1208 /// config.set("ports", vec![8080, 8081]).unwrap();
1209 ///
1210 /// let ports: Option<Vec<i32>> = config.get_optional_list("ports").unwrap();
1211 /// assert_eq!(ports, Some(vec![8080, 8081]));
1212 ///
1213 /// let missing: Option<Vec<i32>> = config.get_optional_list("missing").unwrap();
1214 /// assert_eq!(missing, None);
1215 /// ```
1216 pub fn get_optional_list<T>(&self, name: &str) -> ConfigResult<Option<Vec<T>>>
1217 where
1218 MultiValues: MultiValuesGetter<T>,
1219 {
1220 self.get_optional_when_present(name, |c| c.get_list(name))
1221 }
1222
1223 /// Gets an optional string (with variable substitution when enabled).
1224 ///
1225 /// Same semantics as [`Self::get_optional`], but values are read via
1226 /// [`Self::get_string`], so `${...}` substitution applies when enabled.
1227 ///
1228 /// # Parameters
1229 ///
1230 /// * `name` - Configuration item name
1231 ///
1232 /// # Returns
1233 ///
1234 /// `Ok(Some(s))`, `Ok(None)`, or `Err` as for [`Self::get_optional`].
1235 ///
1236 /// # Examples
1237 ///
1238 /// ```rust
1239 /// use qubit_config::Config;
1240 ///
1241 /// let mut config = Config::new();
1242 /// config.set("base", "http://localhost").unwrap();
1243 /// config.set("api", "${base}/api").unwrap();
1244 ///
1245 /// let api = config.get_optional_string("api").unwrap();
1246 /// assert_eq!(api.as_deref(), Some("http://localhost/api"));
1247 ///
1248 /// let missing = config.get_optional_string("missing").unwrap();
1249 /// assert_eq!(missing, None);
1250 /// ```
1251 pub fn get_optional_string(&self, name: &str) -> ConfigResult<Option<String>> {
1252 self.get_optional_when_present(name, |c| c.get_string(name))
1253 }
1254
1255 /// Gets an optional string list (substitution per element when enabled).
1256 ///
1257 /// Same semantics as [`Self::get_optional_list`], but elements use
1258 /// [`Self::get_string_list`] (same `${...}` rules as [`Self::get_string`]).
1259 ///
1260 /// # Parameters
1261 ///
1262 /// * `name` - Configuration item name
1263 ///
1264 /// # Returns
1265 ///
1266 /// `Ok(Some(vec))`, `Ok(None)`, or `Err` like [`Self::get_optional_list`].
1267 ///
1268 /// # Examples
1269 ///
1270 /// ```rust
1271 /// use qubit_config::Config;
1272 ///
1273 /// let mut config = Config::new();
1274 /// config.set("root", "/opt/app").unwrap();
1275 /// config.set("paths", vec!["${root}/bin", "${root}/lib"]).unwrap();
1276 ///
1277 /// let paths = config.get_optional_string_list("paths").unwrap();
1278 /// assert_eq!(
1279 /// paths,
1280 /// Some(vec![
1281 /// "/opt/app/bin".to_string(),
1282 /// "/opt/app/lib".to_string(),
1283 /// ]),
1284 /// );
1285 /// ```
1286 pub fn get_optional_string_list(&self, name: &str) -> ConfigResult<Option<Vec<String>>> {
1287 self.get_optional_when_present(name, |c| c.get_string_list(name))
1288 }
1289
1290 // ========================================================================
1291 // Structured Config Deserialization (v0.4.0)
1292 // ========================================================================
1293
1294 /// Deserializes the subtree at `prefix` into `T` using `serde`.
1295 /// String values inside the generated serde value apply the same
1296 /// `${...}` substitution rules as [`Self::get_string`] and
1297 /// [`Self::get_string_list`] when substitution is enabled.
1298 ///
1299 /// Keys under `prefix` (prefix and trailing dot removed) form a flat map
1300 /// for `serde`, for example:
1301 ///
1302 /// ```rust
1303 /// #[derive(serde::Deserialize)]
1304 /// struct HttpOptions {
1305 /// host: String,
1306 /// port: u16,
1307 /// }
1308 /// ```
1309 ///
1310 /// can be populated from config keys `http.host` and `http.port` by calling
1311 /// `config.deserialize::<HttpOptions>("http")`.
1312 ///
1313 /// # Type Parameters
1314 ///
1315 /// * `T` - Target type, must implement `serde::de::DeserializeOwned`
1316 ///
1317 /// # Parameters
1318 ///
1319 /// * `prefix` - Key prefix for the struct fields (`""` means the root map)
1320 ///
1321 /// # Returns
1322 ///
1323 /// The deserialized `T`, or a [`ConfigError::DeserializeError`] on failure.
1324 ///
1325 /// # Examples
1326 ///
1327 /// ```rust
1328 /// use qubit_config::Config;
1329 /// use serde::Deserialize;
1330 ///
1331 /// #[derive(Deserialize, Debug, PartialEq)]
1332 /// struct Server {
1333 /// host: String,
1334 /// port: i32,
1335 /// }
1336 ///
1337 /// let mut config = Config::new();
1338 /// config.set("server.host", "localhost").unwrap();
1339 /// config.set("server.port", 8080).unwrap();
1340 ///
1341 /// let server: Server = config.deserialize("server").unwrap();
1342 /// assert_eq!(server.host, "localhost");
1343 /// assert_eq!(server.port, 8080);
1344 /// ```
1345 pub fn deserialize<T>(&self, prefix: &str) -> ConfigResult<T>
1346 where
1347 T: DeserializeOwned,
1348 {
1349 let sub = self.subconfig(prefix, true)?;
1350
1351 let mut properties = sub.properties.iter().collect::<Vec<_>>();
1352 properties.sort_by_key(|(left_key, _)| *left_key);
1353
1354 let mut map = Map::new();
1355 for (key, prop) in properties {
1356 let mut json_val = utils::property_to_json_value(prop);
1357 utils::substitute_json_strings_with_fallback(&mut json_val, &sub, self)?;
1358 utils::insert_deserialize_value(&mut map, key, json_val);
1359 }
1360
1361 let json_obj = Value::Object(map);
1362
1363 from_value(json_obj).map_err(|e| ConfigError::DeserializeError {
1364 path: prefix.to_string(),
1365 message: e.to_string(),
1366 })
1367 }
1368
1369 /// Inserts or replaces a property using an explicit [`Property`] object.
1370 ///
1371 /// This method enforces two invariants:
1372 ///
1373 /// - `name` must exactly match `property.name()`
1374 /// - existing final properties cannot be overridden
1375 ///
1376 /// # Parameters
1377 ///
1378 /// * `name` - Target key in this config.
1379 /// * `property` - Property to store under `name`.
1380 ///
1381 /// # Returns
1382 ///
1383 /// `Ok(())` on success.
1384 ///
1385 /// # Errors
1386 ///
1387 /// - [`ConfigError::MergeError`] when `name` and `property.name()` differ.
1388 /// - [`ConfigError::PropertyIsFinal`] when trying to override a final
1389 /// property.
1390 pub fn insert_property(&mut self, name: &str, property: Property) -> ConfigResult<()> {
1391 if property.name() != name {
1392 return Err(ConfigError::MergeError(format!(
1393 "Property name mismatch: key '{name}' != property '{}'",
1394 property.name()
1395 )));
1396 }
1397 self.ensure_property_not_final(name)?;
1398 self.properties.insert(name.to_string(), property);
1399 Ok(())
1400 }
1401
1402 /// Sets a key to a typed null/empty value.
1403 ///
1404 /// This is the preferred public API for representing null/empty values
1405 /// without exposing raw mutable access to the internal map.
1406 ///
1407 /// # Parameters
1408 ///
1409 /// * `name` - Configuration item name.
1410 /// * `data_type` - Data type metadata for the empty value.
1411 ///
1412 /// # Returns
1413 ///
1414 /// `Ok(())` on success.
1415 ///
1416 /// # Errors
1417 ///
1418 /// - [`ConfigError::PropertyIsFinal`] when trying to override a final
1419 /// property.
1420 #[inline]
1421 pub fn set_null(&mut self, name: &str, data_type: DataType) -> ConfigResult<()> {
1422 self.insert_property(
1423 name,
1424 Property::with_value(name, MultiValues::Empty(data_type)),
1425 )
1426 }
1427}
1428
1429impl ConfigReader for Config {
1430 #[inline]
1431 fn is_enable_variable_substitution(&self) -> bool {
1432 Config::is_enable_variable_substitution(self)
1433 }
1434
1435 #[inline]
1436 fn max_substitution_depth(&self) -> usize {
1437 Config::max_substitution_depth(self)
1438 }
1439
1440 #[inline]
1441 fn description(&self) -> Option<&str> {
1442 Config::description(self)
1443 }
1444
1445 #[inline]
1446 fn get_property(&self, name: &str) -> Option<&Property> {
1447 Config::get_property(self, name)
1448 }
1449
1450 #[inline]
1451 fn len(&self) -> usize {
1452 Config::len(self)
1453 }
1454
1455 #[inline]
1456 fn is_empty(&self) -> bool {
1457 Config::is_empty(self)
1458 }
1459
1460 #[inline]
1461 fn keys(&self) -> Vec<String> {
1462 Config::keys(self)
1463 }
1464
1465 #[inline]
1466 fn contains(&self, name: &str) -> bool {
1467 Config::contains(self, name)
1468 }
1469
1470 #[inline]
1471 fn get<T>(&self, name: &str) -> ConfigResult<T>
1472 where
1473 MultiValues: MultiValuesFirstGetter<T>,
1474 {
1475 Config::get(self, name)
1476 }
1477
1478 #[inline]
1479 fn get_list<T>(&self, name: &str) -> ConfigResult<Vec<T>>
1480 where
1481 MultiValues: MultiValuesGetter<T>,
1482 {
1483 Config::get_list(self, name)
1484 }
1485
1486 #[inline]
1487 fn get_optional<T>(&self, name: &str) -> ConfigResult<Option<T>>
1488 where
1489 MultiValues: MultiValuesFirstGetter<T>,
1490 {
1491 Config::get_optional(self, name)
1492 }
1493
1494 #[inline]
1495 fn get_optional_list<T>(&self, name: &str) -> ConfigResult<Option<Vec<T>>>
1496 where
1497 MultiValues: MultiValuesGetter<T>,
1498 {
1499 Config::get_optional_list(self, name)
1500 }
1501
1502 #[inline]
1503 fn contains_prefix(&self, prefix: &str) -> bool {
1504 Config::contains_prefix(self, prefix)
1505 }
1506
1507 #[inline]
1508 fn iter_prefix<'a>(
1509 &'a self,
1510 prefix: &'a str,
1511 ) -> Box<dyn Iterator<Item = (&'a str, &'a Property)> + 'a> {
1512 Box::new(Config::iter_prefix(self, prefix))
1513 }
1514
1515 #[inline]
1516 fn iter<'a>(&'a self) -> Box<dyn Iterator<Item = (&'a str, &'a Property)> + 'a> {
1517 Box::new(Config::iter(self))
1518 }
1519
1520 #[inline]
1521 fn is_null(&self, name: &str) -> bool {
1522 Config::is_null(self, name)
1523 }
1524
1525 #[inline]
1526 fn subconfig(&self, prefix: &str, strip_prefix: bool) -> ConfigResult<Config> {
1527 Config::subconfig(self, prefix, strip_prefix)
1528 }
1529
1530 #[inline]
1531 fn deserialize<T>(&self, prefix: &str) -> ConfigResult<T>
1532 where
1533 T: DeserializeOwned,
1534 {
1535 Config::deserialize(self, prefix)
1536 }
1537
1538 #[inline]
1539 fn prefix_view(&self, prefix: &str) -> ConfigPrefixView<'_> {
1540 Config::prefix_view(self, prefix)
1541 }
1542}
1543
1544impl Default for Config {
1545 /// Creates a new default configuration
1546 ///
1547 /// # Returns
1548 ///
1549 /// Returns a new configuration instance
1550 ///
1551 /// # Examples
1552 ///
1553 /// ```rust
1554 /// use qubit_config::Config;
1555 ///
1556 /// let config = Config::default();
1557 /// assert!(config.is_empty());
1558 /// ```
1559 #[inline]
1560 fn default() -> Self {
1561 Self::new()
1562 }
1563}