Skip to main content

qubit_config/source/
composite_config_source.rs

1/*******************************************************************************
2 *
3 *    Copyright (c) 2025 - 2026.
4 *    Haixing Hu, Qubit Co. Ltd.
5 *
6 *    All rights reserved.
7 *
8 ******************************************************************************/
9//! # Composite Configuration Source
10//!
11//! Merges configuration from multiple sources in order.
12//!
13//! Sources are applied in the order they are added. Later sources override
14//! earlier sources for the same key (unless the property is marked as final).
15//!
16//! # Examples
17//!
18//! ```rust,ignore
19//! use qubit_config::source::{
20//!     CompositeConfigSource, ConfigSource, EnvConfigSource, TomlConfigSource,
21//! };
22//! use qubit_config::Config;
23//!
24//! let mut composite = CompositeConfigSource::new();
25//! composite.add(TomlConfigSource::from_file("defaults.toml"));
26//! composite.add(TomlConfigSource::from_file("config.toml"));
27//! composite.add(EnvConfigSource::with_prefix("APP_"));
28//!
29//! let mut config = Config::new();
30//! composite.load(&mut config).unwrap();
31//! ```
32//!
33//! # Author
34//!
35//! Haixing Hu
36
37use crate::{Config, ConfigResult};
38
39use super::ConfigSource;
40
41/// Configuration source that merges multiple sources in order
42///
43/// # Author
44///
45/// Haixing Hu
46pub struct CompositeConfigSource {
47    sources: Vec<Box<dyn ConfigSource>>,
48}
49
50impl CompositeConfigSource {
51    /// Creates a new empty `CompositeConfigSource`.
52    ///
53    /// # Returns
54    ///
55    /// An empty composite with no inner sources.
56    #[inline]
57    pub fn new() -> Self {
58        Self {
59            sources: Vec::new(),
60        }
61    }
62
63    /// Adds a configuration source
64    ///
65    /// Sources are applied in the order they are added. Later sources override
66    /// earlier sources for the same key.
67    ///
68    /// # Parameters
69    ///
70    /// * `source` - The configuration source to add
71    ///
72    /// # Returns
73    ///
74    /// `self` for method chaining.
75    #[inline]
76    pub fn add<S: ConfigSource + 'static>(&mut self, source: S) -> &mut Self {
77        self.sources.push(Box::new(source));
78        self
79    }
80
81    /// Returns the number of sources in this composite.
82    ///
83    /// # Returns
84    ///
85    /// The length of the internal source list.
86    #[inline]
87    pub fn len(&self) -> usize {
88        self.sources.len()
89    }
90
91    /// Returns `true` if this composite has no sources.
92    ///
93    /// # Returns
94    ///
95    /// `true` when [`Self::len`] is zero.
96    #[inline]
97    pub fn is_empty(&self) -> bool {
98        self.sources.is_empty()
99    }
100}
101
102impl Default for CompositeConfigSource {
103    #[inline]
104    fn default() -> Self {
105        Self::new()
106    }
107}
108
109impl ConfigSource for CompositeConfigSource {
110    fn load(&self, config: &mut Config) -> ConfigResult<()> {
111        for source in &self.sources {
112            source.load(config)?;
113        }
114        Ok(())
115    }
116}