1use serde::de::{
61 self,
62 value::{MapDeserializer, SeqDeserializer},
63 IntoDeserializer,
64};
65use std::{
66 borrow::Cow,
67 env,
68 iter::{empty, IntoIterator},
69};
70
71mod error;
73pub use crate::error::Error;
74
75pub type Result<T> = std::result::Result<T, Error>;
77
78struct Vars<Iter>(Iter)
79where
80 Iter: IntoIterator<Item = (String, String)>;
81
82struct Val(String, String);
83
84impl<'de> IntoDeserializer<'de, Error> for Val {
85 type Deserializer = Self;
86
87 fn into_deserializer(self) -> Self::Deserializer {
88 self
89 }
90}
91
92struct VarName(String);
93
94impl<'de> IntoDeserializer<'de, Error> for VarName {
95 type Deserializer = Self;
96
97 fn into_deserializer(self) -> Self::Deserializer {
98 self
99 }
100}
101
102impl<Iter: Iterator<Item = (String, String)>> Iterator for Vars<Iter> {
103 type Item = (VarName, Val);
104
105 fn next(&mut self) -> Option<Self::Item> {
106 self.0
107 .next()
108 .map(|(k, v)| (VarName(k.to_lowercase()), Val(k, v)))
109 }
110}
111
112macro_rules! forward_parsed_values {
113 ($($ty:ident => $method:ident,)*) => {
114 $(
115 fn $method<V>(self, visitor: V) -> Result<V::Value>
116 where V: de::Visitor<'de>
117 {
118 match self.1.parse::<$ty>() {
119 Ok(val) => val.into_deserializer().$method(visitor),
120 Err(e) => Err(de::Error::custom(format_args!("{} while parsing value '{}' provided by {}", e, self.1, self.0)))
121 }
122 }
123 )*
124 }
125}
126
127impl<'de> de::Deserializer<'de> for Val {
128 type Error = Error;
129 fn deserialize_any<V>(
130 self,
131 visitor: V,
132 ) -> Result<V::Value>
133 where
134 V: de::Visitor<'de>,
135 {
136 self.1.into_deserializer().deserialize_any(visitor)
137 }
138
139 fn deserialize_seq<V>(
140 self,
141 visitor: V,
142 ) -> Result<V::Value>
143 where
144 V: de::Visitor<'de>,
145 {
146 if self.1.is_empty() {
151 SeqDeserializer::new(empty::<Val>()).deserialize_seq(visitor)
152 } else {
153 let values = self.1.split(',').map(|v| Val(self.0.clone(), v.to_owned()));
154 SeqDeserializer::new(values).deserialize_seq(visitor)
155 }
156 }
157
158 fn deserialize_option<V>(
159 self,
160 visitor: V,
161 ) -> Result<V::Value>
162 where
163 V: de::Visitor<'de>,
164 {
165 visitor.visit_some(self)
166 }
167
168 forward_parsed_values! {
169 bool => deserialize_bool,
170 u8 => deserialize_u8,
171 u16 => deserialize_u16,
172 u32 => deserialize_u32,
173 u64 => deserialize_u64,
174 i8 => deserialize_i8,
175 i16 => deserialize_i16,
176 i32 => deserialize_i32,
177 i64 => deserialize_i64,
178 f32 => deserialize_f32,
179 f64 => deserialize_f64,
180 }
181
182 #[inline]
183 fn deserialize_newtype_struct<V>(
184 self,
185 _: &'static str,
186 visitor: V,
187 ) -> Result<V::Value>
188 where
189 V: serde::de::Visitor<'de>,
190 {
191 visitor.visit_newtype_struct(self)
192 }
193
194 fn deserialize_enum<V>(
195 self,
196 _name: &'static str,
197 _variants: &'static [&'static str],
198 visitor: V,
199 ) -> Result<V::Value>
200 where
201 V: de::Visitor<'de>,
202 {
203 visitor.visit_enum(self.1.into_deserializer())
204 }
205
206 serde::forward_to_deserialize_any! {
207 char str string unit
208 bytes byte_buf map unit_struct tuple_struct
209 identifier tuple ignored_any
210 struct
211 }
212}
213
214impl<'de> de::Deserializer<'de> for VarName {
215 type Error = Error;
216 fn deserialize_any<V>(
217 self,
218 visitor: V,
219 ) -> Result<V::Value>
220 where
221 V: de::Visitor<'de>,
222 {
223 self.0.into_deserializer().deserialize_any(visitor)
224 }
225
226 #[inline]
227 fn deserialize_newtype_struct<V>(
228 self,
229 _: &'static str,
230 visitor: V,
231 ) -> Result<V::Value>
232 where
233 V: serde::de::Visitor<'de>,
234 {
235 visitor.visit_newtype_struct(self)
236 }
237
238 serde::forward_to_deserialize_any! {
239 char str string unit seq option
240 bytes byte_buf map unit_struct tuple_struct
241 identifier tuple ignored_any enum
242 struct bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64
243 }
244}
245
246struct Deserializer<'de, Iter: Iterator<Item = (String, String)>> {
248 inner: MapDeserializer<'de, Vars<Iter>, Error>,
249}
250
251impl<'de, Iter: Iterator<Item = (String, String)>> Deserializer<'de, Iter> {
252 fn new(vars: Iter) -> Self {
253 Deserializer {
254 inner: MapDeserializer::new(Vars(vars)),
255 }
256 }
257}
258
259impl<'de, Iter: Iterator<Item = (String, String)>> de::Deserializer<'de>
260 for Deserializer<'de, Iter>
261{
262 type Error = Error;
263 fn deserialize_any<V>(
264 self,
265 visitor: V,
266 ) -> Result<V::Value>
267 where
268 V: de::Visitor<'de>,
269 {
270 self.deserialize_map(visitor)
271 }
272
273 fn deserialize_map<V>(
274 self,
275 visitor: V,
276 ) -> Result<V::Value>
277 where
278 V: de::Visitor<'de>,
279 {
280 visitor.visit_map(self.inner)
281 }
282
283 serde::forward_to_deserialize_any! {
284 bool u8 u16 u32 u64 i8 i16 i32 i64 f32 f64 char str string unit seq
285 bytes byte_buf unit_struct tuple_struct
286 identifier tuple ignored_any option newtype_struct enum
287 struct
288 }
289}
290
291pub fn from_env<T>() -> Result<T>
293where
294 T: de::DeserializeOwned,
295{
296 from_iter(env::vars())
297}
298
299pub fn from_iter<Iter, T>(iter: Iter) -> Result<T>
302where
303 T: de::DeserializeOwned,
304 Iter: IntoIterator<Item = (String, String)>,
305{
306 T::deserialize(Deserializer::new(iter.into_iter()))
307}
308
309pub struct Prefixed<'a>(Cow<'a, str>);
313
314impl<'a> Prefixed<'a> {
315 pub fn from_env<T>(&self) -> Result<T>
317 where
318 T: de::DeserializeOwned,
319 {
320 self.from_iter(env::vars())
321 }
322
323 pub fn from_iter<Iter, T>(
325 &self,
326 iter: Iter,
327 ) -> Result<T>
328 where
329 T: de::DeserializeOwned,
330 Iter: IntoIterator<Item = (String, String)>,
331 {
332 crate::from_iter(iter.into_iter().filter_map(|(k, v)| {
333 if k.starts_with(self.0.as_ref()) {
334 Some((k.trim_start_matches(self.0.as_ref()).to_owned(), v))
335 } else {
336 None
337 }
338 }))
339 }
340}
341
342pub fn prefixed<'a, C>(prefix: C) -> Prefixed<'a>
365where
366 C: Into<Cow<'a, str>>,
367{
368 Prefixed(prefix.into())
369}
370
371#[cfg(test)]
372mod tests {
373 use super::*;
374 use serde::Deserialize;
375 use std::collections::HashMap;
376
377 #[derive(Deserialize, Debug, PartialEq)]
378 #[serde(rename_all = "lowercase")]
379 pub enum Size {
380 Small,
381 Medium,
382 Large,
383 }
384
385 impl Default for Size {
386 fn default() -> Size {
387 Size::Medium
388 }
389 }
390
391 pub fn default_kaboom() -> u16 {
392 8080
393 }
394
395 #[derive(Deserialize, Debug, PartialEq)]
396 pub struct CustomNewType(u32);
397
398 #[derive(Deserialize, Debug, PartialEq)]
399 pub struct Foo {
400 bar: String,
401 baz: bool,
402 zoom: Option<u16>,
403 doom: Vec<u64>,
404 boom: Vec<String>,
405 #[serde(default = "default_kaboom")]
406 kaboom: u16,
407 #[serde(default)]
408 debug_mode: bool,
409 #[serde(default)]
410 size: Size,
411 provided: Option<String>,
412 newtype: CustomNewType,
413 }
414
415 #[test]
416 fn deserialize_from_iter() {
417 let data = vec![
418 (String::from("BAR"), String::from("test")),
419 (String::from("BAZ"), String::from("true")),
420 (String::from("DOOM"), String::from("1,2,3")),
421 (String::from("BOOM"), String::from("")),
423 (String::from("SIZE"), String::from("small")),
424 (String::from("PROVIDED"), String::from("test")),
425 (String::from("NEWTYPE"), String::from("42")),
426 ];
427 match from_iter::<_, Foo>(data) {
428 Ok(actual) => assert_eq!(
429 actual,
430 Foo {
431 bar: String::from("test"),
432 baz: true,
433 zoom: None,
434 doom: vec![1, 2, 3],
435 boom: vec![],
436 kaboom: 8080,
437 debug_mode: false,
438 size: Size::Small,
439 provided: Some(String::from("test")),
440 newtype: CustomNewType(42)
441 }
442 ),
443 Err(e) => panic!("{:#?}", e),
444 }
445 }
446
447 #[test]
448 fn fails_with_missing_value() {
449 let data = vec![
450 (String::from("BAR"), String::from("test")),
451 (String::from("BAZ"), String::from("true")),
452 ];
453 match from_iter::<_, Foo>(data) {
454 Ok(_) => panic!("expected failure"),
455 Err(e) => assert_eq!(e, Error::MissingValue("doom")),
456 }
457 }
458
459 #[test]
460 fn fails_with_invalid_type() {
461 let data = vec![
462 (String::from("BAR"), String::from("test")),
463 (String::from("BAZ"), String::from("notabool")),
464 (String::from("DOOM"), String::from("1,2,3")),
465 ];
466 match from_iter::<_, Foo>(data) {
467 Ok(_) => panic!("expected failure"),
468 Err(e) => assert_eq!(
469 e,
470 Error::Custom(String::from("provided string was not `true` or `false` while parsing value \'notabool\' provided by BAZ"))
471 ),
472 }
473 }
474
475 #[test]
476 fn deserializes_from_prefixed_fieldnames() {
477 let data = vec![
478 (String::from("APP_BAR"), String::from("test")),
479 (String::from("APP_BAZ"), String::from("true")),
480 (String::from("APP_DOOM"), String::from("")),
481 (String::from("APP_BOOM"), String::from("4,5")),
482 (String::from("APP_SIZE"), String::from("small")),
483 (String::from("APP_PROVIDED"), String::from("test")),
484 (String::from("APP_NEWTYPE"), String::from("42")),
485 ];
486 match prefixed("APP_").from_iter::<_, Foo>(data) {
487 Ok(actual) => assert_eq!(
488 actual,
489 Foo {
490 bar: String::from("test"),
491 baz: true,
492 zoom: None,
493 doom: vec![],
494 boom: vec!["4".to_string(), "5".to_string()],
495 kaboom: 8080,
496 debug_mode: false,
497 size: Size::Small,
498 provided: Some(String::from("test")),
499 newtype: CustomNewType(42)
500 }
501 ),
502 Err(e) => panic!("{:#?}", e),
503 }
504 }
505
506 #[test]
507 fn prefixed_strips_prefixes() {
508 let mut expected = HashMap::new();
509 expected.insert("foo".to_string(), "bar".to_string());
510 assert_eq!(
511 prefixed("PRE_").from_iter(vec![("PRE_FOO".to_string(), "bar".to_string())]),
512 Ok(expected)
513 );
514 }
515
516 #[test]
517 fn prefixed_doesnt_parse_non_prefixed() {
518 let mut expected = HashMap::new();
519 expected.insert("foo".to_string(), 12);
520 assert_eq!(
521 prefixed("PRE_").from_iter(vec![
522 ("FOO".to_string(), "asd".to_string()),
523 ("PRE_FOO".to_string(), "12".to_string())
524 ]),
525 Ok(expected)
526 );
527 }
528}