1#![warn(missing_docs)]
7
8use figment::{
9 Figment,
10 providers::{Env, Format, Toml, Yaml},
11};
12use serde::de::DeserializeOwned;
13use wae_types::{WaeError, WaeResult};
14
15pub struct ConfigLoader {
20 figment: Figment,
21}
22
23impl Default for ConfigLoader {
24 fn default() -> Self {
25 Self::new()
26 }
27}
28
29impl ConfigLoader {
30 pub fn new() -> Self {
32 Self { figment: Figment::new() }
33 }
34
35 pub fn with_toml(mut self, path: &str) -> Self {
40 self.figment = self.figment.merge(Toml::file(path));
41 self
42 }
43
44 pub fn with_yaml(mut self, path: &str) -> Self {
49 self.figment = self.figment.merge(Yaml::file(path));
50 self
51 }
52
53 pub fn with_env(mut self, prefix: &str) -> Self {
58 self.figment = self.figment.merge(Env::prefixed(prefix));
59 self
60 }
61
62 pub fn with_env_separator(mut self, prefix: &str, separator: &str) -> Self {
68 self.figment = self.figment.merge(Env::prefixed(prefix).split(separator));
69 self
70 }
71
72 pub fn with_defaults<T: serde::Serialize>(mut self, defaults: &T) -> Self {
77 self.figment = self.figment.merge(figment::providers::Serialized::defaults(defaults));
78 self
79 }
80
81 pub fn extract<T: DeserializeOwned>(self) -> WaeResult<T> {
86 self.figment.extract().map_err(|e| {
87 let msg = e.to_string();
88 if msg.contains("missing field") { WaeError::config_missing(msg) } else { WaeError::config_invalid("config", msg) }
89 })
90 }
91
92 pub fn extract_with_context<T: DeserializeOwned>(self, context: &str) -> WaeResult<T> {
98 self.extract().map_err(|e| WaeError::internal(format!("{}: {}", context, e)))
99 }
100}
101
102pub fn load_config<T: DeserializeOwned>(config_path: &str, env_prefix: &str) -> WaeResult<T> {
113 ConfigLoader::new().with_toml(config_path).with_env(env_prefix).extract()
114}
115
116pub fn from_env<T: DeserializeOwned>(prefix: &str) -> WaeResult<T> {
124 ConfigLoader::new().with_env(prefix).extract()
125}