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}