From 5743c0b4904a7221b8f78ac5f6e94969f22ad451 Mon Sep 17 00:00:00 2001 From: darwincereska Date: Mon, 8 Jun 2026 05:39:49 -0400 Subject: [PATCH] feat: added support for lists --- Cargo.lock | 2 +- Cargo.toml | 2 +- src/error.rs | 6 +++--- src/lib.rs | 10 ++++++++++ src/parser.rs | 39 ++++++++++++++++++++++++++++++--------- tests/test_parser.rs | 15 +++++++++++++++ 6 files changed, 60 insertions(+), 14 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d04ff0b..24fec1f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,4 +4,4 @@ version = 4 [[package]] name = "envkit" -version = "0.1.1" +version = "0.2.0" diff --git a/Cargo.toml b/Cargo.toml index b6b04a6..56d8ea9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "envkit" -version = "0.1.1" +version = "0.2.0" edition = "2024" authors = ["Darwin Cereska "] description = "A dead-simple env loader" diff --git a/src/error.rs b/src/error.rs index eba25ac..3b00d47 100644 --- a/src/error.rs +++ b/src/error.rs @@ -12,9 +12,9 @@ impl EnvError { /// Creates a new `EnvError::Invalid` with the given key, value, and message. pub fn invalid(key: K, value: V, message: M) -> Self where - K: Into, - V: Into, - M: Into, + K: Into, // The key of the environment variable that was invalid. + V: Into, // The value of the environment variable that was invalid. + M: Into, // A message describing why the value was invalid. { Self::Invalid { key: key.into(), diff --git a/src/lib.rs b/src/lib.rs index 5558d22..fe793b0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -28,6 +28,16 @@ impl FromEnv for T { } } +/// Adds support for loading lists of values from environment variables. +impl FromEnv for Vec { + fn from_env(value: &str) -> Result { + match parser::parse_list(value) { + Ok(value) => Ok(value), + Err(e) => Err(e) + } + } +} + /// Adds support for loading strings from environment variables. impl FromEnv for String { fn from_env(value: &str) -> Result { diff --git a/src/parser.rs b/src/parser.rs index ca40b8d..636fa73 100644 --- a/src/parser.rs +++ b/src/parser.rs @@ -1,5 +1,6 @@ use std::fmt::Display; use std::any::type_name; +use crate::FromEnv; use crate::error::EnvError; use std::str::FromStr; @@ -21,18 +22,24 @@ impl Number for usize {} impl Number for f32 {} impl Number for f64 {} +/// Normalizes a string by trimming whitespace and converting to lowercase. +fn normalize(input: &str) -> String { + input.trim().to_lowercase().to_string() +} + /// Parses a string as a boolean value. pub fn parse_bool(value: &str) -> Result { - if value.to_lowercase() == "t" { return Ok(true) } - if value.to_lowercase() == "f" { return Ok(false) } - if value == "1" { return Ok(true) } - if value == "0" { return Ok(false) } - if value == "yes" { return Ok(true) } - if value == "no" { return Ok(false) } + let normalized = normalize(value); + if normalized == "t" { return Ok(true) } + if normalized == "f" { return Ok(false) } + if normalized == "1" { return Ok(true) } + if normalized == "0" { return Ok(false) } + if normalized == "yes" { return Ok(true) } + if normalized == "no" { return Ok(false) } - match value.parse::() { - Ok(value) => Ok(value), - Err(e) => Err(EnvError::invalid("bool", value, &e.to_string())) + match normalized.parse::() { + Ok(normalized) => Ok(normalized), + Err(e) => Err(EnvError::invalid("bool", normalized, &e.to_string())) } } @@ -43,3 +50,17 @@ pub fn parse_number(value: &str) -> Result { Err(e) => Err(EnvError::invalid(type_name::(), value, &e.to_string())) } } + +/// Parses a comma-separated list of values of the specified type. +pub fn parse_list(value: &str) -> Result, EnvError> { + let items = value.split(',').map(|item| item.trim()); + let mut result = Vec::new(); + for item in items { + match T::from_env(item) { + Ok(value) => result.push(value), + Err(e) => return Err(e) + } + } + + Ok(result) +} \ No newline at end of file diff --git a/tests/test_parser.rs b/tests/test_parser.rs index 427c3e7..67c578f 100644 --- a/tests/test_parser.rs +++ b/tests/test_parser.rs @@ -2,6 +2,7 @@ mod test_parser { use envkit::parser::parse_bool; use envkit::parser::parse_number; + use envkit::parser::parse_list; #[test] /// Tests for the `parse_bool` function. @@ -34,4 +35,18 @@ mod test_parser { assert_eq!(parse_number::("42"), Ok(42_f32)); assert_eq!(parse_number::("42"), Ok(42_f64)); } + + #[test] + /// Tests for the `parse_list` function. + fn test_parse_list() { + let numbers = "1,2,3,4"; + let names = "Alice, Bob, Charlie"; + let bools = "true, false, yes, no"; + let floats = "3.14, 2.718, 1.618"; + + assert_eq!(parse_list::(numbers), Ok(Vec::from([1,2,3,4]))); + assert_eq!(parse_list::(names), Ok(Vec::from(["Alice".to_string(), "Bob".to_string(), "Charlie".to_string()]))); + assert_eq!(parse_list::(bools), Ok(Vec::from([true, false, true, false]))); + assert_eq!(parse_list::(floats), Ok(Vec::from([3.14, 2.718, 1.618]))); + } }