config/
configuration.rs

1use crate::{ConfigurationPath, ConfigurationSection, Value};
2use cfg_if::cfg_if;
3use tokens::ChangeToken;
4
5cfg_if! {
6    if #[cfg(feature = "async")] {
7        /// Defines the behavior of a configuration.
8        pub trait Configuration: Send + Sync {
9            /// Gets the configuration value.
10            ///
11            /// # Arguments
12            ///
13            /// * `key` - The configuration key
14            fn get(&self, key: &str) -> Option<Value>;
15
16            /// Gets a [`ConfigurationSection`](crate::ConfigurationSection) with the specified key.
17            fn section(&self, key: &str) -> Box<dyn ConfigurationSection>;
18
19            /// Gets the sequence of [`ConfigurationSection`](crate::ConfigurationSection) children.
20            fn children(&self) -> Vec<Box<dyn ConfigurationSection>>;
21
22            /// Returns a [`ChangeToken`](tokens::ChangeToken) that can be used to observe when this configuration is reloaded.
23            fn reload_token(&self) -> Box<dyn ChangeToken>;
24
25            /// Attempts to convert the [`Configuration`] as a [`ConfigurationSection`](crate::ConfigurationSection).
26            fn as_section(&self) -> Option<&dyn ConfigurationSection> {
27                None
28            }
29
30            /// Gets an iterator of the key/value pairs within the [`Configuration`].
31            ///
32            /// # Arguments
33            ///
34            /// * `path` - The type of [`ConfigurationPath`] used when iterating
35            fn iter(&self, path: Option<ConfigurationPath>) -> Box<dyn Iterator<Item = (String, Value)>>;
36        }
37    } else {
38        /// Defines the behavior of a configuration.
39        pub trait Configuration {
40            /// Gets the configuration value.
41            ///
42            /// # Arguments
43            ///
44            /// * `key` - The configuration key
45            fn get(&self, key: &str) -> Option<Value>;
46
47            /// Gets a [`ConfigurationSection`](crate::ConfigurationSection) with the specified key.
48            fn section(&self, key: &str) -> Box<dyn ConfigurationSection>;
49
50            /// Gets the sequence of [`ConfigurationSection`](crate::ConfigurationSection) children.
51            fn children(&self) -> Vec<Box<dyn ConfigurationSection>>;
52
53            /// Returns a [`ChangeToken`](tokens::ChangeToken) that can be used to observe when this configuration is reloaded.
54            fn reload_token(&self) -> Box<dyn ChangeToken>;
55
56            /// Attempts to convert the [`Configuration`] as a [`ConfigurationSection`](crate::ConfigurationSection).
57            fn as_section(&self) -> Option<&dyn ConfigurationSection> {
58                None
59            }
60
61            /// Gets an iterator of the key/value pairs within the [`Configuration`].
62            ///
63            /// # Arguments
64            ///
65            /// * `path` - The type of [`ConfigurationPath`] used when iterating
66            fn iter(&self, path: Option<ConfigurationPath>) -> Box<dyn Iterator<Item = (String, Value)>>;
67        }
68    }
69}
70
71/// Represents an iterator of key/value pairs for a [`Configuration`].
72pub struct ConfigurationIterator {
73    stack: Vec<Box<dyn ConfigurationSection>>,
74    first: Option<(String, Value)>,
75    prefix_length: usize,
76}
77
78impl ConfigurationIterator {
79    /// Initializes a new configuration iterator.
80    ///
81    /// # Arguments
82    ///
83    /// * `configuration` - The [`Configuration`] to iterate
84    /// * `path` - The type of [`ConfigurationPath`] used when iterating
85    pub fn new(configuration: &dyn Configuration, path: ConfigurationPath) -> Self {
86        let stack = configuration.children();
87        let mut first = None;
88        let mut prefix_length = 0;
89
90        if let Some(root) = configuration.as_section() {
91            if path == ConfigurationPath::Relative {
92                prefix_length = root.path().len() + 1;
93            } else {
94                let key = root.path()[prefix_length..].to_owned();
95                let value = root.value();
96
97                first = Some((key, value));
98            }
99        }
100
101        Self {
102            stack,
103            first,
104            prefix_length,
105        }
106    }
107}
108
109impl Iterator for ConfigurationIterator {
110    type Item = (String, Value);
111
112    fn next(&mut self) -> Option<Self::Item> {
113        if let Some(first) = self.first.take() {
114            return Some(first);
115        }
116
117        while let Some(config) = self.stack.pop() {
118            self.stack.extend(config.children().into_iter());
119
120            if let Some(section) = config.as_section() {
121                let key = section.path()[self.prefix_length..].to_owned();
122                let value = section.value();
123                return Some((key, value));
124            }
125        }
126
127        None
128    }
129}