Repository: softprops/envy (language: rust)

Issue:
How to deserialize Option<T>
Sorry, if the answer is obvious, but I could not find an example in the documentation nor the tests for this crate.

What should the content of an environment variable be if I want to deserialize a `Option<String>`? A non-existent variable results in `None`, but how to get a `Some(_)`?


Discussion / hints:
Hi there @jonasbb. I was just going to put together a little demo then noticed that was a feature regressed. I'll try to get a fix out soon


Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5875201..1a81ea0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 0.3.1
+
+* fix option support
+
 # 0.3.0
 
 * upgrade to the latest serde (1.0)
diff --git a/Cargo.toml b/Cargo.toml
index c4e133b..1f994c2 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -1,6 +1,6 @@
 [package]
 name = "envy"
-version = "0.3.0"
+version = "0.3.1"
 authors = ["softprops <d.tangren@gmail.com>"]
 description = "deserialize env vars into typesafe structs"
 documentation = "https://softprops.github.io/envy"
@@ -11,3 +11,6 @@ license = "MIT"
 
 [dependencies]
 serde = "1.0"
+
+[dev-dependencies]
+serde_derive = "1.0"
diff --git a/examples/optional.rs b/examples/optional.rs
new file mode 100644
index 0000000..7a64eb4
--- /dev/null
+++ b/examples/optional.rs
@@ -0,0 +1,16 @@
+#[macro_use]
+extern crate serde_derive;
+
+extern crate envy;
+
+#[derive(Deserialize)]
+struct Config {
+    size: Option<u32>,
+}
+
+fn main() {
+    match envy::from_env::<Config>() {
+        Ok(config) => println!("provided config.example {:?}", config.size),
+        Err(err) => println!("error parsing config from env: {}", err),
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
index ea957b7..4042465 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -131,6 +131,12 @@ impl<'de, 'a> de::Deserializer<'de> for Val {
         SeqDeserializer::new(values).deserialize_seq(visitor)
     }
 
+    fn deserialize_option<V>(self, visitor: V) -> Result<V::Value>
+        where V: de::Visitor<'de>
+    {
+        visitor.visit_some(self)
+    }
+
     forward_parsed_values! {
         bool => deserialize_bool,
         u8 => deserialize_u8,
@@ -148,7 +154,7 @@ impl<'de, 'a> de::Deserializer<'de> for Val {
     forward_to_deserialize_any! {
         char str string unit
         bytes byte_buf map unit_struct tuple_struct
-        identifier tuple ignored_any option newtype_struct enum
+        identifier tuple ignored_any newtype_struct enum
         struct
     }
 }


Test patch:
diff --git a/serde-tests/test.rs b/serde-tests/test.rs
index 24ca414..7d3ff2e 100644
--- a/serde-tests/test.rs
+++ b/serde-tests/test.rs
@@ -33,7 +33,8 @@ pub struct Foo {
     #[serde(default)]
     debug_mode: bool,
     #[serde(default)]
-    size: Size
+    size: Size,
+    provided: Option<String>
 }
 
 #[test]
@@ -42,7 +43,8 @@ fn deserialize_from_iter() {
         (String::from("BAR"), String::from("test")),
         (String::from("BAZ"), String::from("true")),
         (String::from("DOOM"), String::from("1,2,3")),
-        (String::from("SIZE"), String::from("small"))
+        (String::from("SIZE"), String::from("small")),
+        (String::from("PROVIDED"), String::from("test"))
     ];
     match envy::from_iter::<_, Foo>(data.into_iter()) {
         Ok(foo) => {
@@ -54,7 +56,8 @@ fn deserialize_from_iter() {
                         doom: vec![1,2,3],
                         kaboom: 8080,
                         debug_mode: false,
-                        size: Size::Small
+                        size: Size::Small,
+                        provided: Some(String::from("test"))
                     }
             )
         },