1 | use crate::BlockContents; |
2 | use proc_macro2::Span; |
3 | use quote::ToTokens; |
4 | |
5 | /// A `DefaultExpression` can be either explicit or refer to the canonical trait. |
6 | #[derive (Debug, Clone)] |
7 | pub enum DefaultExpression { |
8 | Explicit(BlockContents), |
9 | Trait, |
10 | } |
11 | |
12 | impl 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 | |
39 | impl 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` |
60 | struct DefaultExpressionWithCrateRoot<'a> { |
61 | crate_root: &'a syn::Path, |
62 | expr: &'a DefaultExpression, |
63 | } |
64 | |
65 | impl<'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 | |