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}