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