1use crate::*;
3
4#[allow(unused_imports)]
5use self::file::FileLoader;
6use std::path::PathBuf;
7
8pub mod key {
10 pub use crate::key::{CacheKey, PartialKey, PartialKeyCollector};
11}
12pub use super::configuration::ManualSource;
13pub use memory::ConfigSourceBuilder;
14
15pub(crate) mod cargo;
16pub(crate) mod environment;
17pub(crate) mod file;
18pub(crate) mod memory;
19#[doc(hidden)]
20#[cfg(feature = "rand")]
21#[cfg_attr(docsrs, doc(cfg(feature = "rand")))]
22pub(crate) mod random;
23
24#[allow(dead_code)]
25#[derive(Debug, FromConfig)]
26pub(crate) struct EnabledOption {
27 #[config(default = true)]
28 pub(crate) enabled: bool,
29}
30
31macro_rules! file_block {
32 ($($nm:ident.$name:literal.$file:literal: $($k:pat)|* => $x:path,)+) => {
33$(
34#[doc(hidden)]
35#[cfg(feature = $name)]
36#[cfg_attr(docsrs, doc(cfg(feature = $name)))]
37pub mod $nm;
38)+
39
40#[derive(Debug, FromConfig)]
41#[config(prefix = "app.sources")]
42pub(crate) struct SourceOption {
43 #[cfg(feature = "rand")]
44 pub(crate) random: EnabledOption,
45 $(
46 #[cfg(feature = $name)]
47 $nm: EnabledOption,
48 )+
49}
50
51#[inline]
52#[allow(unreachable_code, unused_variables, unused_mut)]
53pub(crate) fn register_by_ext(
54 mut config: Configuration,
55 path: PathBuf,
56 required: bool,
57) -> Result<Configuration, ConfigError> {
58 let ext = path
59 .extension()
60 .and_then(|x| x.to_str())
61 .ok_or_else(|| ConfigError::ConfigFileNotSupported(path.clone()))?;
62 match ext {
63 $(
64 #[cfg(feature = $name)]
65 $($k)|* => {
66 config = config.register_source(<FileLoader<$x>>::new(
67 path.clone(),
68 required,
69 true,
70 ))?;
71 }
72 )+
73 _ => return Err(ConfigError::ConfigFileNotSupported(path)),
74 }
75 Ok(config)
76}
77
78#[allow(unused_mut, unused_variables)]
79pub(crate) fn register_files(
80 mut config: Configuration,
81 option: &SourceOption,
82 path: PathBuf,
83 has_ext: bool,
84) -> Result<Configuration, ConfigError> {
85 $(
86 #[cfg(feature = $name)]
87 if option.$nm.enabled {
88 config =
89 config.register_source(<FileLoader<$x>>::new(path.clone(), false, has_ext))?;
90 }
91 )+
92 Ok(config)
93}
94
95
96#[cfg(test)]
97mod test {
98 $(
99 #[test]
100 #[cfg(not(feature = $name))]
101 fn $nm() {
102 use super::memory::HashSource;
103 use crate::*;
104
105 let _v: Result<HashSource, ConfigError> = inline_source!($file);
106 match _v {
107 Err(ConfigError::ConfigFileNotSupported(_)) =>{}
108 _ => assert_eq!(true, false),
109 }
110 }
111 )+
112}
113 };
114}
115
116file_block!(
117 toml."toml"."../../app.toml" : "toml" | "tml" => toml::Toml,
118 yaml."yaml"."../../app.yaml" : "yaml" | "yml" => yaml::Yaml,
119 json."json"."../../app.json" : "json" => json::Json,
120 ini."ini"."../../app.ini" : "ini" => ini::Ini,
121);
122
123#[macro_export]
125macro_rules! inline_source {
126 ($path:literal) => {
127 $crate::inline_source_internal!(
128 $path:
129 toml."toml": "toml" | "tml" => $crate::source::toml::Toml,
130 yaml."yaml": "yaml" | "yml" => $crate::source::yaml::Yaml,
131 json."json": "json" => $crate::source::json::Json,
132 ini."ini": "ini" => $crate::source::ini::Ini,
133 )
134 };
135}
136
137#[doc(hidden)]
138#[macro_export]
139macro_rules! inline_source_internal {
140 ($path:literal: $($nm:ident.$name:literal: $($k:pat)|* => $x:path,)+) => {
141 match $path.rsplit_once(".") {
142 Some((_, ext)) => {
143 let _name = format!("inline:{}", $path);
144 let _content = include_str!($path);
145 match ext {
146 $(
147 #[cfg(feature = $name)]
148 $($k)|* => $crate::inline_source_config::<$x>(_name, _content),
149 )+
150 _ => Err($crate::ConfigError::ConfigFileNotSupported($path.into()))
151 }
152 }
153 _ => Err($crate::ConfigError::ConfigFileNotSupported($path.into()))
154 }
155 };
156}
157
158pub trait ConfigSourceAdaptor {
168 fn convert_source(self, builder: &mut ConfigSourceBuilder<'_>) -> Result<(), ConfigError>;
170}
171
172pub trait ConfigSourceParser: Send {
174 type Adaptor: ConfigSourceAdaptor;
176
177 fn parse_source(_: &str) -> Result<Self::Adaptor, ConfigError>;
179
180 fn file_extensions() -> Vec<&'static str>;
182}
183
184pub trait ConfigSource: Send {
193 fn name(&self) -> &str;
195
196 fn load(&self, builder: &mut ConfigSourceBuilder<'_>) -> Result<(), ConfigError>;
198
199 fn allow_refresh(&self) -> bool {
201 false
202 }
203
204 fn refreshable(&self) -> Result<bool, ConfigError> {
208 Ok(false)
209 }
210}