1use std::path::Path;
2
3use serde::Deserialize;
4
5use super::ConfigError;
6
7#[derive(Debug, Clone)]
9pub struct RuestConfig {
10 inner: config::Config,
11}
12
13impl RuestConfig {
14 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 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 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
52pub fn get<T: for<'de> Deserialize<'de>>(key: &str) -> Result<T, ConfigError> {
54 RuestConfig::load(None)?.get(key)
55}