1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use crate::{
    util::cmp_keys, Configuration, ConfigurationBuilder, ConfigurationProvider,
    ConfigurationSource, Value,
};
use std::borrow::Borrow;
use std::rc::Rc;
use tokens::ChangeToken;

/// Represents a chained [`ConfigurationProvider`](crate::ConfigurationProvider).
pub struct ChainedConfigurationProvider {
    configuration: Rc<dyn Configuration>,
}

impl ChainedConfigurationProvider {
    /// Initializes a new chained configuration provider.
    ///
    /// # Arguments
    ///
    /// * `configuration` - The [`Configuration`](crate::Configuration) to chain
    pub fn new(configuration: Rc<dyn Configuration>) -> Self {
        Self { configuration }
    }
}

impl ConfigurationProvider for ChainedConfigurationProvider {
    fn get(&self, key: &str) -> Option<Value> {
        self.configuration.get(key)
    }

    fn reload_token(&self) -> Box<dyn ChangeToken> {
        self.configuration.reload_token()
    }

    fn child_keys(&self, earlier_keys: &mut Vec<String>, parent_path: Option<&str>) {
        if let Some(path) = parent_path {
            earlier_keys.extend(
                self.configuration
                    .section(path)
                    .children()
                    .iter()
                    .map(|c| c.key().to_owned()),
            );
        } else {
            earlier_keys.extend(
                self.configuration
                    .children()
                    .iter()
                    .map(|c| c.key().to_owned()),
            );
        }

        earlier_keys.sort_by(|k1, k2| cmp_keys(k1, k2));
    }
}

/// Represents a chained [`ConfigurationSource`](crate::ConfigurationSource).
pub struct ChainedConfigurationSource {
    configuration: Rc<dyn Configuration>,
}

impl ChainedConfigurationSource {
    /// Initializes a new chained configuration sources.
    ///
    /// # Arguments
    ///
    /// * `configuration` - The [`Configuration`](crate::Configuration) to chain
    pub fn new(configuration: Box<dyn Configuration>) -> Self {
        Self {
            configuration: Rc::from(configuration),
        }
    }

    /// Gets the associated [`Configuration`](crate::Configuration).
    pub fn configuration(&self) -> &dyn Configuration {
        self.configuration.borrow()
    }
}

impl ConfigurationSource for ChainedConfigurationSource {
    fn build(&self, _builder: &dyn ConfigurationBuilder) -> Box<dyn ConfigurationProvider> {
        Box::new(ChainedConfigurationProvider::new(
            self.configuration.clone(),
        ))
    }
}

impl From<Box<dyn Configuration>> for ChainedConfigurationSource {
    fn from(value: Box<dyn Configuration>) -> Self {
        Self::new(value)
    }
}

impl From<Rc<dyn Configuration>> for ChainedConfigurationSource {
    fn from(value: Rc<dyn Configuration>) -> Self {
        Self {
            configuration: value,
        }
    }
}

pub mod ext {

    use super::*;

    /// Defines extension methods for [`ConfigurationBuilder`](crate::ConfigurationBuilder).
    pub trait ChainedBuilderExtensions {
        /// Adds the existing configuration.
        ///
        /// # Arguments
        ///
        /// * `configuration` - The existing [`Configuration`](crate::Configuration) to add
        fn add_configuration(&mut self, configuration: Box<dyn Configuration>) -> &mut Self;
    }

    impl ChainedBuilderExtensions for dyn ConfigurationBuilder {
        fn add_configuration(&mut self, configuration: Box<dyn Configuration>) -> &mut Self {
            self.add(Box::new(ChainedConfigurationSource::new(configuration)));
            self
        }
    }

    impl<T: ConfigurationBuilder> ChainedBuilderExtensions for T {
        fn add_configuration(&mut self, configuration: Box<dyn Configuration>) -> &mut Self {
            self.add(Box::new(ChainedConfigurationSource::new(configuration)));
            self
        }
    }
}