Skip to main content

wae_config/
lib.rs

1//! WAE Config - 配置管理模块
2//!
3//! 提供统一的配置加载和管理能力,基于 figment 库实现。
4//! 支持多层级配置合并:环境变量 > 配置文件 > 默认值。
5
6#![warn(missing_docs)]
7
8use figment::{
9    Figment,
10    providers::{Env, Format, Toml, Yaml},
11};
12use serde::de::DeserializeOwned;
13use std::fmt;
14
15/// 配置错误类型
16#[derive(Debug)]
17pub enum ConfigError {
18    /// 配置加载失败
19    LoadFailed(String),
20
21    /// 配置解析失败
22    ParseFailed(String),
23
24    /// 配置验证失败
25    ValidationFailed(String),
26
27    /// 缺少必需配置
28    MissingConfig(String),
29}
30
31impl fmt::Display for ConfigError {
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        match self {
34            ConfigError::LoadFailed(msg) => write!(f, "Failed to load config: {}", msg),
35            ConfigError::ParseFailed(msg) => write!(f, "Failed to parse config: {}", msg),
36            ConfigError::ValidationFailed(msg) => write!(f, "Config validation failed: {}", msg),
37            ConfigError::MissingConfig(msg) => write!(f, "Missing required config: {}", msg),
38        }
39    }
40}
41
42impl std::error::Error for ConfigError {}
43
44/// 配置加载结果类型
45pub type ConfigResult<T> = Result<T, ConfigError>;
46
47/// 配置加载器
48///
49/// 支持从多种来源加载配置,并按优先级合并。
50/// 优先级从高到低:环境变量 > 指定配置文件 > 默认配置文件 > 默认值
51pub struct ConfigLoader {
52    figment: Figment,
53}
54
55impl Default for ConfigLoader {
56    fn default() -> Self {
57        Self::new()
58    }
59}
60
61impl ConfigLoader {
62    /// 创建新的配置加载器
63    pub fn new() -> Self {
64        Self { figment: Figment::new() }
65    }
66
67    /// 从 TOML 文件加载配置
68    ///
69    /// # Arguments
70    /// * `path` - 配置文件路径
71    pub fn with_toml(mut self, path: &str) -> Self {
72        self.figment = self.figment.merge(Toml::file(path));
73        self
74    }
75
76    /// 从 YAML 文件加载配置
77    ///
78    /// # Arguments
79    /// * `path` - 配置文件路径
80    pub fn with_yaml(mut self, path: &str) -> Self {
81        self.figment = self.figment.merge(Yaml::file(path));
82        self
83    }
84
85    /// 从环境变量加载配置
86    ///
87    /// # Arguments
88    /// * `prefix` - 环境变量前缀,如 "APP_"
89    pub fn with_env(mut self, prefix: &str) -> Self {
90        self.figment = self.figment.merge(Env::prefixed(prefix));
91        self
92    }
93
94    /// 从环境变量加载配置(带分隔符)
95    ///
96    /// # Arguments
97    /// * `prefix` - 环境变量前缀
98    /// * `separator` - 嵌套分隔符,如 "__"
99    pub fn with_env_separator(mut self, prefix: &str, separator: &str) -> Self {
100        self.figment = self.figment.merge(Env::prefixed(prefix).split(separator));
101        self
102    }
103
104    /// 合并默认值
105    ///
106    /// # Arguments
107    /// * `defaults` - 默认配置值
108    pub fn with_defaults<T: serde::Serialize>(mut self, defaults: &T) -> Self {
109        self.figment = self.figment.merge(figment::providers::Serialized::defaults(defaults));
110        self
111    }
112
113    /// 提取配置到指定类型
114    ///
115    /// # Type Parameters
116    /// * `T` - 配置类型,需实现 `DeserializeOwned`
117    pub fn extract<T: DeserializeOwned>(self) -> ConfigResult<T> {
118        self.figment.extract().map_err(|e| {
119            let msg = e.to_string();
120            if msg.contains("missing field") { ConfigError::MissingConfig(msg) } else { ConfigError::ParseFailed(msg) }
121        })
122    }
123
124    /// 提取配置到指定类型(带自定义错误消息)
125    ///
126    /// # Type Parameters
127    /// * `T` - 配置类型,需实现 `DeserializeOwned`
128    /// * `context` - 错误上下文信息
129    pub fn extract_with_context<T: DeserializeOwned>(self, context: &str) -> ConfigResult<T> {
130        self.extract().map_err(|e| ConfigError::LoadFailed(format!("{}: {}", context, e)))
131    }
132}
133
134/// 快速加载配置的便捷函数
135///
136/// 从默认位置加载配置文件,并合并环境变量。
137///
138/// # Type Parameters
139/// * `T` - 配置类型
140///
141/// # Arguments
142/// * `config_path` - 配置文件路径
143/// * `env_prefix` - 环境变量前缀
144pub fn load_config<T: DeserializeOwned>(config_path: &str, env_prefix: &str) -> ConfigResult<T> {
145    ConfigLoader::new().with_toml(config_path).with_env(env_prefix).extract()
146}
147
148/// 从环境变量加载配置
149///
150/// # Type Parameters
151/// * `T` - 配置类型
152///
153/// # Arguments
154/// * `prefix` - 环境变量前缀
155pub fn from_env<T: DeserializeOwned>(prefix: &str) -> ConfigResult<T> {
156    ConfigLoader::new().with_env(prefix).extract()
157}