Skip to main content

qubit_config/
configurable.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 ******************************************************************************/
10//! # Configurable Interface
11//!
12//! Provides the `Configurable` trait for types to have unified configuration
13//! access and change callback interfaces.
14//!
15
16use super::{
17    Config,
18    ConfigResult,
19};
20
21/// Configurable trait
22///
23/// Types that implement this trait can be configured using `Config`.
24///
25/// # Examples
26///
27/// ```rust
28/// use qubit_config::{Config, Configurable};
29///
30/// struct Server { config: Config }
31///
32/// impl Configurable for Server {
33///     fn config(&self) -> &Config {
34///         &self.config
35///     }
36///     fn config_mut(&mut self) -> &mut Config {
37///         &mut self.config
38///     }
39///     fn set_config(&mut self, config: Config) {
40///         self.config = config;
41///         self.on_config_changed();
42///     }
43/// }
44/// ```
45///
46/// ```rust
47/// use qubit_config::{ConfigResult, ConfigError};
48/// ```
49///
50pub trait Configurable {
51    /// Gets a reference to the configuration
52    ///
53    /// # Returns
54    ///
55    /// Returns an immutable reference to the configuration
56    ///
57    fn config(&self) -> &Config;
58
59    /// Gets a mutable reference to the configuration.
60    ///
61    /// Direct mutations through this reference do not automatically call
62    /// [`Self::on_config_changed`]. Use [`Self::update_config`] when a mutation
63    /// should trigger the callback once after a successful update.
64    ///
65    /// # Returns
66    ///
67    /// Returns a mutable reference to the configuration
68    ///
69    fn config_mut(&mut self) -> &mut Config;
70
71    /// Sets the configuration
72    ///
73    /// # Parameters
74    ///
75    /// * `config` - The new configuration
76    ///
77    /// # Returns
78    ///
79    /// Nothing.
80    ///
81    fn set_config(&mut self, config: Config);
82
83    /// Updates a staged copy of the configuration through a closure.
84    ///
85    /// The closure receives a cloned configuration. The staged copy is
86    /// committed to [`Self::config_mut`] only after the closure returns
87    /// `Ok(())`. The callback is then called exactly once. If the closure
88    /// returns an error, the original configuration is left unchanged and the
89    /// callback is not called.
90    ///
91    /// # Parameters
92    ///
93    /// * `update` - Closure that mutates the configuration.
94    ///
95    /// # Returns
96    ///
97    /// Returns `Ok(())` when the update succeeds.
98    ///
99    /// # Errors
100    ///
101    /// Returns the [`crate::ConfigError`] produced by the closure.
102    fn update_config<F>(&mut self, update: F) -> ConfigResult<()>
103    where
104        Self: Sized,
105        F: FnOnce(&mut Config) -> ConfigResult<()>,
106    {
107        let mut staged = self.config().clone();
108        update(&mut staged)?;
109        *self.config_mut() = staged;
110        self.on_config_changed();
111        Ok(())
112    }
113
114    /// Callback after configuration replacement or controlled updates.
115    ///
116    /// This method is called by [`Self::set_config`] implementations and by
117    /// the default [`Self::update_config`] helper. Direct mutations through
118    /// [`Self::config_mut`] are intentionally not observed.
119    ///
120    /// # Returns
121    ///
122    /// Nothing.
123    ///
124    #[inline]
125    fn on_config_changed(&mut self) {
126        // Default implementation is empty
127    }
128}