qubit_config/source/config_source.rs
1/*******************************************************************************
2 *
3 * Copyright (c) 2025 - 2026 Haixing Hu.
4 *
5 * SPDX-License-Identifier: Apache-2.0
6 *
7 * Licensed under the Apache License, Version 2.0.
8 *
9 ******************************************************************************/
10use crate::{
11 Config,
12 ConfigResult,
13};
14
15/// Trait for configuration sources
16///
17/// Implementors of this trait can load configuration data and populate a
18/// [`Config`] object.
19///
20/// # Examples
21///
22/// ```rust
23/// use qubit_config::{Config, source::ConfigSource};
24///
25/// struct MySource;
26///
27/// impl ConfigSource for MySource {
28/// fn load(&self, config: &mut Config) -> qubit_config::ConfigResult<()> {
29/// config.set("key", "value")?;
30/// Ok(())
31/// }
32/// }
33/// ```
34///
35pub trait ConfigSource {
36 /// Loads configuration data into the provided `Config` object
37 ///
38 /// # Parameters
39 ///
40 /// * `config` - The configuration object to populate
41 ///
42 /// # Returns
43 ///
44 /// Returns `Ok(())` on success, or a `ConfigError` on failure
45 fn load(&self, config: &mut Config) -> ConfigResult<()>;
46
47 /// Loads configuration data into an already-staged `Config` object.
48 ///
49 /// Built-in sources override this method to avoid cloning when the caller
50 /// has already staged a transaction. Custom implementations can rely on
51 /// the default, which delegates to [`Self::load`].
52 ///
53 /// # Parameters
54 ///
55 /// * `config` - The staged configuration object to populate
56 ///
57 /// # Returns
58 ///
59 /// Returns `Ok(())` on success, or a `ConfigError` on failure
60 #[inline]
61 fn load_into(&self, config: &mut Config) -> ConfigResult<()> {
62 self.load(config)
63 }
64}
65
66/// Runs a source load against a cloned config and commits only on success.
67///
68/// # Parameters
69///
70/// * `source` - Source whose non-transactional loader should be staged.
71/// * `config` - Target configuration to update atomically.
72///
73/// # Returns
74///
75/// Returns `Ok(())` after committing the staged config, or propagates the
76/// source error while leaving `config` unchanged.
77pub(crate) fn load_transactionally<S>(source: &S, config: &mut Config) -> ConfigResult<()>
78where
79 S: ConfigSource + ?Sized,
80{
81 let mut staged = config.clone();
82 source.load_into(&mut staged)?;
83 *config = staged;
84 Ok(())
85}