1use proc_macro2::{Span, TokenStream};
2use quote::{quote, quote_spanned, ToTokens, TokenStreamExt};
3use syn::{spanned::Spanned, Ident, Path};
4
5/// This will be in scope during struct initialization after option parsing.
6const DEFAULT_STRUCT_NAME: &str = "__default";
7
8/// The fallback value for a field or container.
9#[derive(Debug, Clone)]
10pub 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
20impl<'a> DefaultExpression<'a> {
21 pub fn as_declaration(&'a self) -> DefaultDeclaration<'a> {
22 DefaultDeclaration(self)
23 }
24}
25
26impl<'a> ToTokens for DefaultExpression<'a> {
27 fn to_tokens(&self, tokens: &mut TokenStream) {
28 tokens.append_all(iter:match *self {
29 DefaultExpression::Inherit(ident: &Ident) => {
30 let dsn: Ident = Ident::new(DEFAULT_STRUCT_NAME, ::proc_macro2::Span::call_site());
31 quote!(#dsn.#ident)
32 }
33 DefaultExpression::Explicit(path: &Path) => {
34 // Use quote_spanned to properly set the span of the parentheses
35 quote_spanned!(path.span()=>#path())
36 }
37 DefaultExpression::Trait { span: 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.
45pub struct DefaultDeclaration<'a>(&'a DefaultExpression<'a>);
46
47impl<'a> ToTokens for DefaultDeclaration<'a> {
48 fn to_tokens(&self, tokens: &mut TokenStream) {
49 let name: Ident = Ident::new(DEFAULT_STRUCT_NAME, ::proc_macro2::Span::call_site());
50 let expr: &DefaultExpression<'_> = self.0;
51 tokens.append_all(iter:quote!(let #name: Self = #expr;));
52 }
53}
54