1 use std::fmt::Debug;
2 use std::str::FromStr;
3 
4 use async_trait::async_trait;
5 
6 use crate::error::Result;
7 use crate::map::Map;
8 use crate::path;
9 use crate::value::{Value, ValueKind};
10 
11 /// Describes a generic _source_ of configuration properties.
12 pub trait Source: Debug {
clone_into_box(&self) -> Box<dyn Source + Send + Sync>13     fn clone_into_box(&self) -> Box<dyn Source + Send + Sync>;
14 
15     /// Collect all configuration properties available from this source and return
16     /// a Map.
collect(&self) -> Result<Map<String, Value>>17     fn collect(&self) -> Result<Map<String, Value>>;
18 
19     /// Collects all configuration properties to a provided cache.
collect_to(&self, cache: &mut Value) -> Result<()>20     fn collect_to(&self, cache: &mut Value) -> Result<()> {
21         self.collect()?
22             .iter()
23             .for_each(|(key, val)| set_value(cache, key, val));
24 
25         Ok(())
26     }
27 }
28 
set_value(cache: &mut Value, key: &str, value: &Value)29 fn set_value(cache: &mut Value, key: &str, value: &Value) {
30     match path::Expression::from_str(key) {
31         // Set using the path
32         Ok(expr) => expr.set(cache, value.clone()),
33 
34         // Set diretly anyway
35         _ => path::Expression::Identifier(key.to_string()).set(cache, value.clone()),
36     }
37 }
38 
39 /// Describes a generic _source_ of configuration properties capable of using an async runtime.
40 ///
41 /// At the moment this library does not implement it, although it allows using its implementations
42 /// within builders.  Due to the scattered landscape of asynchronous runtimes, it is impossible to
43 /// cater to all needs with one implementation.  Also, this trait might be most useful with remote
44 /// configuration sources, reachable via the network, probably using HTTP protocol.  Numerous HTTP
45 /// libraries exist, making it even harder to find one implementation that rules them all.
46 ///
47 /// For those reasons, it is left to other crates to implement runtime-specific or proprietary
48 /// details.
49 ///
50 /// It is advised to use `async_trait` crate while implementing this trait.
51 ///
52 /// See examples for sample implementation.
53 #[async_trait]
54 pub trait AsyncSource: Debug + Sync {
55     // Sync is supertrait due to https://docs.rs/async-trait/0.1.50/async_trait/index.html#dyn-traits
56 
57     /// Collects all configuration properties available from this source and return
58     /// a Map as an async operations.
collect(&self) -> Result<Map<String, Value>>59     async fn collect(&self) -> Result<Map<String, Value>>;
60 
61     /// Collects all configuration properties to a provided cache.
collect_to(&self, cache: &mut Value) -> Result<()>62     async fn collect_to(&self, cache: &mut Value) -> Result<()> {
63         self.collect()
64             .await?
65             .iter()
66             .for_each(|(key, val)| set_value(cache, key, val));
67 
68         Ok(())
69     }
70 }
71 
72 impl Clone for Box<dyn AsyncSource + Send + Sync> {
clone(&self) -> Self73     fn clone(&self) -> Self {
74         self.to_owned()
75     }
76 }
77 
78 impl Clone for Box<dyn Source + Send + Sync> {
clone(&self) -> Self79     fn clone(&self) -> Self {
80         self.clone_into_box()
81     }
82 }
83 
84 impl Source for Vec<Box<dyn Source + Send + Sync>> {
clone_into_box(&self) -> Box<dyn Source + Send + Sync>85     fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
86         Box::new((*self).clone())
87     }
88 
collect(&self) -> Result<Map<String, Value>>89     fn collect(&self) -> Result<Map<String, Value>> {
90         let mut cache: Value = Map::<String, Value>::new().into();
91 
92         for source in self {
93             source.collect_to(&mut cache)?;
94         }
95 
96         if let ValueKind::Table(table) = cache.kind {
97             Ok(table)
98         } else {
99             unreachable!();
100         }
101     }
102 }
103 
104 impl Source for [Box<dyn Source + Send + Sync>] {
clone_into_box(&self) -> Box<dyn Source + Send + Sync>105     fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
106         Box::new(self.to_owned())
107     }
108 
collect(&self) -> Result<Map<String, Value>>109     fn collect(&self) -> Result<Map<String, Value>> {
110         let mut cache: Value = Map::<String, Value>::new().into();
111 
112         for source in self {
113             source.collect_to(&mut cache)?;
114         }
115 
116         if let ValueKind::Table(table) = cache.kind {
117             Ok(table)
118         } else {
119             unreachable!();
120         }
121     }
122 }
123 
124 impl<T> Source for Vec<T>
125 where
126     T: Source + Sync + Send + Clone + 'static,
127 {
clone_into_box(&self) -> Box<dyn Source + Send + Sync>128     fn clone_into_box(&self) -> Box<dyn Source + Send + Sync> {
129         Box::new((*self).clone())
130     }
131 
collect(&self) -> Result<Map<String, Value>>132     fn collect(&self) -> Result<Map<String, Value>> {
133         let mut cache: Value = Map::<String, Value>::new().into();
134 
135         for source in self {
136             source.collect_to(&mut cache)?;
137         }
138 
139         if let ValueKind::Table(table) = cache.kind {
140             Ok(table)
141         } else {
142             unreachable!();
143         }
144     }
145 }
146