Repository: TedDriggs/darling (rust)

Issue:
`Option` handling is non-intuitive
**Expectations**:
Based on the phrasing in the documentation and the fact that the crate says it is inspired by serde, `Option` would default to `None` in a derive if the item isn't present.

**Reality**:
Missing items error, and need an explicit `#[darling(default)]` on them. This seems non-obvious, and at the least I think the documentation for `Option` in `FromMeta` should be clarified, as while the current documentation technically describes the behavior accurately, I misinterpreted it as I assumed it would work the same as `syn`.

Pull request:
Add FromMeta::from_none and support implicit Option defaulting
Fixes #161 

Patch:
diff --git a/core/src/codegen/field.rs b/core/src/codegen/field.rs
index 6256b24..72e26ef 100644
--- a/core/src/codegen/field.rs
+++ b/core/src/codegen/field.rs
@@ -191,11 +191,19 @@ impl<'a> ToTokens for CheckMissing<'a> {
     fn to_tokens(&self, tokens: &mut TokenStream) {
         if !self.0.multiple && self.0.default_expression.is_none() {
             let ident = self.0.ident;
+            let ty = self.0.ty;
             let name_in_attr = &self.0.name_in_attr;
 
             tokens.append_all(quote! {
                 if !#ident.0 {
-                    __errors.push(::darling::Error::missing_field(#name_in_attr));
+                    match <#ty as ::darling::FromMeta>::from_none() {
+                        ::darling::export::Some(__type_fallback) => {
+                            #ident.1 = ::darling::export::Some(__type_fallback);
+                        }
+                        ::darling::export::None => {
+                            __errors.push(::darling::Error::missing_field(#name_in_attr))
+                        }
+                    }
                 }
             })
         }
diff --git a/core/src/from_meta.rs b/core/src/from_meta.rs
index 56dcf5f..39c980b 100644
--- a/core/src/from_meta.rs
+++ b/core/src/from_meta.rs
@@ -78,6 +78,20 @@ pub trait FromMeta: Sized {
         .map_err(|e| e.with_span(item))
     }
 
+    /// When a field is omitted from a parent meta-item, `from_none` is used to attempt
+    /// recovery before a missing field error is generated.
+    ///
+    /// **Most types should not override this method.** `darling` already allows field-level
+    /// missing-field recovery using `#[darling(default)]` and `#[darling(default = "...")]`,
+    /// and users who add a `String` field to their `FromMeta`-deriving struct would be surprised
+    /// if they get back `""` instead of a missing field error when that field is omitted.
+    ///
+    /// The primary use-case for this is `Option<T>` fields gracefully handlling absence without
+    /// needing `#[darling(default)]`.
+    fn from_none() -> Option<Self> {
+        None
+    }
+
     /// Create an instance from the presence of the word in the attribute with no
     /// additional options specified.
     fn from_word() -> Result<Self> {
@@ -390,18 +404,30 @@ impl FromMeta for ident_case::RenameRule {
 }
 
 impl<T: FromMeta> FromMeta for Option<T> {
+    fn from_none() -> Option<Self> {
+        Some(None)
+    }
+
     fn from_meta(item: &Meta) -> Result<Self> {
         FromMeta::from_meta(item).map(Some)
     }
 }
 
 impl<T: FromMeta> FromMeta for Box<T> {
+    fn from_none() -> Option<Self> {
+        T::from_none().map(Box::new)
+    }
+
     fn from_meta(item: &Meta) -> Result<Self> {
         FromMeta::from_meta(item).map(Box::new)
     }
 }
 
 impl<T: FromMeta> FromMeta for Result<T> {
+    fn from_none() -> Option<Self> {
+        T::from_none().map(Ok)
+    }
+
     fn from_meta(item: &Meta) -> Result<Self> {
         Ok(FromMeta::from_meta(item))
     }
@@ -418,18 +444,30 @@ impl<T: FromMeta> FromMeta for ::std::result::Result<T, Meta> {
 }
 
 impl<T: FromMeta> FromMeta for Rc<T> {
+    fn from_none() -> Option<Self> {
+        T::from_none().map(Rc::new)
+    }
+
     fn from_meta(item: &Meta) -> Result<Self> {
         FromMeta::from_meta(item).map(Rc::new)
     }
 }
 
 impl<T: FromMeta> FromMeta for Arc<T> {
+    fn from_none() -> Option<Self> {
+        T::from_none().map(Arc::new)
+    }
+
     fn from_meta(item: &Meta) -> Result<Self> {
         FromMeta::from_meta(item).map(Arc::new)
     }
 }
 
 impl<T: FromMeta> FromMeta for RefCell<T> {
+    fn from_none() -> Option<Self> {
+        T::from_none().map(RefCell::new)
+    }
+
     fn from_meta(item: &Meta) -> Result<Self> {
         FromMeta::from_meta(item).map(RefCell::new)
     }
diff --git a/core/src/util/mod.rs b/core/src/util/mod.rs
index 3030eee..d19510a 100644
--- a/core/src/util/mod.rs
+++ b/core/src/util/mod.rs
@@ -41,6 +41,10 @@ impl Deref for Flag {
 }
 
 impl FromMeta for Flag {
+    fn from_none() -> Option<Self> {
+        Some(Flag(None))
+    }
+
     fn from_meta(mi: &syn::Meta) -> Result<Self> {
         FromMeta::from_meta(mi).map(Flag)
     }


Test patch:
diff --git a/tests/defaults.rs b/tests/defaults.rs
index 084a00a..4912e34 100644
--- a/tests/defaults.rs
+++ b/tests/defaults.rs
@@ -121,3 +121,69 @@ mod stacked_defaults {
         assert_eq!(person.name.last, "Doe");
     }
 }
+
+mod implicit_default {
+    use darling::{util::Flag, FromDeriveInput};
+    use syn::parse_quote;
+
+    // No use of `darling(default)` here at all!
+    // This struct will fill in missing fields using FromMeta::from_none.
+    #[derive(FromDeriveInput)]
+    #[darling(attributes(person))]
+    struct Person {
+        first_name: String,
+        last_name: Option<String>,
+        lefty: Flag,
+    }
+
+    #[test]
+    fn missing_fields_fill() {
+        let person = Person::from_derive_input(&parse_quote! {
+            #[person(first_name = "James")]
+            struct Foo;
+        })
+        .unwrap();
+
+        assert_eq!(person.first_name, "James");
+        assert_eq!(person.last_name, None);
+        assert_eq!(person.lefty, false);
+    }
+}
+
+/// Test that a field-level implicit default using FromMeta::from_none is superseded
+/// by the parent declaring `#[darling(default)]`.
+mod overridden_implicit_default {
+    use darling::{util::Flag, FromDeriveInput};
+    use syn::parse_quote;
+
+    #[derive(FromDeriveInput)]
+    #[darling(default, attributes(person))]
+    struct Person {
+        first_name: String,
+        last_name: Option<String>,
+        lefty: Flag,
+    }
+
+    impl Default for Person {
+        fn default() -> Self {
+            Self {
+                first_name: "Jane".into(),
+                last_name: Some("Doe".into()),
+                lefty: Flag::default(),
+            }
+        }
+    }
+
+    #[test]
+    fn fill_missing() {
+        let person = Person::from_derive_input(&parse_quote!(
+            #[person(last_name = "Archer")]
+            struct Foo;
+        ))
+        .unwrap();
+
+        assert_eq!(person.first_name, "Jane");
+        assert_eq!(person.last_name, Some("Archer".into()));
+        assert_eq!(person.lefty, false);
+    }
+}