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