1use crate::BlockContents;
2use proc_macro2::Span;
3use quote::ToTokens;
4
5/// A `DefaultExpression` can be either explicit or refer to the canonical trait.
6#[derive(Debug, Clone)]
7pub enum DefaultExpression {
8 Explicit(BlockContents),
9 Trait,
10}
11
12impl DefaultExpression {
13 /// Add the crate root path so the default expression can be emitted
14 /// to a `TokenStream`.
15 ///
16 /// This function is needed because the crate root is inherited from the container, so it cannot
17 /// be provided at parse time to [`darling::FromMeta::from_word`] when reading, and [`ToTokens`] does not
18 /// accept any additional parameters, so it annot be provided at emit time.
19 pub fn with_crate_root<'a>(&'a self, crate_root: &'a syn::Path) -> impl 'a + ToTokens {
20 DefaultExpressionWithCrateRoot {
21 crate_root,
22 expr: self,
23 }
24 }
25
26 pub fn span(&self) -> Span {
27 match self {
28 DefaultExpression::Explicit(block) => block.span(),
29 DefaultExpression::Trait => Span::call_site(),
30 }
31 }
32
33 #[cfg(test)]
34 pub fn explicit<I: Into<BlockContents>>(content: I) -> Self {
35 DefaultExpression::Explicit(content.into())
36 }
37}
38
39impl darling::FromMeta for DefaultExpression {
40 fn from_word() -> darling::Result<Self> {
41 Ok(DefaultExpression::Trait)
42 }
43
44 fn from_expr(expr: &syn::Expr) -> darling::Result<Self> {
45 if let syn::Expr::Lit(el: &ExprLit) = expr {
46 if let syn::Lit::Str(_) = el.lit {
47 return Self::from_value(&el.lit);
48 }
49 }
50
51 Ok(Self::Explicit(expr.clone().into()))
52 }
53
54 fn from_value(value: &syn::Lit) -> darling::Result<Self> {
55 Ok(Self::Explicit(BlockContents::from_value(value)?))
56 }
57}
58
59/// Wrapper for `DefaultExpression`
60struct DefaultExpressionWithCrateRoot<'a> {
61 crate_root: &'a syn::Path,
62 expr: &'a DefaultExpression,
63}
64
65impl<'a> ToTokens for DefaultExpressionWithCrateRoot<'a> {
66 fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
67 let crate_root: &'a Path = self.crate_root;
68 match self.expr {
69 DefaultExpression::Explicit(ref block: &BlockContents) => block.to_tokens(tokens),
70 DefaultExpression::Trait => quoteTokenStream!(
71 #crate_root::export::core::default::Default::default()
72 )
73 .to_tokens(tokens),
74 }
75 }
76}
77