1use std::{
4 collections::{BTreeMap, BTreeSet, HashMap, HashSet},
5 ffi::OsString,
6 fmt::Display,
7 hash::{BuildHasher, Hash},
8 marker::PhantomData,
9 net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6},
10 path::PathBuf,
11 sync::atomic::{
12 AtomicBool, AtomicI16, AtomicI32, AtomicI64, AtomicI8, AtomicIsize, AtomicU16, AtomicU32,
13 AtomicU64, AtomicU8, AtomicUsize,
14 },
15 time::{Duration, SystemTime},
16};
17
18use serde::{de::DeserializeOwned, Deserialize};
19
20use crate::{
21 helpers::{
22 BuilderOf, KeyedContainer, KeyedContainerBuilder, TargetOf, UnkeyedContainerBuilder,
23 },
24 Configuration, ConfigurationBuilder, Error, MissingValue, UnexpectedSecret,
25};
26
27macro_rules! impl_multi_source_via_option {
30 ($type:ty) => {
31 impl Configuration for $type {
32 type Builder = Option<Self>;
33 }
34 };
35
36 ($($type:ty),* $(,)?) => {
37 $(
38 impl_multi_source_via_option! { $type }
39 )*
40 };
41}
42
43impl_multi_source_via_option! {
44 i8, i16, i32, i64, i128, isize,
46
47 u8, u16, u32, u64, u128, usize,
49
50 f32, f64,
52
53 SocketAddr, SocketAddrV4, SocketAddrV6, IpAddr, Ipv4Addr, Ipv6Addr,
55
56 Duration, SystemTime,
58
59 String, OsString, PathBuf, char, bool,
61
62 AtomicI8, AtomicI16, AtomicI32, AtomicI64, AtomicIsize,
64 AtomicU8, AtomicU16, AtomicU32, AtomicU64, AtomicUsize,
65 AtomicBool,
66}
67
68impl<T> Configuration for Vec<T>
70where
71 T: Configuration,
72 BuilderOf<T>: 'static,
73{
74 type Builder = UnkeyedContainerBuilder<Vec<BuilderOf<T>>, Self>;
75}
76
77impl<T> Configuration for BTreeSet<T>
78where
79 T: Configuration + Ord,
80 BuilderOf<T>: Ord + 'static,
81{
82 type Builder = UnkeyedContainerBuilder<BTreeSet<BuilderOf<T>>, Self>;
83}
84
85impl<T, S> Configuration for HashSet<T, S>
86where
87 T: Configuration + Eq + Hash,
88 BuilderOf<T>: Hash + Eq + 'static,
89 S: BuildHasher + Default + 'static,
90{
91 type Builder = UnkeyedContainerBuilder<HashSet<BuilderOf<T>, S>, Self>;
92}
93
94impl<K, V> KeyedContainer for BTreeMap<K, V>
95where
96 K: Ord,
97{
98 type Key = K;
99 type Value = V;
100
101 fn insert(&mut self, k: Self::Key, v: Self::Value) {
102 self.insert(k, v);
103 }
104
105 fn remove(&mut self, k: &Self::Key) -> Option<Self::Value> {
106 self.remove(k)
107 }
108}
109
110impl<K, V> Configuration for BTreeMap<K, V>
111where
112 K: Ord + Display + DeserializeOwned + 'static,
113 V: Configuration,
114 BuilderOf<V>: 'static,
115{
116 type Builder = KeyedContainerBuilder<BTreeMap<K, BuilderOf<V>>, Self>;
117}
118
119impl<K, V, S> KeyedContainer for HashMap<K, V, S>
120where
121 K: Hash + Eq,
122 S: BuildHasher + Default,
123{
124 type Key = K;
125 type Value = V;
126
127 fn insert(&mut self, k: Self::Key, v: Self::Value) {
128 self.insert(k, v);
129 }
130
131 fn remove(&mut self, k: &Self::Key) -> Option<Self::Value> {
132 self.remove(k)
133 }
134}
135
136impl<K, V, S> Configuration for HashMap<K, V, S>
137where
138 K: Hash + Eq + Display + DeserializeOwned + 'static,
139 V: Configuration,
140 BuilderOf<V>: 'static,
141 S: Default + BuildHasher + 'static,
142{
143 type Builder = KeyedContainerBuilder<HashMap<K, BuilderOf<V>, S>, Self>;
144}
145
146impl<T, const N: usize> Configuration for [T; N]
147where
148 [BuilderOf<T>; N]: DeserializeOwned + Default,
149 T: Configuration,
150{
151 type Builder = [BuilderOf<T>; N];
152}
153
154impl<T, const N: usize> ConfigurationBuilder for [T; N]
155where
156 Self: DeserializeOwned + Default,
157 T: ConfigurationBuilder,
158{
159 type Target = [TargetOf<T>; N];
160
161 fn merge(self, other: Self) -> Self {
162 let mut iter = other.into_iter();
163 self.map(|us| us.merge(iter.next().unwrap()))
164 }
165
166 fn try_build(self) -> Result<Self::Target, Error> {
167 self.into_iter()
168 .enumerate()
169 .map(|(index, val)| {
170 val.try_build().map_err(|err| match err {
171 Error::MissingValue(err) => Error::MissingValue(err.prepend(index.to_string())),
172 err => err,
173 })
174 })
175 .collect::<Result<Vec<_>, _>>()?
176 .try_into()
177 .map_err(|vec: Vec<_>| {
178 Error::MissingValue(MissingValue::default().prepend(vec.len().to_string()))
179 })
180 }
181
182 fn contains_non_secret_data(&self) -> Result<bool, UnexpectedSecret> {
183 self.iter()
184 .map(ConfigurationBuilder::contains_non_secret_data)
185 .enumerate()
186 .try_fold(false, |has_secret, (index, val)| {
187 Ok(val.map_err(|err| err.prepend(index.to_string()))? || has_secret)
188 })
189 }
190}
191
192impl<T> Configuration for PhantomData<T> {
196 type Builder = Self;
197}
198
199impl<T> ConfigurationBuilder for PhantomData<T> {
203 type Target = Self;
204
205 fn merge(self, _other: Self) -> Self {
206 self
207 }
208
209 fn try_build(self) -> Result<Self::Target, Error> {
210 Ok(self)
211 }
212
213 fn contains_non_secret_data(&self) -> Result<bool, UnexpectedSecret> {
214 Ok(false)
215 }
216}
217
218impl<T: Configuration> Configuration for Option<T>
221where
222 OptionBuilder<BuilderOf<T>>: DeserializeOwned,
223{
224 type Builder = OptionBuilder<BuilderOf<T>>;
225}
226
227#[derive(Debug, Default, Deserialize, Hash, PartialEq, PartialOrd, Eq, Ord)]
230#[serde(from = "Option<T>")]
231pub enum OptionBuilder<T> {
232 #[default]
236 Unspecified,
237
238 None,
242
243 Some(T),
247}
248
249impl<T> From<Option<T>> for OptionBuilder<T> {
250 fn from(opt: Option<T>) -> Self {
251 opt.map_or(Self::None, |val| Self::Some(val))
252 }
253}
254
255impl<T: ConfigurationBuilder> ConfigurationBuilder for OptionBuilder<T>
256where
257 Self: DeserializeOwned,
258{
259 type Target = Option<TargetOf<T>>;
260
261 fn merge(self, other: Self) -> Self {
262 match (self, other) {
263 (Self::Some(us), Self::Some(other)) => Self::Some(us.merge(other)),
265 (Self::Unspecified, other) => other,
267 (us, _) => us,
273 }
274 }
275
276 fn try_build(self) -> Result<Self::Target, Error> {
277 match self {
278 Self::Unspecified | Self::None => Ok(None),
279 Self::Some(val) => Ok(Some(val.try_build()?)),
280 }
281 }
282
283 fn contains_non_secret_data(&self) -> Result<bool, UnexpectedSecret> {
284 match self {
285 Self::Some(data) => data.contains_non_secret_data(),
286
287 Self::None => Ok(true),
289
290 Self::Unspecified => Ok(false),
291 }
292 }
293}