1use crate::{general::GeneralConfig, logger::LoggerConfig};
2use anyhow::Result;
3use serde::Deserialize;
4
5#[cfg(feature = "postgres")]
6use crate::postgres::PostgresConfig;
7
8#[cfg(feature = "redis")]
9use crate::redis::RedisConfig;
10
11macro_rules! deserialize_with_context {
12 ($name:ident, $type:ty, $context:expr) => {
13 fn $name<'de, D>(deserializer: D) -> std::result::Result<$type, D::Error>
14 where
15 D: serde::Deserializer<'de>,
16 {
17 let config = <$type>::deserialize(deserializer)
18 .map_err(|e| serde::de::Error::custom(format!("{}: {}", $context, e)))?;
19 Ok(config)
20 }
21 };
22}
23
24deserialize_with_context!(deserialize_general_config, GeneralConfig, "[general]");
25deserialize_with_context!(deserialize_logger_config, LoggerConfig, "[logger]");
26
27#[cfg(feature = "postgres")]
28deserialize_with_context!(deserialize_postgres_config, PostgresConfig, "[postgres]");
29
30#[cfg(feature = "redis")]
31deserialize_with_context!(deserialize_redis_config, RedisConfig, "[redis]");
32
33#[derive(Debug, Deserialize)]
34pub struct Config {
35 #[serde(deserialize_with = "deserialize_general_config")]
36 pub general: GeneralConfig,
37 #[serde(deserialize_with = "deserialize_logger_config")]
38 pub logger: LoggerConfig,
39
40 #[cfg(feature = "postgres")]
41 #[serde(deserialize_with = "deserialize_postgres_config")]
42 pub postgres: PostgresConfig,
43
44 #[cfg(feature = "redis")]
45 #[serde(deserialize_with = "deserialize_redis_config")]
46 pub redis: RedisConfig,
47}
48
49pub fn load_config(name: &str) -> Result<Config> {
50 let config = ::config::Config::builder()
51 .add_source(config::File::with_name(name))
52 .build()?
53 .try_deserialize()?;
54 Ok(config)
55}