1use core::ops::Deref;
2use parking_lot::Mutex;
3use std::{collections::HashSet, path::PathBuf, vec};
4
5use crate::{
6 wrapper::IORef, FromEnvironment, IORefT, IsProperty, Key, Property, PropertyError,
7 PropertySource, SalakContext, SubKey, SubKeys, PREFIX,
8};
9#[cfg(feature = "derive")]
10#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
11use crate::{DescFromEnvironment, KeyDesc, PrefixedFromEnvironment, SalakDescContext};
12use crate::{Res, Void};
13
14enum PS<'a> {
15 Ref(&'a Box<dyn PropertySource>),
16 Own(Box<dyn PropertySource>),
17}
18
19impl Deref for PS<'_> {
20 type Target = dyn PropertySource;
21
22 fn deref(&self) -> &Self::Target {
23 match self {
24 PS::Own(f) => f.as_ref(),
25 PS::Ref(f) => f.as_ref(),
26 }
27 }
28}
29
30pub(crate) struct PropertyRegistryInternal<'a> {
31 name: &'a str,
32 providers: Vec<PS<'a>>,
33}
34
35impl PropertySource for PropertyRegistryInternal<'_> {
36 fn name(&self) -> &str {
37 self.name
38 }
39
40 #[inline]
41 fn get_property(&self, key: &Key<'_>) -> Option<Property<'_>> {
42 self.providers.iter().find_map(|p| p.get_property(key))
43 }
44
45 fn is_empty(&self) -> bool {
46 self.providers.is_empty() || self.providers.iter().all(|f| f.is_empty())
47 }
48
49 fn get_sub_keys<'a>(&'a self, key: &Key<'_>, sub_keys: &mut SubKeys<'a>) {
50 self.providers
51 .iter()
52 .for_each(|f| f.get_sub_keys(key, sub_keys));
53 }
54}
55
56impl<'a> PropertyRegistryInternal<'a> {
57 pub(crate) fn register_by_ref(&mut self, provider: Box<dyn PropertySource>) {
58 if !provider.is_empty() {
59 #[cfg(feature = "log")]
60 log::info!("Register source {}.", provider.name());
61 self.providers.push(PS::Own(provider));
62 }
63 }
64
65 pub(crate) fn register<P: PropertySource + Send + Sync + 'static>(
66 mut self,
67 provider: P,
68 ) -> Self {
69 self.register_by_ref(Box::new(provider));
70 self
71 }
72
73 pub(crate) fn new(name: &'a str) -> Self {
74 Self {
75 name,
76 providers: vec![],
77 }
78 }
79
80 fn get(
81 &'a self,
82 key: &mut Key<'_>,
83 def: Option<Property<'a>>,
84 ) -> Result<Option<Property<'a>>, PropertyError> {
85 let tmp;
86 let v = match self.get_property(key).or(def) {
87 Some(Property::S(v)) => v,
88 Some(Property::O(v)) => {
89 tmp = v;
90 &tmp[..]
91 }
92 v => return Ok(v),
93 };
94 let mut history = HashSet::new();
95 history.insert(key.as_str().to_string());
96 Ok(Some(self.resolve(key, v, &mut history)?))
97 }
98
99 #[inline]
100 fn merge(val: Option<String>, new: &str) -> String {
101 match val {
102 Some(mut v) => {
103 v.push_str(new);
104 v
105 }
106 None => new.to_owned(),
107 }
108 }
109
110 #[inline]
111 fn resolve(
112 &self,
113 key: &Key<'_>,
114 mut val: &str,
115 history: &mut HashSet<String>,
116 ) -> Result<Property<'_>, PropertyError> {
117 let mut stack = vec!["".to_owned()];
118 let pat: &[_] = &['$', '\\', '}'];
119
120 while let Some(pos) = val.find(pat) {
121 match &val[pos..=pos] {
122 "$" => {
123 let pos_1 = pos + 1;
124 if val.len() == pos_1 || &val[pos_1..=pos_1] != "{" {
125 return Err(PropertyError::ResolveFail(key.as_str().to_string()));
126 }
127 let last = stack.pop();
128 stack.push(Self::merge(last, &val[..pos]));
129 stack.push("".to_owned());
130 val = &val[pos + 2..];
131 }
132 "\\" => {
133 let pos_1 = pos + 1;
134 if val.len() == pos_1 {
135 return Err(PropertyError::ResolveFail(key.as_str().to_string()));
136 }
137 let last = stack.pop();
138 let mut v = Self::merge(last, &val[..pos]);
139 v.push_str(&val[pos_1..=pos_1]);
140 stack.push(v);
141 val = &val[pos + 2..];
142 }
143 "}" => {
144 let last = stack.pop();
145 let v = Self::merge(last, &val[..pos]);
146 let (key, def) = match v.find(':') {
147 Some(pos) => (&v[..pos], Some(&v[pos + 1..])),
148 _ => (&v[..], None),
149 };
150 if !history.insert(key.to_string()) {
151 return Err(PropertyError::RecursiveFail(key.to_owned()));
152 }
153 let v = if let Some(p) = self.get(&mut Key::from_str(key), None)? {
154 String::from_property(p)?
155 } else if let Some(d) = def {
156 d.to_owned()
157 } else {
158 return Err(PropertyError::ResolveNotFound(key.to_string()));
159 };
160 history.remove(key);
161 let v = Self::merge(stack.pop(), &v);
162 stack.push(v);
163 val = &val[pos + 1..];
164 }
165 _ => return Err(PropertyError::ResolveFail(key.as_str().to_string())),
166 }
167 }
168 if let Some(mut v) = stack.pop() {
169 if stack.is_empty() {
170 v.push_str(val);
171 return Ok(Property::O(v));
172 }
173 }
174 Err(PropertyError::ResolveFail(key.as_str().to_string()))
175 }
176
177 pub(crate) fn reload(&self, iorefs: &'a Mutex<Vec<Box<dyn IORefT + Send>>>) -> Res<bool> {
178 let mut flag = false;
179 let registry = PropertyRegistryInternal {
180 name: "reload",
181 providers: self
182 .providers
183 .iter()
184 .map(|f| match f.reload_source() {
185 Ok(None) => Ok(match f {
186 PS::Own(v) => PS::Ref(&*v),
187 PS::Ref(v) => PS::Ref(*v),
188 }),
189 Ok(Some(v)) => {
190 flag = true;
191 Ok(PS::Own(v))
192 }
193 Err(err) => Err(err),
194 })
195 .collect::<Result<Vec<PS<'_>>, PropertyError>>()?,
196 };
197
198 let guard = iorefs.lock();
199 for io in guard.iter() {
200 io.reload_ref(®istry, iorefs)?;
201 }
202 Ok(flag)
203 }
204
205 #[inline]
206 pub(crate) fn require<T: FromEnvironment>(
207 &self,
208 sub_key: &str,
209 iorefs: &'a Mutex<Vec<Box<dyn IORefT + Send>>>,
210 ) -> Res<T> {
211 let mut key = Key::new();
212 SalakContext::new(&self, iorefs, &mut key).require_def(sub_key, None)
213 }
214}
215#[cfg(feature = "derive")]
216#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
217impl<'a> SalakDescContext<'a> {
218 pub(crate) fn new(key: &'a mut Key<'a>, descs: &'a mut Vec<KeyDesc>) -> Self {
219 let current = KeyDesc::new(key.as_str().to_string(), "String", None, None, None);
220 Self {
221 key,
222 descs,
223 current,
224 }
225 }
226
227 #[inline]
229 pub fn add_key_desc<T: DescFromEnvironment>(
230 &mut self,
231 sub_key: &'a str,
232 required: Option<bool>,
233 def: Option<&'a str>,
234 desc: Option<String>,
235 ) {
236 self.add_key_desc_internal::<T, &str>(sub_key, required, def, desc)
237 }
238
239 pub(crate) fn add_key_desc_internal<T: DescFromEnvironment, K: Into<SubKey<'a>>>(
240 &mut self,
241 sub_key: K,
242 required: Option<bool>,
243 def: Option<&'a str>,
244 desc: Option<String>,
245 ) {
246 self.into_sub_key(sub_key);
247 let key = self.key.as_generic();
248 let bak = std::mem::replace(
249 &mut self.current,
250 KeyDesc::new(key, std::any::type_name::<T>(), required, def, desc),
251 );
252 T::key_desc(self);
253 let desc = std::mem::replace(&mut self.current, bak);
254 if !desc.ignore {
255 self.descs.push(desc);
256 }
257 self.key.pop();
258 }
259 fn into_sub_key<K: Into<SubKey<'a>>>(&mut self, k: K) {
260 self.key.push(k.into());
261 }
262}
263
264impl<'a> SalakContext<'a> {
265 #[inline]
267 pub fn require_def<T: FromEnvironment>(
268 &mut self,
269 sub_key: &'a str,
270 def: Option<Property<'_>>,
271 ) -> Res<T> {
272 self.require_def_internal(sub_key, def)
273 }
274
275 #[inline]
276 pub(crate) fn require_def_internal<T: FromEnvironment, K: Into<SubKey<'a>>>(
277 &mut self,
278 sub_key: K,
279 def: Option<Property<'_>>,
280 ) -> Res<T> {
281 let flag = self.into_sub_key(sub_key);
282 let val = match self.registry.get(self.key, def) {
283 Ok(val) => Ok(T::from_env(val, self)),
284 Err(e) => Err(e),
285 };
286 if flag {
287 self.key.pop();
288 }
289 match val? {
290 Err(PropertyError::ParseFail(None, v)) if !self.key.as_str().is_empty() => Err(
291 PropertyError::ParseFail(Some(self.key.as_str().to_string()), v),
292 ),
293 val => val,
294 }
295 }
296
297 pub(crate) fn get_sub_keys(&mut self) -> SubKeys<'a> {
298 let mut sub_keys = SubKeys::new();
299 self.registry.get_sub_keys(&mut self.key, &mut sub_keys);
300 sub_keys
301 }
302
303 #[inline]
304 pub(crate) fn current_key(&self) -> &str {
305 self.key.as_str()
306 }
307
308 fn into_sub_key<K: Into<SubKey<'a>>>(&mut self, k: K) -> bool {
309 let v = k.into();
310 let flag = !v.is_empty();
311 if flag {
312 self.key.push(v);
313 }
314 return flag;
315 }
316
317 pub(crate) fn new(
318 registry: &'a PropertyRegistryInternal<'a>,
319 iorefs: &'a Mutex<Vec<Box<dyn IORefT + Send>>>,
320 key: &'a mut Key<'a>,
321 ) -> Self {
322 Self {
323 registry,
324 key,
325 iorefs,
326 }
327 }
328
329 #[inline]
330 pub(crate) fn register_ioref<T: Clone + FromEnvironment + Send + 'static>(
331 &self,
332 ioref: &IORef<T>,
333 ) {
334 let mut guard = self.iorefs.lock();
335 let io = ioref.clone();
336 guard.push(Box::new(io));
337 }
338}
339
340impl<T: FromEnvironment> FromEnvironment for Option<T> {
341 fn from_env(val: Option<Property<'_>>, env: &mut SalakContext<'_>) -> Res<Self> {
342 match T::from_env(val, env) {
343 Ok(v) => Ok(Some(v)),
344 Err(PropertyError::NotFound(_)) => Ok(None),
345 Err(err) => Err(err),
346 }
347 }
348}
349
350#[cfg(feature = "derive")]
351#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
352impl<T: DescFromEnvironment> DescFromEnvironment for Option<T> {
353 fn key_desc(env: &mut SalakDescContext<'_>) {
354 env.current.set_required(false);
355 T::key_desc(env);
356 }
357}
358
359pub(crate) struct FileConfig {
360 dir: Option<String>,
361 name: String,
362 profile: String,
363 env_profile: PropertyRegistryInternal<'static>,
364 env_default: PropertyRegistryInternal<'static>,
365}
366
367impl FromEnvironment for FileConfig {
368 fn from_env(_: Option<Property<'_>>, env: &mut SalakContext<'_>) -> Res<Self> {
369 Ok(FileConfig {
370 dir: env.require_def("dir", None)?,
371 name: env.require_def("filename", Some(Property::S("app")))?,
372 profile: env.require_def("profile", Some(Property::S("default")))?,
373 env_profile: PropertyRegistryInternal::new("profile-files"),
374 env_default: PropertyRegistryInternal::new("default-files"),
375 })
376 }
377}
378
379#[cfg(feature = "derive")]
380#[cfg_attr(docsrs, doc(cfg(feature = "derive")))]
381impl DescFromEnvironment for FileConfig {
382 fn key_desc(env: &mut SalakDescContext<'_>) {
383 env.add_key_desc::<Option<String>>("dir", None, None, None);
384 env.add_key_desc::<String>("filename", Some(false), Some("app"), None);
385 env.add_key_desc::<String>("profile", Some(false), Some("default"), None);
386 }
387}
388
389#[cfg(feature = "derive")]
390impl PrefixedFromEnvironment for FileConfig {
391 fn prefix() -> &'static str {
392 PREFIX
393 }
394}
395
396impl FileConfig {
397 #[allow(dead_code)]
398 pub(crate) fn new(
399 env: &PropertyRegistryInternal<'_>,
400 iorefs: &Mutex<Vec<Box<dyn IORefT + Send>>>,
401 ) -> Res<Self> {
402 env.require::<FileConfig>(PREFIX, iorefs)
403 }
404
405 #[allow(dead_code)]
406 pub(crate) fn register_to_env(self, env: &mut PropertyRegistryInternal<'_>) {
407 env.register_by_ref(Box::new(self.env_profile));
408 env.register_by_ref(Box::new(self.env_default));
409 }
410
411 #[allow(dead_code)]
412 pub(crate) fn build<F: Fn(FileItem) -> Res<S>, S: PropertySource + 'static>(
413 &mut self,
414 ext: &str,
415 f: F,
416 ) -> Void {
417 fn make<F: Fn(FileItem) -> Res<S>, S: PropertySource + 'static>(
418 f: F,
419 file: String,
420 dir: &Option<String>,
421 env: &mut PropertyRegistryInternal<'_>,
422 ) -> Void {
423 let mut path = PathBuf::new();
424 if let Some(d) = &dir {
425 path.push(d);
426 }
427 path.push(file);
428 if path.exists() {
429 env.register_by_ref(Box::new((f)(FileItem(path))?));
430 }
431 Ok(())
432 }
433
434 make(
435 &f,
436 format!("{}-{}.{}", self.name, self.profile, ext),
437 &self.dir,
438 &mut self.env_profile,
439 )?;
440 make(
441 &f,
442 format!("{}.{}", self.name, ext),
443 &self.dir,
444 &mut self.env_default,
445 )
446 }
447}
448
449#[derive(Debug, Clone)]
450pub(crate) struct FileItem(PathBuf);
451
452#[allow(dead_code)]
453impl FileItem {
454 pub(crate) fn load(&self) -> Res<String> {
455 Ok(std::fs::read_to_string(self.0.clone())?)
456 }
457
458 pub(crate) fn name(&self) -> String {
459 self.0.as_path().display().to_string()
460 }
461}
462
463#[cfg(test)]
464mod tests {
465 use raw_ioref::IORef;
466
467 use crate::{
468 source::{Key, SubKeys},
469 *,
470 };
471
472 struct Reload(u64);
473
474 impl PropertySource for Reload {
475 fn name(&self) -> &str {
476 "reload"
477 }
478
479 fn get_property(&self, _: &Key<'_>) -> Option<Property<'_>> {
480 Some(Property::I(self.0 as i64))
481 }
482
483 fn get_sub_keys<'a>(&'a self, _: &Key<'_>, _: &mut SubKeys<'a>) {}
484
485 fn is_empty(&self) -> bool {
486 false
487 }
488 fn reload_source(&self) -> Result<Option<Box<dyn PropertySource>>, PropertyError> {
489 Ok(Some(Box::new(Reload(self.0 + 1))))
490 }
491 }
492
493 #[test]
494 fn reload_test() {
495 let mut env = Salak::new().unwrap();
496 env.register(Reload(0));
497 let u8ref = env.require::<IORef<u8>>("").unwrap();
498 assert_eq!(0, u8ref.get_val().unwrap());
499 env.reload().unwrap();
500 assert_eq!(1, u8ref.get_val().unwrap());
501 env.reload().unwrap();
502 assert_eq!(1, u8ref.get_val().unwrap());
503 }
504}