use std::env;
use crate::error::ConfigError;
pub(crate) fn collect(prefix: &str) -> Result<toml::Table, ConfigError> {
let mut table = toml::Table::new();
for (key_os, value_os) in env::vars_os() {
let Some(key) = key_os.to_str() else {
continue;
};
let Some(rest) = key.strip_prefix(prefix) else {
continue;
};
if rest.is_empty() {
continue;
}
let value = match value_os.into_string() {
Ok(text) => infer(&text),
Err(raw) => {
return Err(ConfigError::EnvVar {
key: key.to_owned(),
source: env::VarError::NotUnicode(raw),
});
}
};
table.insert(rest.to_lowercase(), value);
}
Ok(table)
}
fn infer(raw: &str) -> toml::Value {
if raw == "true" {
return toml::Value::Boolean(true);
}
if raw == "false" {
return toml::Value::Boolean(false);
}
if let Ok(int) = raw.parse::<i64>() {
return toml::Value::Integer(int);
}
if let Ok(float) = raw.parse::<f64>() {
return toml::Value::Float(float);
}
toml::Value::String(raw.to_owned())
}
#[cfg(test)]
mod tests {
#![allow(clippy::unwrap_used, clippy::expect_used)]
use super::*;
#[test]
fn infer_typed_literals() {
assert_eq!(infer("true"), toml::Value::Boolean(true));
assert_eq!(infer("false"), toml::Value::Boolean(false));
assert_eq!(infer("8080"), toml::Value::Integer(8080));
assert_eq!(infer("-3"), toml::Value::Integer(-3));
assert_eq!(infer("0.5"), toml::Value::Float(0.5));
assert_eq!(infer("svc"), toml::Value::String("svc".into()));
assert_eq!(infer(""), toml::Value::String(String::new()));
}
#[test]
fn collect_maps_and_lowercases() {
let marker = "CKIT_TEST_COLLECT_";
env::set_var(format!("{marker}PORT"), "9000");
env::set_var(format!("{marker}name"), "demo");
let table = collect(marker).expect("collect");
assert_eq!(table.get("port"), Some(&toml::Value::Integer(9000)));
assert_eq!(table.get("name"), Some(&toml::Value::String("demo".into())));
assert!(table.get("port").is_some());
env::remove_var(format!("{marker}PORT"));
env::remove_var(format!("{marker}name"));
}
#[test]
fn collect_skips_bare_prefix() {
let marker = "CKIT_TEST_BARE_";
env::set_var(marker, "1");
let table = collect(marker).expect("collect");
assert!(table.is_empty());
env::remove_var(marker);
}
}