1use std::collections::BTreeSet;
2
3use crate::error::Error;
4use crate::value::Node;
5use serde::de::{DeserializeSeed, IntoDeserializer, SeqAccess, Visitor};
6use serde::{de, forward_to_deserialize_any};
7
8pub fn from_env<T>() -> Result<T, Error>
31where
32 T: de::DeserializeOwned,
33{
34 T::deserialize(Deserializer(Node::from_env()))
35}
36pub fn from_env_with_prefix<T>(prefix: &str) -> Result<T, Error>
66where
67 T: de::DeserializeOwned,
68{
69 T::deserialize(Deserializer(Node::from_env_with_prefix(prefix)))
70}
71
72pub fn from_iter<Iter, S, T>(iter: Iter) -> Result<T, Error>
101where
102 Iter: IntoIterator<Item = (S, S)>,
103 S: AsRef<str>,
104 T: de::DeserializeOwned,
105{
106 T::deserialize(Deserializer(Node::from_iter(iter)))
107}
108
109pub fn from_iter_with_prefix<Iter, S, T>(iter: Iter, prefix: &str) -> Result<T, Error>
138where
139 Iter: IntoIterator<Item = (S, S)>,
140 S: AsRef<str>,
141 T: de::DeserializeOwned,
142{
143 T::deserialize(Deserializer(Node::from_iter_with_prefix(iter, prefix)))
144}
145
146struct Deserializer(Node);
147
148impl<'de> de::Deserializer<'de> for Deserializer {
149 type Error = Error;
150
151 fn deserialize_any<V>(self, vis: V) -> Result<V::Value, Self::Error>
152 where
153 V: Visitor<'de>,
154 {
155 vis.visit_str(self.0.value())
156 }
157
158 fn deserialize_bool<V>(self, vis: V) -> Result<V::Value, Self::Error>
159 where
160 V: Visitor<'de>,
161 {
162 vis.visit_bool(self.0.value().parse().map_err(Error::new)?)
163 }
164
165 fn deserialize_i8<V>(self, vis: V) -> Result<V::Value, Self::Error>
166 where
167 V: Visitor<'de>,
168 {
169 vis.visit_i8(self.0.value().parse().map_err(Error::new)?)
170 }
171
172 fn deserialize_i16<V>(self, vis: V) -> Result<V::Value, Self::Error>
173 where
174 V: Visitor<'de>,
175 {
176 vis.visit_i16(self.0.value().parse().map_err(Error::new)?)
177 }
178
179 fn deserialize_i32<V>(self, vis: V) -> Result<V::Value, Self::Error>
180 where
181 V: Visitor<'de>,
182 {
183 vis.visit_i32(self.0.value().parse().map_err(Error::new)?)
184 }
185
186 fn deserialize_i64<V>(self, vis: V) -> Result<V::Value, Self::Error>
187 where
188 V: Visitor<'de>,
189 {
190 vis.visit_i64(self.0.value().parse().map_err(Error::new)?)
191 }
192
193 fn deserialize_u8<V>(self, vis: V) -> Result<V::Value, Self::Error>
194 where
195 V: Visitor<'de>,
196 {
197 vis.visit_u8(self.0.value().parse().map_err(Error::new)?)
198 }
199
200 fn deserialize_u16<V>(self, vis: V) -> Result<V::Value, Self::Error>
201 where
202 V: Visitor<'de>,
203 {
204 vis.visit_u16(self.0.value().parse().map_err(Error::new)?)
205 }
206
207 forward_to_deserialize_any! {
208 unit unit_struct
209 tuple_struct ignored_any
210 }
211
212 fn deserialize_u32<V>(self, vis: V) -> Result<V::Value, Self::Error>
213 where
214 V: Visitor<'de>,
215 {
216 vis.visit_u32(self.0.value().parse().map_err(Error::new)?)
217 }
218
219 fn deserialize_u64<V>(self, vis: V) -> Result<V::Value, Self::Error>
220 where
221 V: Visitor<'de>,
222 {
223 vis.visit_u64(self.0.value().parse().map_err(Error::new)?)
224 }
225
226 fn deserialize_f32<V>(self, vis: V) -> Result<V::Value, Self::Error>
227 where
228 V: Visitor<'de>,
229 {
230 vis.visit_f32(self.0.value().parse().map_err(Error::new)?)
231 }
232
233 fn deserialize_f64<V>(self, vis: V) -> Result<V::Value, Self::Error>
234 where
235 V: Visitor<'de>,
236 {
237 vis.visit_f64(self.0.value().parse().map_err(Error::new)?)
238 }
239
240 fn deserialize_char<V>(self, vis: V) -> Result<V::Value, Self::Error>
241 where
242 V: Visitor<'de>,
243 {
244 vis.visit_char(self.0.value().parse().map_err(Error::new)?)
245 }
246
247 fn deserialize_str<V>(self, vis: V) -> Result<V::Value, Self::Error>
248 where
249 V: Visitor<'de>,
250 {
251 vis.visit_str(self.0.value())
252 }
253
254 fn deserialize_string<V>(self, vis: V) -> Result<V::Value, Self::Error>
255 where
256 V: Visitor<'de>,
257 {
258 vis.visit_string(self.0.into_value())
259 }
260
261 fn deserialize_bytes<V>(self, vis: V) -> Result<V::Value, Self::Error>
262 where
263 V: Visitor<'de>,
264 {
265 vis.visit_bytes(self.0.value().as_bytes())
266 }
267
268 fn deserialize_byte_buf<V>(self, vis: V) -> Result<V::Value, Self::Error>
269 where
270 V: Visitor<'de>,
271 {
272 vis.visit_byte_buf(self.0.into_value().into_bytes())
273 }
274
275 fn deserialize_option<V>(self, vis: V) -> Result<V::Value, Self::Error>
276 where
277 V: Visitor<'de>,
278 {
279 if self.0.is_empty() {
280 vis.visit_none()
281 } else {
282 vis.visit_some(Deserializer(self.0))
283 }
284 }
285
286 fn deserialize_newtype_struct<V>(
287 self,
288 _name: &'static str,
289 vis: V,
290 ) -> Result<V::Value, Self::Error>
291 where
292 V: Visitor<'de>,
293 {
294 vis.visit_newtype_struct(Deserializer(self.0))
295 }
296
297 fn deserialize_seq<V>(self, vis: V) -> Result<V::Value, Self::Error>
298 where
299 V: Visitor<'de>,
300 {
301 let elements = self
302 .0
303 .value()
304 .split(',')
305 .map(|v| v.trim().to_string())
306 .filter(|v| !v.is_empty())
307 .collect();
308
309 vis.visit_seq(SeqAccessor::new(elements))
310 }
311
312 fn deserialize_tuple<V>(self, _len: usize, vis: V) -> Result<V::Value, Self::Error>
313 where
314 V: Visitor<'de>,
315 {
316 let elements = self
317 .0
318 .value()
319 .split(',')
320 .map(|v| v.trim().to_string())
321 .collect();
322
323 vis.visit_seq(SeqAccessor::new(elements))
324 }
325
326 fn deserialize_map<V>(self, vis: V) -> Result<V::Value, Self::Error>
327 where
328 V: Visitor<'de>,
329 {
330 let keys = self.0.flatten("");
331 vis.visit_map(MapAccessor::new(keys, self.0))
332 }
333
334 fn deserialize_struct<V>(
335 self,
336 _name: &'static str,
337 fields: &'static [&'static str],
338 vis: V,
339 ) -> Result<V::Value, Self::Error>
340 where
341 V: Visitor<'de>,
342 {
343 let keys = fields.iter().map(|v| v.to_string()).collect();
344
345 vis.visit_map(MapAccessor::new(keys, self.0))
346 }
347
348 fn deserialize_identifier<V>(self, vis: V) -> Result<V::Value, Self::Error>
349 where
350 V: Visitor<'de>,
351 {
352 self.deserialize_string(vis)
353 }
354
355 fn deserialize_enum<V>(
356 self,
357 _name: &'static str,
358 variants: &'static [&'static str],
359 vis: V,
360 ) -> Result<V::Value, Self::Error>
361 where
362 V: Visitor<'de>,
363 {
364 let keys = variants.iter().map(|v| v.to_string()).collect();
365
366 vis.visit_enum(EnumAccessor::new(keys, self.0))
367 }
368}
369
370struct KeyDeserializer {
377 key: String,
378}
379
380impl KeyDeserializer {
381 fn new(key: String) -> Self {
382 Self { key }
383 }
384}
385
386impl<'de> de::Deserializer<'de> for KeyDeserializer {
387 type Error = Error;
388
389 fn deserialize_any<V>(self, vis: V) -> Result<V::Value, Self::Error>
390 where
391 V: Visitor<'de>,
392 {
393 vis.visit_str(&self.key)
394 }
395
396 fn deserialize_str<V>(self, vis: V) -> Result<V::Value, Self::Error>
397 where
398 V: Visitor<'de>,
399 {
400 vis.visit_str(&self.key)
401 }
402
403 fn deserialize_string<V>(self, vis: V) -> Result<V::Value, Self::Error>
404 where
405 V: Visitor<'de>,
406 {
407 vis.visit_string(self.key)
408 }
409
410 fn deserialize_enum<V>(
411 self,
412 _name: &'static str,
413 variants: &'static [&'static str],
414 visitor: V,
415 ) -> Result<V::Value, Self::Error>
416 where
417 V: Visitor<'de>,
418 {
419 for v in variants {
420 if self.key.eq_ignore_ascii_case(v) {
422 return visitor.visit_enum(v.into_deserializer());
423 }
424 }
425 Err(de::Error::unknown_variant(&self.key, variants))
426 }
427
428 forward_to_deserialize_any! {
429 bool i8 i16 i32 i64 u8 u16 u32 u64 f32 f64 char bytes byte_buf
430 option unit unit_struct newtype_struct seq tuple
431 tuple_struct map struct identifier ignored_any
432 }
433}
434
435struct SeqAccessor {
436 elements: std::vec::IntoIter<String>,
437}
438
439impl SeqAccessor {
440 fn new(keys: Vec<String>) -> Self {
441 Self {
442 elements: keys.into_iter(),
443 }
444 }
445}
446
447impl<'de> SeqAccess<'de> for SeqAccessor {
448 type Error = Error;
449
450 fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
451 where
452 T: DeserializeSeed<'de>,
453 {
454 match self.elements.next() {
455 None => Ok(None),
456 Some(v) => Ok(Some(seed.deserialize(Deserializer(Node::new(v)))?)),
457 }
458 }
459}
460
461struct MapAccessor {
462 last_value: Option<Node>,
463 keys: std::collections::btree_set::IntoIter<String>,
464 node: Node,
465}
466
467impl MapAccessor {
468 fn new(keys: BTreeSet<String>, node: Node) -> Self {
469 Self {
470 last_value: None,
471 keys: keys.into_iter(),
472 node,
473 }
474 }
475}
476
477impl<'de> de::MapAccess<'de> for MapAccessor {
478 type Error = Error;
479
480 fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
481 where
482 K: DeserializeSeed<'de>,
483 {
484 debug_assert!(
485 self.last_value.is_none(),
486 "value for the last entry is not deserialized"
487 );
488
489 loop {
490 let key = match self.keys.next() {
491 None => return Ok(None),
492 Some(v) => v,
493 };
494
495 match self.node.get(&key) {
496 None => continue,
498 Some(v) => {
499 self.last_value = Some(v.clone());
500 return Ok(Some(seed.deserialize(KeyDeserializer::new(key))?));
501 }
502 }
503 }
504 }
505
506 fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
507 where
508 V: DeserializeSeed<'de>,
509 {
510 let value = self
511 .last_value
512 .take()
513 .expect("value for current entry is missing");
514
515 seed.deserialize(Deserializer(value))
516 }
517}
518
519struct EnumAccessor {
520 keys: std::vec::IntoIter<String>,
521 node: Node,
522}
523
524impl EnumAccessor {
525 fn new(keys: Vec<String>, node: Node) -> Self {
526 Self {
527 keys: keys.into_iter(),
528 node,
529 }
530 }
531}
532
533impl<'de> de::EnumAccess<'de> for EnumAccessor {
534 type Error = Error;
535 type Variant = VariantAccessor;
536
537 fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
538 where
539 V: DeserializeSeed<'de>,
540 {
541 let key = self
542 .keys
543 .find(|key| self.node.value() == key)
544 .ok_or_else(|| de::Error::custom("no variant found"))?;
545
546 let variant = VariantAccessor::new(self.node);
547 Ok((seed.deserialize(key.into_deserializer())?, variant))
548 }
549}
550
551struct VariantAccessor {
552 node: Node,
553}
554
555impl VariantAccessor {
556 fn new(node: Node) -> Self {
557 Self { node }
558 }
559}
560
561impl<'de> de::VariantAccess<'de> for VariantAccessor {
562 type Error = Error;
563
564 fn unit_variant(self) -> Result<(), Self::Error> {
565 if self.node.has_children() {
566 return Err(de::Error::custom("variant is not unit"));
567 }
568 Ok(())
569 }
570 fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
571 where
572 T: DeserializeSeed<'de>,
573 {
574 seed.deserialize(Deserializer(self.node))
575 }
576 fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
577 where
578 V: Visitor<'de>,
579 {
580 Err(de::Error::custom("tuple variant is not supported"))
581 }
582 fn struct_variant<V>(
583 self,
584 fields: &'static [&'static str],
585 visitor: V,
586 ) -> Result<V::Value, Self::Error>
587 where
588 V: Visitor<'de>,
589 {
590 let keys = fields.iter().map(|v| v.to_string()).collect();
591
592 visitor.visit_map(MapAccessor::new(keys, self.node))
593 }
594}
595
596#[cfg(test)]
597mod tests {
598 use serde::Deserialize;
599 use std::collections::HashMap;
600
601 use super::*;
602
603 #[derive(Deserialize, Default, PartialEq, Debug)]
604 #[serde(default)]
605 struct TestStruct {
606 a: i64,
607 b: bool,
608 c: String,
609 d: EmbedStruct,
610 }
611
612 #[derive(Deserialize, Default, PartialEq, Debug)]
613 #[serde(default)]
614 struct EmbedStruct {
615 aa: f32,
616 bb: String,
617 }
618
619 #[test]
620 fn test_from_env() {
621 temp_env::with_vars(
622 vec![
623 ("A", Some("123")),
624 ("B", Some("true")),
625 ("C", Some("Hello, test")),
626 ("D_AA", Some("1.2")),
627 ("D_BB", Some("Hello, embed")),
628 ],
629 || {
630 let t: TestStruct = from_env().expect("must success");
631 assert_eq!(
632 t,
633 TestStruct {
634 a: 123,
635 b: true,
636 c: "Hello, test".to_string(),
637 d: EmbedStruct {
638 aa: 1.2,
639 bb: "Hello, embed".to_string()
640 }
641 }
642 )
643 },
644 )
645 }
646
647 #[derive(Deserialize, Debug, PartialEq, Eq)]
649 struct Foo {
650 bar: String,
651 baz: bool,
652 zoom: Option<u16>,
653 doom: Vec<u64>,
654 boom: Vec<String>,
655 #[serde(default = "default_kaboom")]
656 kaboom: u16,
657 #[serde(default)]
658 debug_mode: bool,
659 provided: Option<String>,
660 newtype: CustomNewType,
661 boom_zoom: bool,
662 #[serde(default = "default_bool")]
663 mode_xx: bool,
664 }
665
666 fn default_bool() -> bool {
667 true
668 }
669
670 fn default_kaboom() -> u16 {
671 8080
672 }
673
674 #[derive(Deserialize, Debug, PartialEq, Eq, Default)]
675 struct CustomNewType(u32);
676
677 #[test]
678 fn test_ported_from_envy() {
679 temp_env::with_vars(
680 vec![
681 ("BAR", Some("test")),
682 ("BAZ", Some("true")),
683 ("DOOM", Some("1, 2, 3 ")),
684 ("BOOM", Some("")),
686 ("SIZE", Some("small")),
687 ("PROVIDED", Some("test")),
688 ("NEWTYPE", Some("42")),
689 ("boom_zoom", Some("true")),
690 ("mode_xx", Some("false")),
691 ],
692 || {
693 let actual: Foo = from_env().expect("must success");
694 assert_eq!(
695 actual,
696 Foo {
697 bar: String::from("test"),
698 baz: true,
699 zoom: None,
700 doom: vec![1, 2, 3],
701 boom: vec![],
702 kaboom: 8080,
703 debug_mode: false,
704 provided: Some(String::from("test")),
705 newtype: CustomNewType(42),
706 boom_zoom: true,
707 mode_xx: false
708 }
709 )
710 },
711 )
712 }
713
714 #[derive(Deserialize, PartialEq, Debug)]
715 struct TestStructAlias {
716 #[serde(alias = "meta_log_level")]
717 log_level: String,
718 }
719
720 #[test]
722 #[ignore]
723 fn test_from_env_alias() {
724 temp_env::with_vars(vec![("meta_log_level", Some("DEBUG"))], || {
725 let t: TestStructAlias = from_env().expect("must success");
726 assert_eq!(
727 t,
728 TestStructAlias {
729 log_level: "DEBUG".to_string()
730 }
731 )
732 })
733 }
734
735 #[derive(Deserialize, PartialEq, Debug)]
736 struct TestStructFlat {
737 meta_log_level: String,
738 }
739
740 #[test]
741 fn test_from_env_flat() {
742 temp_env::with_vars(vec![("meta_log_level", Some("DEBUG"))], || {
743 let t: TestStructFlat = from_env().expect("must success");
744 assert_eq!(
745 t,
746 TestStructFlat {
747 meta_log_level: "DEBUG".to_string()
748 }
749 )
750 })
751 }
752
753 #[test]
754 fn test_from_env_flat_upper() {
755 temp_env::with_vars(vec![("META_LOG_LEVEL", Some("DEBUG"))], || {
756 let t: TestStructFlat = from_env().expect("must success");
757 assert_eq!(
758 t,
759 TestStructFlat {
760 meta_log_level: "DEBUG".to_string()
761 }
762 )
763 })
764 }
765
766 #[derive(Deserialize, PartialEq, Debug)]
767 struct TestStructFlatWithDefault {
768 meta_log_level: String,
769 }
770
771 impl Default for TestStructFlatWithDefault {
772 fn default() -> Self {
773 Self {
774 meta_log_level: "INFO".to_string(),
775 }
776 }
777 }
778
779 #[test]
780 fn test_from_env_flat_with_default() {
781 temp_env::with_vars(vec![("meta_log_level", Some("DEBUG"))], || {
782 let t: TestStructFlatWithDefault = from_env().expect("must success");
783 assert_eq!(
784 t,
785 TestStructFlatWithDefault {
786 meta_log_level: "DEBUG".to_string()
787 }
788 )
789 })
790 }
791
792 #[test]
793 fn test_from_env_flat_upper_with_default() {
794 temp_env::with_vars(vec![("META_LOG_LEVEL", Some("DEBUG"))], || {
795 let t: TestStructFlatWithDefault = from_env().expect("must success");
796 assert_eq!(
797 t,
798 TestStructFlatWithDefault {
799 meta_log_level: "DEBUG".to_string()
800 }
801 )
802 })
803 }
804
805 #[test]
806 fn test_from_env_as_map() {
807 temp_env::with_vars(vec![("METASRV_LOG_LEVEL", Some("DEBUG"))], || {
808 let t: HashMap<String, String> = from_env().expect("must success");
809 assert_eq!(t["metasrv_log_level"], "DEBUG".to_string())
810 })
811 }
812
813 #[derive(Deserialize, PartialEq, Debug)]
814 struct EnumNewtype {
815 bar: String,
816 }
817
818 #[derive(Deserialize, PartialEq, Debug)]
819 struct ExternallyEnumStruct {
820 foo: ExternallyEnum,
821 }
822
823 #[derive(Deserialize, PartialEq, Debug)]
824 enum ExternallyEnum {
825 X,
826 Y(EnumNewtype),
827 Z { a: i32 },
828 }
829
830 #[test]
831 fn test_from_env_externally_enum() {
832 temp_env::with_vars(vec![("FOO", Some("X"))], || {
833 let t: ExternallyEnumStruct = from_env().expect("must success");
834 assert_eq!(t.foo, ExternallyEnum::X)
835 });
836
837 temp_env::with_vars(vec![("FOO", Some("Y")), ("FOO_BAR", Some("xxx"))], || {
838 let t: ExternallyEnumStruct = from_env().expect("must success");
839 assert_eq!(
840 t.foo,
841 ExternallyEnum::Y(EnumNewtype {
842 bar: "xxx".to_string()
843 })
844 )
845 });
846
847 temp_env::with_vars(vec![("FOO", Some("Z")), ("FOO_A", Some("1"))], || {
848 let t: ExternallyEnumStruct = from_env().expect("must success");
849 assert_eq!(t.foo, ExternallyEnum::Z { a: 1 })
850 });
851 }
852
853 #[derive(Deserialize, PartialEq, Debug)]
854 struct TriggerDeserializeAny {
855 foo: TriggerDeserializeAnyEnum,
856 }
857
858 #[serde_with::serde_as]
859 #[derive(Deserialize, PartialEq, Debug)]
860 #[serde(untagged)]
861 enum TriggerDeserializeAnyEnum {
862 Json(#[serde_as(as = "serde_with::json::JsonString")] Vec<String>),
863 CommaSeparated(
864 #[serde_as(
865 deserialize_as = "serde_with::StringWithSeparator<serde_with::formats::CommaSeparator, String>"
866 )]
867 Vec<String>,
868 ),
869 NonJSON(Vec<String>),
870 }
871
872 #[test]
873 fn test_from_env_deserialize_any() {
874 temp_env::with_vars(vec![("FOO", Some("X"))], || {
875 let t: TriggerDeserializeAny = from_env().expect("must success");
876 assert_eq!(
877 t.foo,
878 TriggerDeserializeAnyEnum::CommaSeparated(vec!["X".to_string()])
879 )
880 });
881
882 temp_env::with_vars(vec![("FOO", Some("X,Y"))], || {
883 let t: TriggerDeserializeAny = from_env().expect("must success");
884 assert_eq!(
885 t.foo,
886 TriggerDeserializeAnyEnum::CommaSeparated(vec!["X".to_string(), "Y".to_string()])
887 )
888 });
889
890 temp_env::with_vars(vec![("FOO", Some("[\"X\",\"Y\"]"))], || {
891 let t: TriggerDeserializeAny = from_env().expect("must success");
892 assert_eq!(
893 t.foo,
894 TriggerDeserializeAnyEnum::Json(vec!["X".to_string(), "Y".to_string()])
895 )
896 });
897 }
898
899 #[derive(Deserialize, PartialEq, Debug)]
900 struct InternallyEnumStruct {
901 foo: InternallyEnum,
902 }
903
904 #[derive(Deserialize, PartialEq, Debug)]
905 #[serde(tag = "type")]
906 enum InternallyEnum {
907 X,
908 Y(EnumNewtype),
909 Z { a: i32 },
910 }
911
912 #[test]
915 #[ignore]
916 fn test_from_env_internally_enum() {
917 temp_env::with_vars(vec![("FOO_TYPE", Some("X"))], || {
918 let t: InternallyEnumStruct = from_env().expect("must success");
919 assert_eq!(t.foo, InternallyEnum::X)
920 });
921
922 temp_env::with_vars(
923 vec![("FOO_TYPE", Some("Y")), ("FOO_BAR", Some("xxx"))],
924 || {
925 let t: InternallyEnumStruct = from_env().expect("must success");
926 assert_eq!(
927 t.foo,
928 InternallyEnum::Y(EnumNewtype {
929 bar: "xxx".to_string()
930 })
931 )
932 },
933 );
934
935 temp_env::with_vars(vec![("FOO_TYPE", Some("Z")), ("FOO_A", Some("1"))], || {
936 let t: InternallyEnumStruct = from_env().expect("must success");
937 assert_eq!(t.foo, InternallyEnum::Z { a: 1 })
938 });
939 }
940
941 #[derive(Deserialize, PartialEq, Debug, Eq)]
942 struct DoubleOptionOuter {
943 inner: Option<DoubleOptionInner>,
944 }
945
946 #[derive(Deserialize, PartialEq, Debug, Eq)]
947 struct DoubleOptionInner {
948 val: Option<u8>,
949 }
950
951 #[test]
952 fn double_option() {
953 temp_env::with_var("INNER_VAL", Some("2"), || {
954 let t: DoubleOptionOuter = from_env().expect("must success");
955 assert_eq!(
956 t,
957 DoubleOptionOuter {
958 inner: Some(DoubleOptionInner { val: Some(2) })
959 }
960 )
961 })
962 }
963
964 #[test]
965 fn inner_mapping_with_enum_keys() {
966 #[derive(Debug, Deserialize, Eq, Hash, PartialEq)]
967 enum MappingKey {
968 Option1,
969 Option2,
970 }
971 #[derive(Debug, Deserialize, Eq, PartialEq)]
972 struct Mapping {
973 val: HashMap<MappingKey, String>,
974 }
975
976 let env = vec![("VAL_OPTION1", "FOO"), ("VAL_OPTION2", "BAR")];
977 let t: Mapping = from_iter(env).expect("must succeed");
978 assert_eq!(
979 t,
980 Mapping {
981 val: HashMap::from_iter(vec![
982 (MappingKey::Option1, "FOO".to_string()),
983 (MappingKey::Option2, "BAR".to_string())
984 ])
985 }
986 );
987 }
988
989 #[test]
990 fn enum_with_unused_envs() {
991 temp_env::with_vars(vec![("FOO", Some("X")), ("FOO_Z_A", Some("20"))], || {
992 let t: ExternallyEnumStruct = from_env().expect("must success");
993 assert_eq!(t.foo, ExternallyEnum::X)
994 });
995
996 temp_env::with_vars(
997 vec![
998 ("FOO", Some("Y")),
999 ("FOO_A", Some("20")),
1000 ("FOO_BAR", Some("test")),
1001 ],
1002 || {
1003 let t: ExternallyEnumStruct = from_env().expect("must success");
1004 assert_eq!(
1005 t.foo,
1006 ExternallyEnum::Y(EnumNewtype {
1007 bar: "test".to_string()
1008 })
1009 )
1010 },
1011 );
1012 }
1013
1014 }