Skip to content

Commit c22b366

Browse files
committed
Move generation of from_word body for unit variants
1 parent d135cdc commit c22b366

File tree

5 files changed

+49
-27
lines changed

5 files changed

+49
-27
lines changed

core/src/codegen/from_meta_impl.rs

Lines changed: 5 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::borrow::Cow;
2+
13
use proc_macro2::TokenStream;
24
use quote::{quote, quote_spanned, ToTokens};
35
use syn::spanned::Spanned;
@@ -8,15 +10,15 @@ use crate::util::Callable;
810

911
pub struct FromMetaImpl<'a> {
1012
pub base: TraitImpl<'a>,
11-
pub from_word: Option<&'a Callable>,
13+
pub from_word: Option<Cow<'a, Callable>>,
1214
pub from_none: Option<&'a Callable>,
1315
}
1416

1517
impl ToTokens for FromMetaImpl<'_> {
1618
fn to_tokens(&self, tokens: &mut TokenStream) {
1719
let base = &self.base;
1820

19-
let from_word = self.from_word.map(|body| {
21+
let from_word = self.from_word.as_ref().map(|body| {
2022
quote_spanned! {body.span()=>
2123
fn from_word() -> ::darling::Result<Self> {
2224
::darling::export::identity::<fn() -> ::darling::Result<Self>>(#body)()
@@ -113,23 +115,6 @@ impl ToTokens for FromMetaImpl<'_> {
113115
}
114116
};
115117

116-
let from_word_method = variants
117-
.iter()
118-
.find_map(|variant| {
119-
if variant.word {
120-
let ty_ident = variant.ty_ident;
121-
let variant_ident = variant.variant_ident;
122-
Some(quote! {
123-
fn from_word() -> ::darling::Result<Self> {
124-
::darling::export::Ok(#ty_ident::#variant_ident)
125-
}
126-
})
127-
} else {
128-
None
129-
}
130-
})
131-
.or(from_word);
132-
133118
let data_variants = variants.iter().map(Variant::as_data_match_arm);
134119

135120
quote!(
@@ -159,7 +144,7 @@ impl ToTokens for FromMetaImpl<'_> {
159144
}
160145
}
161146

162-
#from_word_method
147+
#from_word
163148

164149
#from_none
165150
)

core/src/codegen/variant.rs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,6 @@ pub struct Variant<'a> {
2626
/// Whether or not the variant should be skipped in the generated code.
2727
pub skip: bool,
2828

29-
/// Whether or not the variant should be used to create an instance for
30-
/// `FromMeta::from_word`.
31-
pub word: bool,
32-
3329
pub allow_unknown_fields: bool,
3430
}
3531

core/src/options/from_meta.rs

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1+
use std::borrow::Cow;
2+
13
use proc_macro2::TokenStream;
24
use quote::ToTokens;
5+
use syn::parse_quote;
36

47
use crate::ast::Data;
58
use crate::codegen::FromMetaImpl;
@@ -26,6 +29,29 @@ impl FromMetaOptions {
2629
.parse_attributes(&di.attrs)?
2730
.parse_body(&di.data)
2831
}
32+
33+
/// Get the `from_word` method body, if one exists. This can come from direct use of
34+
/// `#[darling(from_word = ...)]` on the container or from use of `#[darling(word)]` on
35+
/// a unit variant.
36+
fn from_word(&self) -> Option<Cow<'_, Callable>> {
37+
self.from_word.as_ref().map(Cow::Borrowed).or_else(|| {
38+
if let Data::Enum(ref variants) = self.base.data {
39+
// The first variant which has `word` set to `true`.
40+
// This assumes that validation has prevented multiple variants
41+
// from claiming `word`.
42+
let variant = variants
43+
.iter()
44+
.find(|v| v.word.map(|x| *x).unwrap_or_default())?;
45+
let variant_ident = &variant.ident;
46+
let closure: syn::ExprClosure = parse_quote! {
47+
|| ::darling::export::Ok(Self::#variant_ident)
48+
};
49+
Some(Cow::Owned(Callable::from(closure)))
50+
} else {
51+
None
52+
}
53+
})
54+
}
2955
}
3056

3157
impl ParseAttribute for FromMetaOptions {
@@ -109,7 +135,7 @@ impl<'a> From<&'a FromMetaOptions> for FromMetaImpl<'a> {
109135
fn from(v: &'a FromMetaOptions) -> Self {
110136
FromMetaImpl {
111137
base: (&v.base).into(),
112-
from_word: v.from_word.as_ref(),
138+
from_word: v.from_word(),
113139
from_none: v.from_none.as_ref(),
114140
}
115141
}

core/src/options/input_variant.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ use crate::{Error, FromMeta, Result};
88

99
#[derive(Debug, Clone)]
1010
pub struct InputVariant {
11-
ident: syn::Ident,
11+
pub ident: syn::Ident,
1212
attr_name: Option<String>,
1313
data: Fields<InputField>,
1414
skip: Option<bool>,
@@ -30,7 +30,6 @@ impl InputVariant {
3030
.map_or_else(|| Cow::Owned(self.ident.to_string()), Cow::Borrowed),
3131
data: self.data.as_ref().map(InputField::as_codegen_field),
3232
skip: self.skip.unwrap_or_default(),
33-
word: *self.word.unwrap_or_default(),
3433
allow_unknown_fields: self.allow_unknown_fields.unwrap_or_default(),
3534
}
3635
}

core/src/util/callable.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,22 @@ impl AsRef<syn::Expr> for Callable {
2424
}
2525
}
2626

27+
impl From<syn::ExprPath> for Callable {
28+
fn from(value: syn::ExprPath) -> Self {
29+
Self {
30+
call: syn::Expr::Path(value),
31+
}
32+
}
33+
}
34+
35+
impl From<syn::ExprClosure> for Callable {
36+
fn from(value: syn::ExprClosure) -> Self {
37+
Self {
38+
call: syn::Expr::Closure(value),
39+
}
40+
}
41+
}
42+
2743
impl From<Callable> for syn::Expr {
2844
fn from(value: Callable) -> Self {
2945
value.call

0 commit comments

Comments
 (0)