Skip to main content

ferro_rs/config/
mod.rs

1//! Configuration module for Ferro framework
2//!
3//! This module provides Laravel-like configuration management including:
4//! - Automatic `.env` file loading with environment-based precedence
5//! - Type-safe configuration structs
6//! - Simple API for accessing config values
7//!
8//! # Example
9//!
10//! ```rust,ignore
11//! use ferro_rs::{Config, ServerConfig};
12//!
13//! // Initialize config (loads .env files)
14//! Config::init(std::path::Path::new("."));
15//!
16//! // Get typed config
17//! let server = Config::get::<ServerConfig>().unwrap();
18//! println!("Server port: {}", server.port);
19//! ```
20
21/// Environment detection and `.env` file loading.
22pub mod env;
23/// Typed configuration providers (app, server, lang).
24pub mod providers;
25/// In-memory configuration repository.
26pub mod repository;
27
28pub use env::{env, env_optional, env_required, load_dotenv, Environment};
29pub use providers::{
30    AppConfig, AppConfigBuilder, LangConfig, LangConfigBuilder, ServerConfig, ServerConfigBuilder,
31};
32
33use std::path::Path;
34
35/// Main Config facade for accessing configuration
36///
37/// The Config struct provides a centralized way to initialize and access
38/// application configuration. It follows the Laravel pattern of type-safe
39/// configuration with environment variable support.
40pub struct Config;
41
42impl Config {
43    /// Initialize the configuration system
44    ///
45    /// This should be called at application startup, before creating the server.
46    /// It loads environment variables from `.env` files and registers default configs.
47    ///
48    /// # Arguments
49    ///
50    /// * `project_root` - Path to the project root where `.env` files are located
51    ///
52    /// # Returns
53    ///
54    /// The detected environment (Local, Development, Production, etc.)
55    ///
56    /// # Example
57    ///
58    /// ```rust,no_run
59    /// use ferro_rs::Config;
60    ///
61    /// let env = Config::init(std::path::Path::new("."));
62    /// println!("Running in {} environment", env);
63    /// ```
64    pub fn init(project_root: &Path) -> Environment {
65        let env = env::load_dotenv(project_root);
66
67        // Register default configs
68        repository::register(AppConfig::from_env());
69        repository::register(ServerConfig::from_env());
70        repository::register(LangConfig::from_env());
71
72        env
73    }
74
75    /// Get a typed config struct from the repository
76    ///
77    /// # Example
78    ///
79    /// ```rust,no_run
80    /// use ferro_rs::{Config, ServerConfig};
81    ///
82    /// let server_config = Config::get::<ServerConfig>().unwrap();
83    /// println!("Port: {}", server_config.port);
84    /// ```
85    pub fn get<T: std::any::Any + Send + Sync + Clone + 'static>() -> Option<T> {
86        repository::get::<T>()
87    }
88
89    /// Register a custom config struct
90    ///
91    /// Use this to register your own configuration structs that can be
92    /// retrieved later with `Config::get::<T>()`.
93    ///
94    /// # Example
95    ///
96    /// ```rust,no_run
97    /// use ferro_rs::Config;
98    ///
99    /// #[derive(Clone)]
100    /// struct DatabaseConfig {
101    ///     host: String,
102    ///     port: u16,
103    /// }
104    ///
105    /// Config::register(DatabaseConfig {
106    ///     host: "localhost".to_string(),
107    ///     port: 5432,
108    /// });
109    /// ```
110    pub fn register<T: std::any::Any + Send + Sync + 'static>(config: T) {
111        repository::register(config);
112    }
113
114    /// Check if a config type is registered
115    pub fn has<T: std::any::Any + 'static>() -> bool {
116        repository::has::<T>()
117    }
118
119    /// Get the current environment
120    ///
121    /// Returns the environment from AppConfig if initialized,
122    /// otherwise detects from the APP_ENV environment variable.
123    pub fn environment() -> Environment {
124        Config::get::<AppConfig>()
125            .map(|c| c.environment)
126            .unwrap_or_else(Environment::detect)
127    }
128
129    /// Check if running in production environment
130    pub fn is_production() -> bool {
131        Self::environment().is_production()
132    }
133
134    /// Check if running in development environment (local or development)
135    pub fn is_development() -> bool {
136        Self::environment().is_development()
137    }
138
139    /// Check if debug mode is enabled
140    pub fn is_debug() -> bool {
141        Config::get::<AppConfig>().map(|c| c.debug).unwrap_or(true)
142    }
143}