Skip to main content

river_data_core/
env.rs

1//! Environment variable helpers shared by sync services.
2
3use std::str::FromStr;
4
5/// Read a required variable, with a readable error naming the missing key.
6pub fn require(key: &str) -> Result<String, String> {
7    std::env::var(key).map_err(|_| format!("Missing required env var: {key}"))
8}
9
10/// Read a string variable, falling back to a default when unset.
11pub fn string_or(key: &str, default: &str) -> String {
12    std::env::var(key).unwrap_or_else(|_| default.to_string())
13}
14
15/// Parse a variable into any FromStr type, falling back on unset or unparseable values.
16pub fn parse_or<T: FromStr>(key: &str, default: T) -> T {
17    parse_from(std::env::var(key).ok(), default)
18}
19
20/// Read a boolean variable ("true" or "1"), falling back to a default when unset.
21pub fn bool_or(key: &str, default: bool) -> bool {
22    bool_from(std::env::var(key).ok(), default)
23}
24
25fn parse_from<T: FromStr>(value: Option<String>, default: T) -> T {
26    value.and_then(|v| v.parse().ok()).unwrap_or(default)
27}
28
29fn bool_from(value: Option<String>, default: bool) -> bool {
30    value.map(|v| v == "true" || v == "1").unwrap_or(default)
31}
32
33#[cfg(test)]
34mod tests {
35    use super::*;
36
37    #[test]
38    fn test_require_missing() {
39        let err = require("RIVER_CORE_TEST_UNSET").unwrap_err();
40        assert!(err.contains("RIVER_CORE_TEST_UNSET"));
41    }
42
43    #[test]
44    fn test_string_or_unset() {
45        assert_eq!(string_or("RIVER_CORE_TEST_UNSET", "fallback"), "fallback");
46    }
47
48    #[test]
49    fn test_parse_from_garbage_falls_back() {
50        assert_eq!(parse_from(Some("not-a-number".to_string()), 7u64), 7);
51    }
52
53    #[test]
54    fn test_parse_from_valid() {
55        assert_eq!(parse_from(Some("12".to_string()), 7u64), 12);
56        assert_eq!(parse_from::<i64>(None, 42), 42);
57    }
58
59    #[test]
60    fn test_bool_from() {
61        assert!(bool_from(Some("1".to_string()), false));
62        assert!(bool_from(Some("true".to_string()), false));
63        assert!(!bool_from(Some("no".to_string()), true));
64        assert!(bool_from(None, true));
65    }
66}