config/
binder.rs

1use crate::{ext::*, *};
2use serde::de::DeserializeOwned;
3use std::{str::FromStr, ops::Deref};
4
5/// Provides binder extension methods for a [`Configuration`](crate::Configuration).
6pub trait ConfigurationBinder {
7    /// Creates and returns a structure bound to the configuration.
8    fn reify<T: DeserializeOwned>(&self) -> T;
9
10    /// Binds the configuration to the specified instance.
11    ///
12    /// # Arguments
13    ///
14    /// * `instance` - The instance to bind the configuration to
15    fn bind<T: DeserializeOwned>(&self, instance: &mut T);
16
17    /// Binds the specified configuration section to the provided instance.
18    ///
19    /// # Arguments
20    ///
21    /// * `key` - The key of the configuration section to bind
22    /// * `instance` - The instance to bind the configuration to
23    fn bind_at<T: DeserializeOwned>(&self, key: impl AsRef<str>, instance: &mut T);
24
25    /// Gets a typed value from the configuration.
26    ///
27    /// # Arguments
28    ///
29    /// * `key` - The key of the value to retrieve
30    fn get_value<T: FromStr>(&self, key: impl AsRef<str>) -> Result<Option<T>, T::Err>;
31
32    /// Gets an optional, typed value from the configuration.
33    ///
34    /// # Arguments
35    ///
36    /// * `key` - The key of the value to retrieve
37    fn get_value_or_default<T: FromStr + Default>(&self, key: impl AsRef<str>) -> Result<T, T::Err>;
38}
39
40impl ConfigurationBinder for dyn Configuration + '_ {
41    fn reify<T: DeserializeOwned>(&self) -> T {
42        from_config::<T>(self).unwrap()
43    }
44
45    fn bind<T: DeserializeOwned>(&self, instance: &mut T) {
46        bind_config(self, instance).unwrap()
47    }
48
49    fn bind_at<T: DeserializeOwned>(&self, key: impl AsRef<str>, instance: &mut T) {
50        let section = self.section(key.as_ref());
51
52        if section.exists() {
53            bind_config(section.deref().as_ref(), instance).unwrap()
54        }
55    }
56
57    fn get_value<T: FromStr>(&self, key: impl AsRef<str>) -> Result<Option<T>, T::Err> {
58        let section = self.section(key.as_ref());
59        let value = if section.exists() {
60            Some(T::from_str(section.value().as_str())?)
61        } else {
62            None
63        };
64
65        Ok(value)
66    }
67
68    fn get_value_or_default<T: FromStr + Default>(&self, key: impl AsRef<str>) -> Result<T, T::Err> {
69        let section = self.section(key.as_ref());
70        let value = if section.exists() {
71            T::from_str(section.value().as_str())?
72        } else {
73            T::default()
74        };
75
76        Ok(value)
77    }
78}
79
80impl<C: AsRef<dyn Configuration>> ConfigurationBinder for C {
81    fn reify<T: DeserializeOwned>(&self) -> T {
82        from_config::<T>(self.as_ref()).unwrap()
83    }
84
85    fn bind<T: DeserializeOwned>(&self, instance: &mut T) {
86        bind_config(self.as_ref(), instance).unwrap()
87    }
88
89    fn bind_at<T: DeserializeOwned>(&self, key: impl AsRef<str>, instance: &mut T) {
90        let section = self.as_ref().section(key.as_ref());
91
92        if section.exists() {
93            bind_config(section.deref().as_ref(), instance).unwrap()
94        }
95    }
96
97    fn get_value<T: FromStr>(&self, key: impl AsRef<str>) -> Result<Option<T>, T::Err> {
98        let section = self.as_ref().section(key.as_ref());
99        let value = if section.exists() {
100            Some(T::from_str(section.value().as_str())?)
101        } else {
102            None
103        };
104
105        Ok(value)
106    }
107
108    fn get_value_or_default<T: FromStr + Default>(&self, key: impl AsRef<str>) -> Result<T, T::Err> {
109        let section = self.as_ref().section(key.as_ref());
110        let value = if section.exists() {
111            T::from_str(section.value().as_str())?
112        } else {
113            T::default()
114        };
115
116        Ok(value)
117    }
118}