-
Notifications
You must be signed in to change notification settings - Fork 68
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This allows the `attrs` magic field to have any type, rather than being limited to `Vec<Attribute>`. Fixes #273
- Loading branch information
Showing
21 changed files
with
347 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,107 @@ | ||
use quote::{quote, quote_spanned, ToTokens, TokenStreamExt}; | ||
use syn::spanned::Spanned; | ||
|
||
use crate::options::{AttrsField, ForwardAttrsFilter}; | ||
|
||
#[derive(Default)] | ||
pub struct ForwardAttrs<'a> { | ||
pub filter: Option<&'a ForwardAttrsFilter>, | ||
pub field: Option<&'a AttrsField>, | ||
} | ||
|
||
impl ForwardAttrs<'_> { | ||
/// Check if this will forward any attributes; this requires both that | ||
/// there be a filter which can match some attributes and a field to receive them. | ||
pub fn will_forward_any(&self) -> bool { | ||
if let Some(filter) = self.filter { | ||
!filter.is_empty() && self.field.is_some() | ||
} else { | ||
false | ||
} | ||
} | ||
|
||
/// Get the field declarations to support attribute forwarding | ||
pub fn as_declaration(&self) -> Option<Declaration> { | ||
self.field.map(Declaration) | ||
} | ||
|
||
/// Get the match arms for attribute matching | ||
pub fn as_match_arms(&self) -> MatchArms { | ||
MatchArms(self) | ||
} | ||
|
||
/// Get the statement that will try to transform forwarded attributes into | ||
/// the result expected by the receiver field. | ||
pub fn as_value_populator(&self) -> Option<ValuePopulator> { | ||
self.field.map(ValuePopulator) | ||
} | ||
|
||
/// Get the field initializer for use when building the deriving struct. | ||
pub fn as_initializer(&self) -> Option<Initializer> { | ||
self.field.map(Initializer) | ||
} | ||
} | ||
|
||
pub struct Declaration<'a>(pub &'a AttrsField); | ||
|
||
impl ToTokens for Declaration<'_> { | ||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { | ||
let ident = &self.0.ident; | ||
tokens.append_all(quote! { | ||
let mut __fwd_attrs: ::darling::export::Vec<::darling::export::syn::Attribute> = vec![]; | ||
let mut #ident: ::darling::export::Option<_> = None; | ||
}); | ||
} | ||
} | ||
|
||
pub struct ValuePopulator<'a>(pub &'a AttrsField); | ||
|
||
impl ToTokens for ValuePopulator<'_> { | ||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { | ||
let AttrsField { ident, with } = self.0; | ||
let initializer_expr = match with { | ||
Some(with) => quote_spanned!(with.span()=> __errors.handle(#with(__fwd_attrs))), | ||
None => quote!(::darling::export::Some(__fwd_attrs)), | ||
}; | ||
tokens.append_all(quote!(#ident = #initializer_expr;)); | ||
} | ||
} | ||
|
||
pub struct Initializer<'a>(pub &'a AttrsField); | ||
|
||
impl ToTokens for Initializer<'_> { | ||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { | ||
let ident = &self.0.ident; | ||
tokens.append_all(quote!(#ident: #ident.expect("Errors were already checked"),)); | ||
} | ||
} | ||
|
||
pub struct MatchArms<'a>(&'a ForwardAttrs<'a>); | ||
|
||
impl ToTokens for MatchArms<'_> { | ||
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) { | ||
if !self.0.will_forward_any() { | ||
tokens.append_all(quote!(_ => continue)); | ||
return; | ||
} | ||
|
||
let push_command = quote!(__fwd_attrs.push(__attr.clone())); | ||
|
||
tokens.append_all( | ||
match self | ||
.0 | ||
.filter | ||
.expect("Can only forward attributes if filter is defined") | ||
{ | ||
ForwardAttrsFilter::All => quote!(_ => #push_command), | ||
ForwardAttrsFilter::Only(idents) => { | ||
let names = idents.to_strings(); | ||
quote! { | ||
#(#names)|* => #push_command, | ||
_ => continue, | ||
} | ||
} | ||
}, | ||
); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.