From 8a962ab78872874b03fa0c6bfffce458a3ac248e Mon Sep 17 00:00:00 2001 From: Ted Driggs Date: Mon, 11 Apr 2022 09:20:24 -0700 Subject: [PATCH] Use from_none in codegen This removes the need to use #[darling(default)] on options in deriving structs. Fixes #161 --- core/src/codegen/field.rs | 10 +++++- tests/defaults.rs | 66 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+), 1 deletion(-) 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/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, + 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, + 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); + } +}