Skip to main content

config/prelude/
binder.rs

1use crate::{de, section::OwnedSection, Configuration, ReloadableConfiguration, Section};
2use serde::de::DeserializeOwned;
3use std::rc::Rc;
4use std::str::FromStr;
5use std::sync::Arc;
6
7/// Represents [configuration](Configuration) binder for strongly-typed configurations.
8pub trait Binder: Sized {
9    /// Creates and returns a structure reified from the configuration.
10    fn reify<T: DeserializeOwned>(&self) -> crate::Result<T>;
11
12    /// Creates and returns a structure reified from the configuration.
13    ///
14    /// # Remarks
15    ///
16    /// This function panics the reify operation fails.
17    fn reify_unchecked<T: DeserializeOwned>(&self) -> T {
18        match self.reify::<T>() {
19            Ok(data) => data,
20            Err(error) => panic!("{}", error),
21        }
22    }
23
24    /// Binds the configuration to the specified instance.
25    ///
26    /// # Arguments
27    ///
28    /// * `instance` - The instance to bind the configuration to
29    fn bind<T: DeserializeOwned>(&self, instance: &mut T) -> crate::Result;
30
31    /// Binds the configuration to the specified instance.
32    ///
33    /// # Arguments
34    ///
35    /// * `instance` - The instance to bind the configuration to
36    ///
37    /// # Remarks
38    ///
39    /// This function panics the bind operation fails.
40    fn bind_unchecked<T: DeserializeOwned>(&self, instance: &mut T) {
41        if let Err(error) = self.bind(instance) {
42            panic!("{}", error);
43        }
44    }
45
46    /// Binds the specified configuration section to the provided instance.
47    ///
48    /// # Arguments
49    ///
50    /// * `key` - The key of the configuration section to bind
51    /// * `instance` - The instance to bind the configuration to
52    fn bind_at<T: DeserializeOwned>(&self, key: impl AsRef<str>, instance: &mut T) -> crate::Result;
53
54    /// Binds the specified configuration section to the provided instance.
55    ///
56    /// # Arguments
57    ///
58    /// * `key` - The key of the configuration section to bind
59    /// * `instance` - The instance to bind the configuration to
60    ///
61    /// # Remarks
62    ///
63    /// This function panics the bind operation fails.
64    fn bind_at_unchecked<T: DeserializeOwned>(&self, key: impl AsRef<str>, instance: &mut T) {
65        if let Err(error) = self.bind_at(key, instance) {
66            panic!("{}", error);
67        }
68    }
69
70    /// Gets a typed value from the configuration.
71    ///
72    /// # Arguments
73    ///
74    /// * `key` - The key of the value to retrieve
75    fn get_value<T: FromStr>(&self, key: impl AsRef<str>) -> Result<Option<T>, T::Err>;
76
77    /// Gets an optional, typed value from the configuration.
78    ///
79    /// # Arguments
80    ///
81    /// * `key` - The key of the value to retrieve
82    fn get_value_or_default<T: FromStr + Default>(&self, key: impl AsRef<str>) -> Result<T, T::Err>;
83}
84
85macro_rules! binder {
86    ($type:ty) => {
87        impl Binder for $type {
88            #[inline]
89            fn reify<T: DeserializeOwned>(&self) -> crate::Result<T> {
90                Ok(de::from::<T>(self.sections())?)
91            }
92
93            fn bind<T: DeserializeOwned>(&self, instance: &mut T) -> crate::Result {
94                Ok(de::bind(self.sections(), instance)?)
95            }
96
97            fn bind_at<T: DeserializeOwned>(&self, key: impl AsRef<str>, instance: &mut T) -> crate::Result {
98                let section = self.section(key.as_ref());
99
100                if section.exists() {
101                    Ok(de::bind(section.sections(), instance)?)
102                } else {
103                    Ok(())
104                }
105            }
106
107            fn get_value<T: FromStr>(&self, key: impl AsRef<str>) -> Result<Option<T>, T::Err> {
108                let section = self.section(key.as_ref());
109                let value = if section.exists() {
110                    Some(T::from_str(section.value())?)
111                } else {
112                    None
113                };
114
115                Ok(value)
116            }
117
118            fn get_value_or_default<T: FromStr + Default>(&self, key: impl AsRef<str>) -> Result<T, T::Err> {
119                let section = self.section(key.as_ref());
120                let value = if section.exists() {
121                    T::from_str(section.value())?
122                } else {
123                    T::default()
124                };
125
126                Ok(value)
127            }
128        }
129    };
130}
131
132binder!(Configuration);
133binder!(Arc<Configuration>);
134binder!(Rc<Configuration>);
135binder!(Section<'_>);
136binder!(OwnedSection);
137
138impl Binder for ReloadableConfiguration {
139    #[inline]
140    fn reify<T: DeserializeOwned>(&self) -> crate::Result<T> {
141        self.reify()
142    }
143
144    #[inline]
145    fn bind<T: DeserializeOwned>(&self, instance: &mut T) -> crate::Result {
146        self.bind(instance)
147    }
148
149    #[inline]
150    fn bind_at<T: DeserializeOwned>(&self, key: impl AsRef<str>, instance: &mut T) -> crate::Result {
151        self.bind_at(key, instance)
152    }
153
154    #[inline]
155    fn get_value<T: FromStr>(&self, key: impl AsRef<str>) -> Result<Option<T>, T::Err> {
156        self.get_value(key)
157    }
158
159    #[inline]
160    fn get_value_or_default<T: FromStr + Default>(&self, key: impl AsRef<str>) -> Result<T, T::Err> {
161        self.get_value_or_default(key)
162    }
163}