• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use proc_macro2::{Span, TokenStream};
2 use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
3 use syn::{spanned::Spanned, Ident, Path};
4 
5 /// This will be in scope during struct initialization after option parsing.
6 const DEFAULT_STRUCT_NAME: &str = "__default";
7 
8 /// The fallback value for a field or container.
9 #[derive(Debug, Clone)]
10 pub enum DefaultExpression<'a> {
11     /// Only valid on fields, `Inherit` indicates that the value should be taken from a pre-constructed
12     /// fallback object. The value in the variant is the ident of the field.
13     Inherit(&'a Ident),
14     Explicit(&'a Path),
15     Trait {
16         span: Span,
17     },
18 }
19 
20 impl<'a> DefaultExpression<'a> {
as_declaration(&'a self) -> DefaultDeclaration<'a>21     pub fn as_declaration(&'a self) -> DefaultDeclaration<'a> {
22         DefaultDeclaration(self)
23     }
24 }
25 
26 impl<'a> ToTokens for DefaultExpression<'a> {
to_tokens(&self, tokens: &mut TokenStream)27     fn to_tokens(&self, tokens: &mut TokenStream) {
28         tokens.append_all(match *self {
29             DefaultExpression::Inherit(ident) => {
30                 let dsn = Ident::new(DEFAULT_STRUCT_NAME, ::proc_macro2::Span::call_site());
31                 quote!(#dsn.#ident)
32             }
33             DefaultExpression::Explicit(path) => {
34                 // Use quote_spanned to properly set the span of the parentheses
35                 quote_spanned!(path.span()=>#path())
36             }
37             DefaultExpression::Trait { span } => {
38                 quote_spanned!(span=> ::darling::export::Default::default())
39             }
40         });
41     }
42 }
43 
44 /// Used only by containers, this wrapper type generates code to declare the fallback instance.
45 pub struct DefaultDeclaration<'a>(&'a DefaultExpression<'a>);
46 
47 impl<'a> ToTokens for DefaultDeclaration<'a> {
to_tokens(&self, tokens: &mut TokenStream)48     fn to_tokens(&self, tokens: &mut TokenStream) {
49         let name = Ident::new(DEFAULT_STRUCT_NAME, ::proc_macro2::Span::call_site());
50         let expr = self.0;
51         tokens.append_all(quote!(let #name: Self = #expr;));
52     }
53 }
54