rskit_config/source/
env.rs1use rskit_errors::{AppError, AppResult};
2
3use super::contract::ConfigSource;
4
5#[derive(Debug, Clone, Default)]
7pub struct EnvironmentSource {
8 prefix: String,
9}
10
11impl EnvironmentSource {
12 pub fn new() -> Self {
14 Self::default()
15 }
16
17 pub fn with_prefix(prefix: impl Into<String>) -> Self {
19 Self {
20 prefix: prefix.into(),
21 }
22 }
23}
24
25impl ConfigSource for EnvironmentSource {
26 fn collect(&self) -> AppResult<config::Config> {
27 let env_source = if self.prefix.is_empty() {
28 config::Environment::default()
29 .separator("__")
30 .try_parsing(true)
31 } else {
32 config::Environment::with_prefix(&self.prefix)
33 .separator("__")
34 .try_parsing(true)
35 };
36
37 config::Config::builder()
38 .add_source(env_source)
39 .build()
40 .map_err(|e| AppError::invalid_input("config", e.to_string()))
41 }
42}
43
44pub(crate) fn normalize_env_key(prefix: &str, key: &str) -> Option<String> {
45 let key = key.to_ascii_lowercase();
46 if prefix.is_empty() {
47 return Some(key.replace("__", "."));
48 }
49
50 let prefix = prefix.to_ascii_lowercase();
51 key.strip_prefix(&format!("{prefix}__"))
52 .map(|stripped| stripped.replace("__", "."))
53}
54
55pub(crate) fn parse_env_value(value: String) -> config::Value {
56 if let Ok(value) = value.parse::<bool>() {
57 return value.into();
58 }
59 if let Ok(value) = value.parse::<i64>() {
60 return value.into();
61 }
62 if let Ok(value) = value.parse::<f64>() {
63 return value.into();
64 }
65 value.into()
66}
67
68#[cfg(test)]
69mod tests {
70 use super::*;
71
72 #[test]
73 fn normalize_env_key_handles_prefixes_and_nested_keys() {
74 assert_eq!(
75 normalize_env_key("", "SERVICE__PORT").as_deref(),
76 Some("service.port")
77 );
78 assert_eq!(
79 normalize_env_key("APP", "APP__SERVICE__DEBUG").as_deref(),
80 Some("service.debug")
81 );
82 assert_eq!(normalize_env_key("APP", "OTHER__VALUE"), None);
83 }
84
85 #[test]
86 fn parse_env_value_preserves_basic_types() {
87 assert!(parse_env_value("true".to_string()).into_bool().unwrap());
88 assert_eq!(parse_env_value("42".to_string()).into_int().unwrap(), 42);
89 assert_eq!(
90 parse_env_value("1.5".to_string()).into_float().unwrap(),
91 1.5
92 );
93 assert_eq!(
94 parse_env_value("plain".to_string()).into_string().unwrap(),
95 "plain"
96 );
97 }
98}