Skip to main content

dynamo_config/
lib.rs

1// SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Configuration utilities and trait re-exports.
5//!
6//! This module provides utility functions for parsing configuration values
7//! and re-exports the core configuration traits from the integrations module.
8
9// ===== Environment Variable Utilities =====
10
11/// Check if a string is truthy.
12///
13/// This will be used to evaluate environment variables or any other subjective
14/// configuration parameters that can be set by the user that should be evaluated
15/// as a boolean value.
16///
17/// Truthy values: "1", "true", "on", "yes" (case-insensitive)
18///
19/// Returns `false` for invalid values. Use [`parse_bool`] if you need to error on invalid values.
20pub fn is_truthy(val: &str) -> bool {
21    matches!(val.to_lowercase().as_str(), "1" | "true" | "on" | "yes")
22}
23
24/// Check if a string is falsey.
25///
26/// This will be used to evaluate environment variables or any other subjective
27/// configuration parameters that can be set by the user that should be evaluated
28/// as a boolean value (opposite of is_truthy).
29///
30/// Falsey values: "0", "false", "off", "no" (case-insensitive)
31///
32/// Returns `false` for invalid values. Use [`parse_bool`] if you need to error on invalid values.
33pub fn is_falsey(val: &str) -> bool {
34    matches!(val.to_lowercase().as_str(), "0" | "false" | "off" | "no")
35}
36
37/// Parse a string as a boolean value, returning an error if invalid.
38///
39/// This function strictly validates that the input is a valid boolean representation.
40///
41/// # Arguments
42/// * `val` - The string value to parse
43///
44/// # Returns
45/// * `Ok(true)` - For truthy values: "1", "true", "on", "yes" (case-insensitive)
46/// * `Ok(false)` - For falsey values: "0", "false", "off", "no" (case-insensitive)
47/// * `Err(_)` - For any other value
48///
49/// # Example
50/// ```ignore
51/// assert_eq!(parse_bool("true")?, true);
52/// assert_eq!(parse_bool("0")?, false);
53/// assert!(parse_bool("maybe").is_err());
54/// ```
55pub fn parse_bool(val: &str) -> anyhow::Result<bool> {
56    if is_truthy(val) {
57        Ok(true)
58    } else if is_falsey(val) {
59        Ok(false)
60    } else {
61        anyhow::bail!(
62            "Invalid boolean value: '{}'. Expected one of: true/false, 1/0, on/off, yes/no",
63            val
64        )
65    }
66}
67
68/// Check if an environment variable is truthy.
69///
70/// Returns `false` if the environment variable is not set or is invalid.
71/// Use [`env_parse_bool`] if you need to distinguish between unset, valid, and invalid values.
72pub fn env_is_truthy(env: &str) -> bool {
73    match std::env::var(env) {
74        Ok(val) => is_truthy(val.as_str()),
75        Err(_) => false,
76    }
77}
78
79/// Check if an environment variable is falsey.
80///
81/// Returns `false` if the environment variable is not set or is invalid.
82/// Use [`env_parse_bool`] if you need to distinguish between unset, valid, and invalid values.
83pub fn env_is_falsey(env: &str) -> bool {
84    match std::env::var(env) {
85        Ok(val) => is_falsey(val.as_str()),
86        Err(_) => false,
87    }
88}
89
90/// Parse an environment variable as a boolean, returning an error if invalid.
91///
92/// # Arguments
93/// * `env` - The environment variable name
94///
95/// # Returns
96/// * `Ok(Some(true))` - If the env var is set to a truthy value
97/// * `Ok(Some(false))` - If the env var is set to a falsey value
98/// * `Ok(None)` - If the env var is not set
99/// * `Err(_)` - If the env var is set to an invalid value
100///
101/// # Example
102/// ```ignore
103/// match env_parse_bool("MY_FLAG")? {
104///     Some(true) => println!("enabled"),
105///     Some(false) => println!("disabled"),
106///     None => println!("not configured"),
107/// }
108/// ```
109pub fn env_parse_bool(env: &str) -> anyhow::Result<Option<bool>> {
110    match std::env::var(env) {
111        Ok(val) => parse_bool(&val).map(Some),
112        Err(std::env::VarError::NotPresent) => Ok(None),
113        Err(e) => anyhow::bail!("Failed to read environment variable {}: {}", env, e),
114    }
115}
116
117#[cfg(test)]
118mod tests {
119    use super::*;
120
121    #[test]
122    fn test_is_truthy() {
123        assert!(is_truthy("1"));
124        assert!(is_truthy("true"));
125        assert!(is_truthy("True"));
126        assert!(is_truthy("TRUE"));
127        assert!(is_truthy("on"));
128        assert!(is_truthy("ON"));
129        assert!(is_truthy("yes"));
130        assert!(is_truthy("YES"));
131
132        assert!(!is_truthy("0"));
133        assert!(!is_truthy("false"));
134        assert!(!is_truthy("off"));
135        assert!(!is_truthy("no"));
136        assert!(!is_truthy(""));
137        assert!(!is_truthy("random"));
138    }
139
140    #[test]
141    fn test_is_falsey() {
142        assert!(is_falsey("0"));
143        assert!(is_falsey("false"));
144        assert!(is_falsey("False"));
145        assert!(is_falsey("FALSE"));
146        assert!(is_falsey("off"));
147        assert!(is_falsey("OFF"));
148        assert!(is_falsey("no"));
149        assert!(is_falsey("NO"));
150
151        assert!(!is_falsey("1"));
152        assert!(!is_falsey("true"));
153        assert!(!is_falsey("on"));
154        assert!(!is_falsey("yes"));
155        assert!(!is_falsey(""));
156        assert!(!is_falsey("random"));
157    }
158
159    #[test]
160    fn test_env_is_truthy_not_set() {
161        // Test with a variable that definitely doesn't exist
162        assert!(!env_is_truthy("DEFINITELY_NOT_SET_VAR_12345"));
163    }
164
165    #[test]
166    fn test_env_is_falsey_not_set() {
167        // Test with a variable that definitely doesn't exist
168        assert!(!env_is_falsey("DEFINITELY_NOT_SET_VAR_12345"));
169    }
170
171    #[test]
172    fn test_parse_bool() {
173        // Truthy values
174        assert!(parse_bool("1").unwrap());
175        assert!(parse_bool("true").unwrap());
176        assert!(parse_bool("TRUE").unwrap());
177        assert!(parse_bool("on").unwrap());
178        assert!(parse_bool("yes").unwrap());
179
180        // Falsey values
181        assert!(!parse_bool("0").unwrap());
182        assert!(!parse_bool("false").unwrap());
183        assert!(!parse_bool("FALSE").unwrap());
184        assert!(!parse_bool("off").unwrap());
185        assert!(!parse_bool("no").unwrap());
186
187        // Invalid values
188        assert!(parse_bool("").is_err());
189        assert!(parse_bool("maybe").is_err());
190        assert!(parse_bool("2").is_err());
191        assert!(parse_bool("random").is_err());
192    }
193
194    #[test]
195    fn test_env_parse_bool_not_set() {
196        // Test with a variable that definitely doesn't exist
197        assert_eq!(
198            env_parse_bool("DEFINITELY_NOT_SET_VAR_12345").unwrap(),
199            None
200        );
201    }
202}