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}