Skip to main content

config/
configuration.rs

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