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
use std::sync::Arc;
use serde::de::DeserializeOwned;
use thiserror::Error;
use crate::configuration_builder::ConfigurationBuilder;
use crate::configuration_provider::ConfigurationProvider;
use crate::value::{Value, ValueDeserializer};
use crate::value::deserializer::DeserializationError;

pub mod configuration_builder;
pub mod value;
pub mod configuration_provider;

#[derive(Clone, Debug)]
pub struct Configuration {
    value: Arc<Value>,
}

impl Default for Configuration {
    fn default() -> Self {
        Configuration {
            value: Arc::new(Value::None)
        }
    }
}

impl Configuration {
    pub(crate) fn new(value: Value) -> Self {
        Configuration {
            value: Arc::new(value),
        }
    }

    pub fn builder(provider: impl ConfigurationProvider) -> ConfigurationBuilder {
        ConfigurationBuilder::new(provider)
    }

    pub fn get<T: DeserializeOwned>(&self, key: &str) -> Result<T, GetConfigurationError> {
        let value = match self.value.get(key) {
            Some(config) => config,
            None => return Err(GetConfigurationError::MissingValue(key.to_string())),
        };

        T::deserialize(ValueDeserializer(value))
            .map_err(|err| err.with_prefix(key.as_ref()))
            .map_err(|error| GetConfigurationError::FailedToDeserialize {
                error,
                key: key.to_string(),
            })
    }

    pub fn with_override(&self, key: &str, override_value: Value) -> Self {
        let mut value = (*self.value).clone();

        *value.get_mut_or_create(&key) = override_value;

        return Configuration { value: Arc::new(value) };
    }
}

#[derive(Error, Debug)]
pub enum GetConfigurationError {
    #[error("Missing value [key = `{0}`]")]
    MissingValue(String),

    #[error("Failed to deserialize value [key = `{key}`]")]
    FailedToDeserialize {
        #[source]
        error: DeserializationError,
        key: String,
    },
}