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}