Skip to main content

serde_env/
de.rs

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
8/// Deserialize into struct via env.
9///
10/// # Examples
11///
12/// ```
13/// use serde::Deserialize;
14/// use serde_env::from_env;
15///
16/// #[derive(Debug, Deserialize)]
17/// struct Test {
18///     #[cfg(windows)]
19///     #[serde(rename = "userprofile")]
20///     home: String,
21///     #[cfg(not(windows))]
22///     home: String,
23///     #[serde(rename = "path")]
24///     path_renamed: String,
25/// }
26///
27/// let t: Test = from_env().expect("deserialize from env");
28/// println!("{:?}", t);
29/// ```
30pub fn from_env<T>() -> Result<T, Error>
31where
32    T: de::DeserializeOwned,
33{
34    T::deserialize(Deserializer(Node::from_env()))
35}
36/// Deserialize into struct via env with a prefix.
37///
38/// # Examples
39///
40/// ```
41/// use serde::Deserialize;
42/// use serde_env::from_env_with_prefix;
43///
44/// #[derive(Debug, Deserialize, PartialEq)]
45/// struct Test {
46///     home: String,
47///     path: String,
48/// }
49/// temp_env::with_vars(
50///     [
51///         ("TEST_ENV_HOME", Some("/test")),
52///         ("TEST_ENV_PATH", Some("foo:bar")),
53///     ],
54///     || {
55///         let t: Test = from_env_with_prefix("TEST_ENV").expect("deserialize from env");
56///
57///         let result = Test {
58///             home: "/test".to_string(),
59///             path: "foo:bar".to_string(),
60///         };
61///         assert_eq!(t, result);
62///     },
63/// );
64/// ```
65pub 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
72/// Deserialize into struct via an iterable of `(AsRef<str>, AsRef<str>)`
73/// representing keys and values.
74///
75/// # Examples
76///
77/// ```
78/// use serde::Deserialize;
79/// use serde_env::from_iter;
80///
81/// #[derive(Debug, Deserialize, PartialEq)]
82/// struct Test {
83///     home: String,
84///     path: String,
85/// }
86/// let vars = [
87///     ("HOME", "/test"),
88///     ("PATH", "foo:bar"),
89/// ];
90///
91/// let actual: Test = from_iter(vars).expect("deserialize from iter");
92///
93/// let expected = Test {
94///     home: "/test".to_string(),
95///     path: "foo:bar".to_string(),
96/// };
97///
98/// assert_eq!(actual, expected);
99/// ```
100pub 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
109/// Deserialize into struct via an iterable of `(AsRef<str>, AsRef<str>)`
110/// representing keys and values, with a prefix.
111///
112/// # Examples
113///
114/// ```
115/// use serde::Deserialize;
116/// use serde_env::from_iter_with_prefix;
117///
118/// #[derive(Debug, Deserialize, PartialEq)]
119/// struct Test {
120///     home: String,
121///     path: String,
122/// }
123/// let vars = ([
124///     ("TEST_ENV_HOME", "/test"),
125///     ("TEST_ENV_PATH", "foo:bar"),
126/// ]);
127///
128/// let actual: Test = from_iter_with_prefix(vars, "TEST_ENV").expect("deserialize from iter");
129///
130/// let expected = Test {
131///     home: "/test".to_string(),
132///     path: "foo:bar".to_string(),
133/// };
134///
135/// assert_eq!(actual, expected);
136/// ```
137pub 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
370/// KeyDeserializer is used to deserialize key of a map/enum/struct.
371///
372/// It's similar to `StringDeserializer`, but only used for key deserialization in serde-env where:
373///
374/// - Key is case insensitive: `PATH`, `Path`, `path`, `PatH` all map to the same key.
375/// - Key is prefix based: Key could be adapted based on the deserialize target itself.
376struct 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            // Return the enum variant if it matches the key.
421            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                // If key is not found inside node, skip it and continue.
497                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    /// This test is ported from [softprops/envy](https://github.com/softprops/envy/blob/801d81e7c3e443470e110bf4e34460acba113476/src/lib.rs#L410)
648    #[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                // Empty string should result in empty vector.
685                ("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    // We are not support alias now.
721    #[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    // Currently Internally / Adjacently / Untagged enum is not support by the following issues
913    // https://github.com/serde-rs/serde/issues/2187
914    #[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    // TODO: not supported yet, refer to https://github.com/Xuanwo/serde-env/issues/49
1015    //
1016    // #[test]
1017    // fn double_inner_mapping_with_enum_keys() {
1018    //     #[derive(Debug, Deserialize, Eq, Hash, PartialEq)]
1019    //     #[serde(rename_all = "lowercase")]
1020    //     enum MappingKey {
1021    //         Option1,
1022    //         Option2,
1023    //     }
1024    //
1025    //     #[derive(Debug, Deserialize, Eq, Hash, PartialEq)]
1026    //     #[serde(rename_all = "lowercase")]
1027    //     enum MappingKey2 {
1028    //         Inner1,
1029    //         Inner2,
1030    //     }
1031    //
1032    //     #[derive(Debug, Deserialize, Eq, PartialEq)]
1033    //     struct Mapping {
1034    //         val: HashMap<MappingKey, HashMap<MappingKey2, String>>,
1035    //     }
1036    //
1037    //     let env = vec![("VAL_OPTION1_INNER2", "FOO"), ("VAL_OPTION2_INNER1", "BAR")];
1038    //     let t: Mapping = from_iter(env).expect("must succeed");
1039    //     assert_eq!(
1040    //         t,
1041    //         Mapping {
1042    //             val: HashMap::from_iter(vec![
1043    //                 (
1044    //                     MappingKey::Option1,
1045    //                     HashMap::from_iter(vec![(MappingKey2::Inner2, "FOO".to_string())])
1046    //                 ),
1047    //                 (
1048    //                     MappingKey::Option2,
1049    //                     HashMap::from_iter(vec![(MappingKey2::Inner1, "BAR".to_string())])
1050    //                 ),
1051    //             ])
1052    //         }
1053    //     );
1054    // }
1055}