1use anyhow::Error;
2use once_cell::sync::OnceCell;
3use std::convert::identity;
4use std::env;
5use std::fmt;
6use std::str::FromStr;
7
8#[derive(Debug)]
11pub struct ConfigPatch<T> {
12 pre: &'static str,
14 post: OnceCell<T>,
16}
17
18impl<T> ConfigPatch<T> {
19 pub const fn new(pre: &'static str) -> Self {
20 Self {
21 pre,
22 post: OnceCell::new(),
23 }
24 }
25
26 pub const fn var(&self) -> &'static str {
27 self.pre
28 }
29
30 pub fn env_var(&self) -> Result<Option<T>, Error>
31 where
32 T: FromStr,
33 {
34 if let Ok(s) = env::var(self.pre) {
35 let value = s.parse().map_err(|_err| {
36 Error::msg(format!("Can't parse {} variable from '{}'.", self.pre, s))
37 })?;
38 Ok(Some(value))
39 } else {
40 Ok(None)
41 }
42 }
43
44 pub fn offer(&self, value: T) {
46 if let Err(_err) = self.post.set(value) {
47 log::error!("Config value {} already overriden.", self.pre);
48 }
49 }
50
51 pub fn get<F, D>(&self, value: F, default: D) -> T
52 where
53 T: fmt::Debug + FromStr + Clone,
54 F: Fn() -> Option<T>,
55 D: Fn() -> T,
56 {
57 let value = self
58 .env_var()
59 .map_err(|err| {
60 log::error!("Default value for {} will be used: {}", self.pre, err);
61 })
62 .ok()
63 .and_then(identity)
64 .or_else(value)
65 .or_else(|| self.post.get().cloned())
66 .unwrap_or_else(default);
67 log::debug!("{} = {:?}", self.pre, value);
68 value
69 }
70}