1use std::error::Error;
8
9mod helpers;
10mod key;
11mod value;
12pub mod sources;
13
14pub use key::{Key, KeyBuf};
15pub use value::{TryFromValue, Value};
16
17pub trait Source {
19 type Error;
21
22 fn get_value(&self, key: &Key) -> Result<Option<Value>, Self::Error>;
24}
25
26struct BoxedErrorSource<S> {
28 contained: S,
29}
30
31impl<S, E> From<S> for BoxedErrorSource<S>
32where
33 E: Error + 'static,
34 S: Source<Error = E>,
35{
36 fn from(source: S) -> Self {
37 BoxedErrorSource { contained: source }
38 }
39}
40
41impl<S, E> Source for BoxedErrorSource<S>
42where
43 E: Error + 'static,
44 S: Source<Error = E>,
45{
46 type Error = Box<dyn Error>;
47
48 fn get_value(&self, key: &Key) -> Result<Option<Value>, Self::Error> {
49 self.contained
50 .get_value(key)
51 .map_err(|e| Box::new(e) as Box<dyn Error>)
52 }
53}
54
55#[derive(Debug)]
57pub enum ValueReadError {
58 SourceReadError(Box<dyn Error>),
60 ValueConversionError(Box<dyn Error>),
63 ValueNotPresent,
65}
66
67impl Error for ValueReadError {}
68impl std::fmt::Display for ValueReadError {
69 fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 match self {
71 ValueReadError::SourceReadError(e) => {
72 write!(
73 fmt,
74 "Error occurred while reading from configuration source: "
75 )?;
76 e.fmt(fmt)
77 }
78 ValueReadError::ValueConversionError(e) => {
79 write!(fmt, "Value failed to be converted to requested type: ")?;
80 e.fmt(fmt)
81 }
82 ValueReadError::ValueNotPresent => write!(fmt, "Requested value did not exist"),
83 }
84 }
85}
86
87pub trait ValueRead: Sized {
88 fn get_value<T, K>(&self, key: K) -> Result<Option<T>, ValueReadError>
92 where
93 K: AsRef<Key>,
94 T: TryFromValue;
95
96 fn get_expected_value<T, K>(&self, key: K) -> Result<T, ValueReadError>
101 where
102 K: AsRef<Key>,
103 T: TryFromValue,
104 {
105 self.get_value(key)?.ok_or(ValueReadError::ValueNotPresent)
106 }
107
108 fn bind<T: TryFromValueRead>(&self) -> Result<T, ValueReadError> {
110 <T as TryFromValueRead>::try_from(self)
111 }
112}
113pub trait TryFromValueRead: Sized {
116 fn try_from<R: ValueRead>(value_read: &R) -> Result<Self, ValueReadError>;
117}
118
119pub struct Section<'a> {
130 key: KeyBuf,
131 config: &'a Config,
132}
133
134impl<'a> Section<'a> {
135 pub fn section<K: AsRef<Key>>(&self, key: K) -> Section {
147 self.section(key.as_ref())
148 }
149
150 fn _section(&self, key: &Key) -> Section {
151 Section {
152 key: self.key.extend_with_suffix(key),
153 config: self.config
154 }
155 }
156}
157
158impl<'a> ValueRead for Section<'a> {
159 fn get_value<T, K>(&self, key: K) -> Result<Option<T>, ValueReadError>
160 where
161 K: AsRef<Key>,
162 T: TryFromValue,
163 {
164 let mut new_key = self.key.to_key_buf();
165 new_key.push(key.as_ref());
166 self.config.get_value(&new_key)
167 }
168}
169
170pub struct Config {
171 sources: Vec<Box<dyn Source<Error = Box<dyn Error>>>>,
172}
173
174impl Config {
175 pub fn section<K: AsRef<Key>>(&self, key: K) -> Section {
180 Section {
181 key: key.as_ref().to_owned(),
182 config: self,
183 }
184 }
185
186 fn _get_value(&self, key: &Key) -> Result<Option<Value>, ValueReadError> {
187 if self.sources.len() == 0 {
188 return Ok(None);
189 }
190
191 self.sources
194 .iter()
195 .map(|s| s.get_value(key))
196 .skip_while(|v| match v {
197 Ok(None) => true,
198 _ => false,
199 })
200 .next()
201 .unwrap_or(Ok(None))
202 .map_err(|e| ValueReadError::SourceReadError(e))
203 }
204}
205
206impl ValueRead for Config {
207 fn get_value<T, K>(&self, key: K) -> Result<Option<T>, ValueReadError>
208 where
209 K: AsRef<Key>,
210 T: TryFromValue,
211 {
212 self._get_value(key.as_ref())?
213 .map(|v| T::try_from_value(v))
214 .transpose()
215 .map_err(|e| ValueReadError::ValueConversionError(Box::new(e)))
216 }
217}
218
219type BoxedDynamicSource = Box<dyn Source<Error = Box<dyn Error>>>;
220
221pub struct Builder {
222 sources: Vec<BoxedDynamicSource>,
223}
224
225impl Builder {
226 pub fn new() -> Self {
228 Self {
229 sources: Vec::new(),
230 }
231 }
232
233 pub fn add_source<S, E>(mut self, source: S) -> Self
240 where
241 E: Error + 'static,
242 S: Source<Error = E> + 'static,
243 {
244 self.sources.push(Box::new(BoxedErrorSource::from(source)));
245 self
246 }
247
248 pub fn add_source_at_prefix<S, E, K>(self, source: S, prefix: K) -> Self
255 where
256 E: Error + 'static,
257 S: Source<Error = E> + 'static,
258 K: AsRef<Key>
259 {
260 self.add_source(WithPrefixSource {
261 prefix: prefix.as_ref().to_owned(),
262 source
263 })
264 }
265
266 pub fn build(self) -> Config {
268 Config {
269 sources: self.sources,
270 }
271 }
272}
273
274pub struct WithPrefixSource<S: Source> {
279 prefix: KeyBuf,
280 source: S,
281}
282
283impl<S: Source> Source for WithPrefixSource<S> {
284 type Error = S::Error;
285
286 fn get_value(&self, key: &Key) -> Result<Option<Value>, Self::Error> {
287 if !key.start_with(key) {
288 return Ok(None);
289 }
290
291 self.source.get_value(&key.strip_prefix(&self.prefix))
292 }
293}
294