/// Environment detection — which deployment context are we in? /// The current deployment environment. #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] pub enum Environment { /// Local developer machine. Verbose errors, hot reload, relaxed auth. Development, /// Pre-production environment. Production build, test data. Staging, /// Live production. Minimal logging, strict auth, performance mode. Production, } impl Environment { /// Detect from the `EL_ENV` environment variable (or `APP_ENV`, `RUST_ENV`). /// /// Falls back to Development if unset or unrecognized. pub fn current() -> Self { let val = std::env::var("EL_ENV") .or_else(|_| std::env::var("APP_ENV")) .or_else(|_| std::env::var("RUST_ENV")) .unwrap_or_default(); Self::from_str(&val) } /// Parse from a string. pub fn from_str(s: &str) -> Self { match s.to_lowercase().as_str() { "production" | "prod" => Environment::Production, "staging" | "stage" => Environment::Staging, _ => Environment::Development, } } /// The canonical name for this environment. pub fn name(&self) -> &'static str { match self { Environment::Development => "development", Environment::Staging => "staging", Environment::Production => "production", } } /// Whether this is a production environment. pub fn is_production(&self) -> bool { matches!(self, Environment::Production) } /// Whether this is a development environment. pub fn is_development(&self) -> bool { matches!(self, Environment::Development) } /// Whether debug features should be enabled. pub fn debug_enabled(&self) -> bool { !self.is_production() } } impl std::fmt::Display for Environment { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "{}", self.name()) } } #[cfg(test)] mod tests { use super::*; #[test] fn parse_production() { assert_eq!(Environment::from_str("production"), Environment::Production); assert_eq!(Environment::from_str("prod"), Environment::Production); assert_eq!(Environment::from_str("PRODUCTION"), Environment::Production); } #[test] fn parse_staging() { assert_eq!(Environment::from_str("staging"), Environment::Staging); assert_eq!(Environment::from_str("stage"), Environment::Staging); } #[test] fn parse_development_fallback() { assert_eq!(Environment::from_str("dev"), Environment::Development); assert_eq!(Environment::from_str(""), Environment::Development); assert_eq!(Environment::from_str("unknown"), Environment::Development); } #[test] fn production_is_production() { assert!(Environment::Production.is_production()); assert!(!Environment::Development.is_production()); } #[test] fn development_debug_enabled() { assert!(Environment::Development.debug_enabled()); assert!(!Environment::Production.debug_enabled()); } #[test] fn environment_name() { assert_eq!(Environment::Production.name(), "production"); assert_eq!(Environment::Staging.name(), "staging"); assert_eq!(Environment::Development.name(), "development"); } #[test] fn display() { assert_eq!(format!("{}", Environment::Production), "production"); } }