mirror of
https://github.com/darwincereska/envkit.git
synced 2026-06-11 10:23:23 -05:00
feat: initial commit
This commit is contained in:
+10
@@ -0,0 +1,10 @@
|
|||||||
|
/target
|
||||||
|
idea/
|
||||||
|
|
||||||
|
|
||||||
|
# Added by cargo
|
||||||
|
#
|
||||||
|
# already existing elements were commented out
|
||||||
|
|
||||||
|
#/target
|
||||||
|
/.idea/
|
||||||
Generated
+7
@@ -0,0 +1,7 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "envkit"
|
||||||
|
version = "0.1.0"
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
[package]
|
||||||
|
name = "envkit"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
pub enum EnvError {
|
||||||
|
Invalid { key: String, value: String, message: String },
|
||||||
|
MissingVar(String),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl EnvError {
|
||||||
|
pub fn invalid<K, V, M>(key: K, value: V, message: M) -> Self
|
||||||
|
where
|
||||||
|
K: Into<String>,
|
||||||
|
V: Into<String>,
|
||||||
|
M: Into<String>,
|
||||||
|
{
|
||||||
|
Self::Invalid {
|
||||||
|
key: key.into(),
|
||||||
|
value: value.into(),
|
||||||
|
message: message.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn missing<T>(key: T) -> Self
|
||||||
|
where T: Into<String> {
|
||||||
|
Self::MissingVar(key.into())
|
||||||
|
}
|
||||||
|
}
|
||||||
+90
@@ -0,0 +1,90 @@
|
|||||||
|
use crate::error::EnvError;
|
||||||
|
use crate::parser::Number;
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
|
pub mod parser;
|
||||||
|
|
||||||
|
pub trait FromEnv: Sized {
|
||||||
|
fn from_env(value: &str) -> Result<Self, EnvError>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromEnv for bool {
|
||||||
|
fn from_env(value: &str) -> Result<bool, EnvError> {
|
||||||
|
match parser::parse_bool(value) {
|
||||||
|
Ok(value) => Ok(value),
|
||||||
|
Err(e) => Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Number> FromEnv for T {
|
||||||
|
fn from_env(value: &str) -> Result<Self, EnvError> {
|
||||||
|
match parser::parse_number(value) {
|
||||||
|
Ok(value) => Ok(value),
|
||||||
|
Err(e) => Err(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl FromEnv for String {
|
||||||
|
fn from_env(value: &str) -> Result<String, EnvError> {
|
||||||
|
Ok(value.to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct EnvLoader;
|
||||||
|
|
||||||
|
impl EnvLoader {
|
||||||
|
pub fn with_prefix<P: Into<String>>(&self, prefix: P) -> PrefixedEnvLoader {
|
||||||
|
PrefixedEnvLoader {
|
||||||
|
prefix: prefix.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get<T: FromEnv>(&self, key: &str) -> Result<T, EnvError> {
|
||||||
|
let raw = std::env::var(key).map_err(|_| EnvError::missing(key))?;
|
||||||
|
FromEnv::from_env(&raw)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_or<T: FromEnv>(&self, key: &str, default: T) -> T {
|
||||||
|
match self.get(key) {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(_) => default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_opt<T: FromEnv>(&self, key: &str) -> Option<T> {
|
||||||
|
match self.get(key) {
|
||||||
|
Ok(value) => Some(value),
|
||||||
|
Err(_) => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct PrefixedEnvLoader {
|
||||||
|
prefix: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrefixedEnvLoader {
|
||||||
|
fn key(&self, key: &str) -> String {
|
||||||
|
format!("{}{}", self.prefix, key)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get<T: FromEnv>(&self, key: &str) -> Result<T, EnvError> {
|
||||||
|
EnvLoader.get(&self.key(key))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_or<T: FromEnv>(&self, key: &str, default: T) -> T {
|
||||||
|
match self.get(key) {
|
||||||
|
Ok(value) => value,
|
||||||
|
Err(_) => default
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_opt<T: FromEnv>(&self, key: &str) -> Option<T> {
|
||||||
|
match self.get(key) {
|
||||||
|
Ok(value) => Some(value),
|
||||||
|
Err(_) => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,40 @@
|
|||||||
|
use std::fmt::Display;
|
||||||
|
use std::any::type_name;
|
||||||
|
use crate::error::EnvError;
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
pub trait Number: FromStr<Err: Display> {}
|
||||||
|
|
||||||
|
impl Number for i8 {}
|
||||||
|
impl Number for i16 {}
|
||||||
|
impl Number for i32 {}
|
||||||
|
impl Number for i64 {}
|
||||||
|
impl Number for i128 {}
|
||||||
|
impl Number for isize {}
|
||||||
|
impl Number for u8 {}
|
||||||
|
impl Number for u16 {}
|
||||||
|
impl Number for u32 {}
|
||||||
|
impl Number for u64 {}
|
||||||
|
impl Number for u128 {}
|
||||||
|
impl Number for usize {}
|
||||||
|
impl Number for f32 {}
|
||||||
|
impl Number for f64 {}
|
||||||
|
|
||||||
|
pub fn parse_bool(value: &str) -> Result<bool, EnvError> {
|
||||||
|
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) }
|
||||||
|
|
||||||
|
match value.parse::<bool>() {
|
||||||
|
Ok(value) => Ok(value),
|
||||||
|
Err(e) => Err(EnvError::invalid("bool", value, &e.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse_number<T: Number>(value: &str) -> Result<T, EnvError> {
|
||||||
|
match value.parse::<T>() {
|
||||||
|
Ok(value) => Ok(value),
|
||||||
|
Err(e) => Err(EnvError::invalid(type_name::<T>(), value, &e.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod test_errors {
|
||||||
|
use envkit::error::EnvError;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_missing_var() {
|
||||||
|
assert_eq!(EnvError::missing("missing test"), EnvError::MissingVar("missing test".to_string()));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_invalid() {
|
||||||
|
assert_eq!(EnvError::invalid("key", "value", "message"), EnvError::Invalid {
|
||||||
|
key: "key".to_string(),
|
||||||
|
value: "value".to_string(),
|
||||||
|
message: "message".to_string(),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
#[cfg(test)]
|
||||||
|
mod test_parser {
|
||||||
|
use envkit::parser::parse_bool;
|
||||||
|
use envkit::parser::parse_number;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_bool() {
|
||||||
|
assert_eq!(parse_bool("true"), Ok(true));
|
||||||
|
assert_eq!(parse_bool("false"), Ok(false));
|
||||||
|
assert_eq!(parse_bool("1"), Ok(true));
|
||||||
|
assert_eq!(parse_bool("0"), Ok(false));
|
||||||
|
assert_eq!(parse_bool("t"), Ok(true));
|
||||||
|
assert_eq!(parse_bool("f"), Ok(false));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_number() {
|
||||||
|
assert_eq!(parse_number::<i8>("42"), Ok(42_i8));
|
||||||
|
assert_eq!(parse_number::<i16>("42"), Ok(42_i16));
|
||||||
|
assert_eq!(parse_number::<i32>("42"), Ok(42_i32));
|
||||||
|
assert_eq!(parse_number::<i64>("42"), Ok(42_i64));
|
||||||
|
assert_eq!(parse_number::<i128>("42"), Ok(42_i128));
|
||||||
|
assert_eq!(parse_number::<isize>("42"), Ok(42_isize));
|
||||||
|
assert_eq!(parse_number::<u8>("42"), Ok(42_u8));
|
||||||
|
assert_eq!(parse_number::<u16>("42"), Ok(42_u16));
|
||||||
|
assert_eq!(parse_number::<u32>("42"), Ok(42_u32));
|
||||||
|
assert_eq!(parse_number::<u64>("42"), Ok(42_u64));
|
||||||
|
assert_eq!(parse_number::<u128>("42"), Ok(42_u128));
|
||||||
|
assert_eq!(parse_number::<usize>("42"), Ok(42_usize));
|
||||||
|
assert_eq!(parse_number::<f32>("42"), Ok(42_f32));
|
||||||
|
assert_eq!(parse_number::<f64>("42"), Ok(42_f64));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user