serde_env/
de.rs

1use std::collections::HashSet;
2
3use serde::de::{DeserializeSeed, IntoDeserializer, SeqAccess, Visitor};
4use serde::{de, forward_to_deserialize_any};
5
6use crate::error::Error;
7use crate::value::Node;
8
9/// Deserialize into struct via env.
10///
11/// # Examples
12///
13/// ```
14/// use serde::Deserialize;
15/// use serde_env::from_env;
16///
17/// #[derive(Debug, Deserialize)]
18/// struct Test {
19///     #[cfg(windows)]
20///     #[serde(rename = "userprofile")]
21///     home: String,
22///     #[cfg(not(windows))]
23///     home: String,
24///     #[serde(rename = "path")]
25///     path_renamed: String,
26/// }
27///
28/// let t: Test = from_env().expect("deserialize from env");
29/// println!("{:?}", t);
30/// ```
31pub fn from_env<T>() -> Result<T, Error>
32where
33    T: de::DeserializeOwned,
34{
35    T::deserialize(Deserializer(Node::from_env()))
36}
37/// Deserialize into struct via env with a prefix.
38///
39/// # Examples
40///
41/// ```
42/// use serde::Deserialize;
43/// use serde_env::from_env_with_prefix;
44///
45/// #[derive(Debug, Deserialize, PartialEq)]
46/// struct Test {
47///     home: String,
48///     path: String,
49/// }
50/// temp_env::with_vars(
51///     [
52///         ("TEST_ENV_HOME", Some("/test")),
53///         ("TEST_ENV_PATH", Some("foo:bar")),
54///     ],
55///     || {
56///         let t: Test = from_env_with_prefix("TEST_ENV").expect("deserialize from env");
57///
58///         let result = Test {
59///             home: "/test".to_string(),
60///             path: "foo:bar".to_string(),
61///         };
62///         assert_eq!(t, result);
63///     },
64/// );
65/// ```
66pub fn from_env_with_prefix<T>(prefix: &str) -> Result<T, Error>
67where
68    T: de::DeserializeOwned,
69{
70    T::deserialize(Deserializer(Node::from_env_with_prefix(prefix)))
71}
72
73/// Deserialize into struct via an iterable of `(AsRef<str>, AsRef<str>)`
74/// representing keys and values.
75///
76/// # Examples
77///
78/// ```
79/// use serde::Deserialize;
80/// use serde_env::from_iter;
81///
82/// #[derive(Debug, Deserialize, PartialEq)]
83/// struct Test {
84///     home: String,
85///     path: String,
86/// }
87/// let vars = [
88///     ("HOME", "/test"),
89///     ("PATH", "foo:bar"),
90/// ];
91///
92/// let actual: Test = from_iter(vars).expect("deserialize from iter");
93///
94/// let expected = Test {
95///     home: "/test".to_string(),
96///     path: "foo:bar".to_string(),
97/// };
98///
99/// assert_eq!(actual, expected);
100/// ```
101pub fn from_iter<Iter, S, T>(iter: Iter) -> Result<T, Error>
102where
103    Iter: IntoIterator<Item = (S, S)>,
104    S: AsRef<str>,
105    T: de::DeserializeOwned,
106{
107    T::deserialize(Deserializer(Node::from_iter(iter)))
108}
109
110/// Deserialize into struct via an iterable of `(AsRef<str>, AsRef<str>)`
111/// representing keys and values, with a prefix.
112///
113/// # Examples
114///
115/// ```
116/// use serde::Deserialize;
117/// use serde_env::from_iter_with_prefix;
118///
119/// #[derive(Debug, Deserialize, PartialEq)]
120/// struct Test {
121///     home: String,
122///     path: String,
123/// }
124/// let vars = ([
125///     ("TEST_ENV_HOME", "/test"),
126///     ("TEST_ENV_PATH", "foo:bar"),
127/// ]);
128///
129/// let actual: Test = from_iter_with_prefix(vars, "TEST_ENV").expect("deserialize from iter");
130///
131/// let expected = Test {
132///     home: "/test".to_string(),
133///     path: "foo:bar".to_string(),
134/// };
135///
136/// assert_eq!(actual, expected);
137/// ```
138pub fn from_iter_with_prefix<Iter, S, T>(iter: Iter, prefix: &str) -> Result<T, Error>
139where
140    Iter: IntoIterator<Item = (S, S)>,
141    S: AsRef<str>,
142    T: de::DeserializeOwned,
143{
144    T::deserialize(Deserializer(Node::from_iter_with_prefix(iter, prefix)))
145}
146
147struct Deserializer(Node);
148
149impl<'de> de::Deserializer<'de> for Deserializer {
150    type Error = Error;
151
152    fn deserialize_any<V>(self, _vis: V) -> Result<V::Value, Self::Error>
153    where
154        V: Visitor<'de>,
155    {
156        Err(de::Error::custom("deserialize_any is not supported"))
157    }
158
159    fn deserialize_bool<V>(self, vis: V) -> Result<V::Value, Self::Error>
160    where
161        V: Visitor<'de>,
162    {
163        vis.visit_bool(self.0.value().parse().map_err(Error::new)?)
164    }
165
166    fn deserialize_i8<V>(self, vis: V) -> Result<V::Value, Self::Error>
167    where
168        V: Visitor<'de>,
169    {
170        vis.visit_i8(self.0.value().parse().map_err(Error::new)?)
171    }
172
173    fn deserialize_i16<V>(self, vis: V) -> Result<V::Value, Self::Error>
174    where
175        V: Visitor<'de>,
176    {
177        vis.visit_i16(self.0.value().parse().map_err(Error::new)?)
178    }
179
180    fn deserialize_i32<V>(self, vis: V) -> Result<V::Value, Self::Error>
181    where
182        V: Visitor<'de>,
183    {
184        vis.visit_i32(self.0.value().parse().map_err(Error::new)?)
185    }
186
187    fn deserialize_i64<V>(self, vis: V) -> Result<V::Value, Self::Error>
188    where
189        V: Visitor<'de>,
190    {
191        vis.visit_i64(self.0.value().parse().map_err(Error::new)?)
192    }
193
194    fn deserialize_u8<V>(self, vis: V) -> Result<V::Value, Self::Error>
195    where
196        V: Visitor<'de>,
197    {
198        vis.visit_u8(self.0.value().parse().map_err(Error::new)?)
199    }
200
201    fn deserialize_u16<V>(self, vis: V) -> Result<V::Value, Self::Error>
202    where
203        V: Visitor<'de>,
204    {
205        vis.visit_u16(self.0.value().parse().map_err(Error::new)?)
206    }
207
208    forward_to_deserialize_any! {
209        unit unit_struct
210        tuple_struct ignored_any
211    }
212
213    fn deserialize_u32<V>(self, vis: V) -> Result<V::Value, Self::Error>
214    where
215        V: Visitor<'de>,
216    {
217        vis.visit_u32(self.0.value().parse().map_err(Error::new)?)
218    }
219
220    fn deserialize_u64<V>(self, vis: V) -> Result<V::Value, Self::Error>
221    where
222        V: Visitor<'de>,
223    {
224        vis.visit_u64(self.0.value().parse().map_err(Error::new)?)
225    }
226
227    fn deserialize_f32<V>(self, vis: V) -> Result<V::Value, Self::Error>
228    where
229        V: Visitor<'de>,
230    {
231        vis.visit_f32(self.0.value().parse().map_err(Error::new)?)
232    }
233
234    fn deserialize_f64<V>(self, vis: V) -> Result<V::Value, Self::Error>
235    where
236        V: Visitor<'de>,
237    {
238        vis.visit_f64(self.0.value().parse().map_err(Error::new)?)
239    }
240
241    fn deserialize_char<V>(self, vis: V) -> Result<V::Value, Self::Error>
242    where
243        V: Visitor<'de>,
244    {
245        vis.visit_char(self.0.value().parse().map_err(Error::new)?)
246    }
247
248    fn deserialize_str<V>(self, vis: V) -> Result<V::Value, Self::Error>
249    where
250        V: Visitor<'de>,
251    {
252        vis.visit_str(self.0.value())
253    }
254
255    fn deserialize_string<V>(self, vis: V) -> Result<V::Value, Self::Error>
256    where
257        V: Visitor<'de>,
258    {
259        vis.visit_string(self.0.into_value())
260    }
261
262    fn deserialize_bytes<V>(self, vis: V) -> Result<V::Value, Self::Error>
263    where
264        V: Visitor<'de>,
265    {
266        vis.visit_bytes(self.0.value().as_bytes())
267    }
268
269    fn deserialize_byte_buf<V>(self, vis: V) -> Result<V::Value, Self::Error>
270    where
271        V: Visitor<'de>,
272    {
273        vis.visit_byte_buf(self.0.into_value().into_bytes())
274    }
275
276    fn deserialize_option<V>(self, vis: V) -> Result<V::Value, Self::Error>
277    where
278        V: Visitor<'de>,
279    {
280        if self.0.is_empty() {
281            vis.visit_none()
282        } else {
283            vis.visit_some(Deserializer(self.0))
284        }
285    }
286
287    fn deserialize_newtype_struct<V>(
288        self,
289        _name: &'static str,
290        vis: V,
291    ) -> Result<V::Value, Self::Error>
292    where
293        V: Visitor<'de>,
294    {
295        vis.visit_newtype_struct(Deserializer(self.0))
296    }
297
298    fn deserialize_seq<V>(self, vis: V) -> Result<V::Value, Self::Error>
299    where
300        V: Visitor<'de>,
301    {
302        let elements = self
303            .0
304            .value()
305            .split(',')
306            .map(|v| v.trim().to_string())
307            .filter(|v| !v.is_empty())
308            .collect();
309
310        vis.visit_seq(SeqAccessor::new(elements))
311    }
312
313    fn deserialize_tuple<V>(self, _len: usize, vis: V) -> Result<V::Value, Self::Error>
314    where
315        V: Visitor<'de>,
316    {
317        let elements = self
318            .0
319            .value()
320            .split(',')
321            .map(|v| v.trim().to_string())
322            .collect();
323
324        vis.visit_seq(SeqAccessor::new(elements))
325    }
326
327    fn deserialize_map<V>(self, vis: V) -> Result<V::Value, Self::Error>
328    where
329        V: Visitor<'de>,
330    {
331        let keys = self.0.flatten("");
332        vis.visit_map(MapAccessor::new(keys, self.0))
333    }
334
335    fn deserialize_struct<V>(
336        self,
337        _name: &'static str,
338        fields: &'static [&'static str],
339        vis: V,
340    ) -> Result<V::Value, Self::Error>
341    where
342        V: Visitor<'de>,
343    {
344        let keys = fields.iter().map(|v| v.to_string()).collect();
345
346        vis.visit_map(MapAccessor::new(keys, self.0))
347    }
348
349    fn deserialize_identifier<V>(self, vis: V) -> Result<V::Value, Self::Error>
350    where
351        V: Visitor<'de>,
352    {
353        self.deserialize_string(vis)
354    }
355
356    fn deserialize_enum<V>(
357        self,
358        _name: &'static str,
359        variants: &'static [&'static str],
360        vis: V,
361    ) -> Result<V::Value, Self::Error>
362    where
363        V: Visitor<'de>,
364    {
365        let keys = variants.iter().map(|v| v.to_string()).collect();
366
367        vis.visit_enum(EnumAccessor::new(keys, self.0))
368    }
369}
370
371struct SeqAccessor {
372    elements: std::vec::IntoIter<String>,
373}
374
375impl SeqAccessor {
376    fn new(keys: Vec<String>) -> Self {
377        Self {
378            elements: keys.into_iter(),
379        }
380    }
381}
382
383impl<'de> SeqAccess<'de> for SeqAccessor {
384    type Error = Error;
385
386    fn next_element_seed<T>(&mut self, seed: T) -> Result<Option<T::Value>, Self::Error>
387    where
388        T: DeserializeSeed<'de>,
389    {
390        match self.elements.next() {
391            None => Ok(None),
392            Some(v) => Ok(Some(seed.deserialize(Deserializer(Node::new(v)))?)),
393        }
394    }
395}
396
397struct MapAccessor {
398    last_value: Option<Node>,
399    keys: std::collections::hash_set::IntoIter<String>,
400    node: Node,
401}
402
403impl MapAccessor {
404    fn new(keys: HashSet<String>, node: Node) -> Self {
405        Self {
406            last_value: None,
407            keys: keys.into_iter(),
408            node,
409        }
410    }
411}
412
413impl<'de> de::MapAccess<'de> for MapAccessor {
414    type Error = Error;
415
416    fn next_key_seed<K>(&mut self, seed: K) -> Result<Option<K::Value>, Self::Error>
417    where
418        K: DeserializeSeed<'de>,
419    {
420        debug_assert!(
421            self.last_value.is_none(),
422            "value for the last entry is not deserialized"
423        );
424
425        loop {
426            let key = match self.keys.next() {
427                None => return Ok(None),
428                Some(v) => v,
429            };
430
431            match self.node.get(&key) {
432                // If key is not found inside node, skip it and continue.
433                None => continue,
434                Some(v) => {
435                    self.last_value = Some(v.clone());
436                    return Ok(Some(seed.deserialize(key.into_deserializer())?));
437                }
438            }
439        }
440    }
441
442    fn next_value_seed<V>(&mut self, seed: V) -> Result<V::Value, Self::Error>
443    where
444        V: DeserializeSeed<'de>,
445    {
446        let value = self
447            .last_value
448            .take()
449            .expect("value for current entry is missing");
450
451        seed.deserialize(Deserializer(value))
452    }
453}
454
455struct EnumAccessor {
456    keys: std::vec::IntoIter<String>,
457    node: Node,
458}
459
460impl EnumAccessor {
461    fn new(keys: Vec<String>, node: Node) -> Self {
462        Self {
463            keys: keys.into_iter(),
464            node,
465        }
466    }
467}
468
469impl<'de> de::EnumAccess<'de> for EnumAccessor {
470    type Error = Error;
471    type Variant = VariantAccessor;
472
473    fn variant_seed<V>(mut self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
474    where
475        V: DeserializeSeed<'de>,
476    {
477        let key = self
478            .keys
479            .find(|key| self.node.value() == key)
480            .ok_or_else(|| de::Error::custom("no variant found"))?;
481
482        let variant = VariantAccessor::new(self.node);
483        Ok((seed.deserialize(key.into_deserializer())?, variant))
484    }
485}
486
487struct VariantAccessor {
488    node: Node,
489}
490
491impl VariantAccessor {
492    fn new(node: Node) -> Self {
493        Self { node }
494    }
495}
496
497impl<'de> de::VariantAccess<'de> for VariantAccessor {
498    type Error = Error;
499
500    fn unit_variant(self) -> Result<(), Self::Error> {
501        if self.node.has_children() {
502            return Err(de::Error::custom("variant is not unit"));
503        }
504        Ok(())
505    }
506    fn newtype_variant_seed<T>(self, seed: T) -> Result<T::Value, Self::Error>
507    where
508        T: DeserializeSeed<'de>,
509    {
510        seed.deserialize(Deserializer(self.node))
511    }
512    fn tuple_variant<V>(self, _len: usize, _visitor: V) -> Result<V::Value, Self::Error>
513    where
514        V: Visitor<'de>,
515    {
516        Err(de::Error::custom("tuple variant is not supported"))
517    }
518    fn struct_variant<V>(
519        self,
520        fields: &'static [&'static str],
521        visitor: V,
522    ) -> Result<V::Value, Self::Error>
523    where
524        V: Visitor<'de>,
525    {
526        let keys = fields.iter().map(|v| v.to_string()).collect();
527
528        visitor.visit_map(MapAccessor::new(keys, self.node))
529    }
530}
531
532#[cfg(test)]
533mod tests {
534    use serde::Deserialize;
535    use std::collections::HashMap;
536
537    use super::*;
538
539    #[derive(Deserialize, Default, PartialEq, Debug)]
540    #[serde(default)]
541    struct TestStruct {
542        a: i64,
543        b: bool,
544        c: String,
545        d: EmbedStruct,
546    }
547
548    #[derive(Deserialize, Default, PartialEq, Debug)]
549    #[serde(default)]
550    struct EmbedStruct {
551        aa: f32,
552        bb: String,
553    }
554
555    #[test]
556    fn test_from_env() {
557        temp_env::with_vars(
558            vec![
559                ("A", Some("123")),
560                ("B", Some("true")),
561                ("C", Some("Hello, test")),
562                ("D_AA", Some("1.2")),
563                ("D_BB", Some("Hello, embed")),
564            ],
565            || {
566                let t: TestStruct = from_env().expect("must success");
567                assert_eq!(
568                    t,
569                    TestStruct {
570                        a: 123,
571                        b: true,
572                        c: "Hello, test".to_string(),
573                        d: EmbedStruct {
574                            aa: 1.2,
575                            bb: "Hello, embed".to_string()
576                        }
577                    }
578                )
579            },
580        )
581    }
582
583    /// This test is ported from [softprops/envy](https://github.com/softprops/envy/blob/801d81e7c3e443470e110bf4e34460acba113476/src/lib.rs#L410)
584    #[derive(Deserialize, Debug, PartialEq, Eq)]
585    struct Foo {
586        bar: String,
587        baz: bool,
588        zoom: Option<u16>,
589        doom: Vec<u64>,
590        boom: Vec<String>,
591        #[serde(default = "default_kaboom")]
592        kaboom: u16,
593        #[serde(default)]
594        debug_mode: bool,
595        provided: Option<String>,
596        newtype: CustomNewType,
597        boom_zoom: bool,
598        #[serde(default = "default_bool")]
599        mode_xx: bool,
600    }
601
602    fn default_bool() -> bool {
603        true
604    }
605
606    fn default_kaboom() -> u16 {
607        8080
608    }
609
610    #[derive(Deserialize, Debug, PartialEq, Eq, Default)]
611    struct CustomNewType(u32);
612
613    #[test]
614    fn test_ported_from_envy() {
615        temp_env::with_vars(
616            vec![
617                ("BAR", Some("test")),
618                ("BAZ", Some("true")),
619                ("DOOM", Some("1, 2, 3 ")),
620                // Empty string should result in empty vector.
621                ("BOOM", Some("")),
622                ("SIZE", Some("small")),
623                ("PROVIDED", Some("test")),
624                ("NEWTYPE", Some("42")),
625                ("boom_zoom", Some("true")),
626                ("mode_xx", Some("false")),
627            ],
628            || {
629                let actual: Foo = from_env().expect("must success");
630                assert_eq!(
631                    actual,
632                    Foo {
633                        bar: String::from("test"),
634                        baz: true,
635                        zoom: None,
636                        doom: vec![1, 2, 3],
637                        boom: vec![],
638                        kaboom: 8080,
639                        debug_mode: false,
640                        provided: Some(String::from("test")),
641                        newtype: CustomNewType(42),
642                        boom_zoom: true,
643                        mode_xx: false
644                    }
645                )
646            },
647        )
648    }
649
650    #[derive(Deserialize, PartialEq, Debug)]
651    struct TestStructAlias {
652        #[serde(alias = "meta_log_level")]
653        log_level: String,
654    }
655
656    // We are not support alias now.
657    #[test]
658    #[ignore]
659    fn test_from_env_alias() {
660        temp_env::with_vars(vec![("meta_log_level", Some("DEBUG"))], || {
661            let t: TestStructAlias = from_env().expect("must success");
662            assert_eq!(
663                t,
664                TestStructAlias {
665                    log_level: "DEBUG".to_string()
666                }
667            )
668        })
669    }
670
671    #[derive(Deserialize, PartialEq, Debug)]
672    struct TestStructFlat {
673        meta_log_level: String,
674    }
675
676    #[test]
677    fn test_from_env_flat() {
678        temp_env::with_vars(vec![("meta_log_level", Some("DEBUG"))], || {
679            let t: TestStructFlat = from_env().expect("must success");
680            assert_eq!(
681                t,
682                TestStructFlat {
683                    meta_log_level: "DEBUG".to_string()
684                }
685            )
686        })
687    }
688
689    #[test]
690    fn test_from_env_flat_upper() {
691        temp_env::with_vars(vec![("META_LOG_LEVEL", Some("DEBUG"))], || {
692            let t: TestStructFlat = from_env().expect("must success");
693            assert_eq!(
694                t,
695                TestStructFlat {
696                    meta_log_level: "DEBUG".to_string()
697                }
698            )
699        })
700    }
701
702    #[derive(Deserialize, PartialEq, Debug)]
703    struct TestStructFlatWithDefault {
704        meta_log_level: String,
705    }
706
707    impl Default for TestStructFlatWithDefault {
708        fn default() -> Self {
709            Self {
710                meta_log_level: "INFO".to_string(),
711            }
712        }
713    }
714
715    #[test]
716    fn test_from_env_flat_with_default() {
717        temp_env::with_vars(vec![("meta_log_level", Some("DEBUG"))], || {
718            let t: TestStructFlatWithDefault = from_env().expect("must success");
719            assert_eq!(
720                t,
721                TestStructFlatWithDefault {
722                    meta_log_level: "DEBUG".to_string()
723                }
724            )
725        })
726    }
727
728    #[test]
729    fn test_from_env_flat_upper_with_default() {
730        temp_env::with_vars(vec![("META_LOG_LEVEL", Some("DEBUG"))], || {
731            let t: TestStructFlatWithDefault = from_env().expect("must success");
732            assert_eq!(
733                t,
734                TestStructFlatWithDefault {
735                    meta_log_level: "DEBUG".to_string()
736                }
737            )
738        })
739    }
740
741    #[test]
742    fn test_from_env_as_map() {
743        temp_env::with_vars(vec![("METASRV_LOG_LEVEL", Some("DEBUG"))], || {
744            let t: HashMap<String, String> = from_env().expect("must success");
745            assert_eq!(t["metasrv_log_level"], "DEBUG".to_string())
746        })
747    }
748
749    #[derive(Deserialize, PartialEq, Debug)]
750    struct EnumNewtype {
751        bar: String,
752    }
753
754    #[derive(Deserialize, PartialEq, Debug)]
755    struct ExternallyEnumStruct {
756        foo: ExternallyEnum,
757    }
758
759    #[derive(Deserialize, PartialEq, Debug)]
760    enum ExternallyEnum {
761        X,
762        Y(EnumNewtype),
763        Z { a: i32 },
764    }
765
766    #[test]
767    fn test_from_env_externally_enum() {
768        temp_env::with_vars(vec![("FOO", Some("X"))], || {
769            let t: ExternallyEnumStruct = from_env().expect("must success");
770            assert_eq!(t.foo, ExternallyEnum::X)
771        });
772
773        temp_env::with_vars(vec![("FOO", Some("Y")), ("FOO_BAR", Some("xxx"))], || {
774            let t: ExternallyEnumStruct = from_env().expect("must success");
775            assert_eq!(
776                t.foo,
777                ExternallyEnum::Y(EnumNewtype {
778                    bar: "xxx".to_string()
779                })
780            )
781        });
782
783        temp_env::with_vars(vec![("FOO", Some("Z")), ("FOO_A", Some("1"))], || {
784            let t: ExternallyEnumStruct = from_env().expect("must success");
785            assert_eq!(t.foo, ExternallyEnum::Z { a: 1 })
786        });
787    }
788
789    #[derive(Deserialize, PartialEq, Debug)]
790    struct InternallyEnumStruct {
791        foo: InternallyEnum,
792    }
793
794    #[derive(Deserialize, PartialEq, Debug)]
795    #[serde(tag = "type")]
796    enum InternallyEnum {
797        X,
798        Y(EnumNewtype),
799        Z { a: i32 },
800    }
801
802    // Currently Internally / Adjacently / Untagged enum is not support by the following issues
803    // https://github.com/serde-rs/serde/issues/2187
804    #[test]
805    #[ignore]
806    fn test_from_env_internally_enum() {
807        temp_env::with_vars(vec![("FOO_TYPE", Some("X"))], || {
808            let t: InternallyEnumStruct = from_env().expect("must success");
809            assert_eq!(t.foo, InternallyEnum::X)
810        });
811
812        temp_env::with_vars(
813            vec![("FOO_TYPE", Some("Y")), ("FOO_BAR", Some("xxx"))],
814            || {
815                let t: InternallyEnumStruct = from_env().expect("must success");
816                assert_eq!(
817                    t.foo,
818                    InternallyEnum::Y(EnumNewtype {
819                        bar: "xxx".to_string()
820                    })
821                )
822            },
823        );
824
825        temp_env::with_vars(vec![("FOO_TYPE", Some("Z")), ("FOO_A", Some("1"))], || {
826            let t: InternallyEnumStruct = from_env().expect("must success");
827            assert_eq!(t.foo, InternallyEnum::Z { a: 1 })
828        });
829    }
830
831    #[derive(Deserialize, PartialEq, Debug, Eq)]
832    struct DoubleOptionOuter {
833        inner: Option<DoubleOptionInner>,
834    }
835
836    #[derive(Deserialize, PartialEq, Debug, Eq)]
837    struct DoubleOptionInner {
838        val: Option<u8>,
839    }
840
841    #[test]
842    fn double_option() {
843        temp_env::with_var("INNER_VAL", Some("2"), || {
844            let t: DoubleOptionOuter = from_env().expect("must success");
845            assert_eq!(
846                t,
847                DoubleOptionOuter {
848                    inner: Some(DoubleOptionInner { val: Some(2) })
849                }
850            )
851        })
852    }
853}