Skip to main content

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}