Skip to main content

ruest/config/
settings.rs

1use std::path::Path;
2
3use serde::Deserialize;
4
5use super::ConfigError;
6
7/// Global configuration accessor (env, .env, TOML, YAML, JSON).
8#[derive(Debug, Clone)]
9pub struct RuestConfig {
10    inner: config::Config,
11}
12
13impl RuestConfig {
14    /// Load configuration with optional file path.
15    pub fn load(path: Option<&Path>) -> Result<Self, ConfigError> {
16        let _ = dotenvy::dotenv();
17
18        let mut builder = config::Config::builder().add_source(
19            config::Environment::default()
20                .separator("__")
21                .try_parsing(true),
22        );
23
24        if let Some(path) = path {
25            builder = builder.add_source(config::File::from(path).required(false));
26        }
27
28        let inner = builder.build()?;
29        Ok(Self { inner })
30    }
31
32    /// Get a configuration value by key.
33    pub fn get<T: for<'de> Deserialize<'de>>(&self, key: &str) -> Result<T, ConfigError> {
34        self.inner
35            .get(key)
36            .map_err(|e| ConfigError::Message(e.to_string()))
37    }
38
39    /// Get optional value.
40    pub fn get_optional<T: for<'de> Deserialize<'de>>(
41        &self,
42        key: &str,
43    ) -> Result<Option<T>, ConfigError> {
44        match self.get(key) {
45            Ok(v) => Ok(Some(v)),
46            Err(ConfigError::Message(_)) => Ok(None),
47            Err(e) => Err(e),
48        }
49    }
50}
51
52/// Convenience static-style accessor when a global config is initialized.
53pub fn get<T: for<'de> Deserialize<'de>>(key: &str) -> Result<T, ConfigError> {
54    RuestConfig::load(None)?.get(key)
55}