1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{Expr, PathSegment, parse_macro_input, punctuated::Punctuated, token::Colon};
4
5pub fn example_impl(input: TokenStream) -> TokenStream {
6 let derive_input = parse_macro_input!(input as Expr);
7
8 match derive_input {
9 Expr::Struct(e) => {
10 let ident = e.path;
12 let fields = e.fields.into_iter().map(|f| {
13 let member = f.member;
14 if f.colon_token.is_some() {
15 let expr = f.expr;
16 quote! { #member: #expr }
17 } else {
18 quote! { #member: Example::example() }
19 }
20 });
21 return quote! {
22 impl Example for #ident {
23 fn example() -> Self {
24 #ident { #(#fields),* }
25 }
26 }
27 }
28 .into();
29 }
30 Expr::Call(e) => {
31 if let Expr::Path(p) = *e.func {
32 let underscore: Expr = syn::parse_str("_").unwrap();
34 let segments = p.path.segments;
35
36 let len = segments.len();
38 let ty: Punctuated<PathSegment, Colon> =
39 segments.clone().into_iter().take(len - 1).collect();
40 let args = e
41 .args
42 .into_iter()
43 .map(|a| {
44 if a == underscore {
45 quote! { Example::example() }
46 } else {
47 quote! { #a }
48 }
49 })
50 .collect::<Vec<_>>();
51 return quote! {
52 impl Example for #ty {
53 fn example() -> Self {
54 #segments ( #(#args),* )
55 }
56 }
57 }
58 .into();
59 }
60 }
61 Expr::Path(e) => {
62 let segments = e.path.segments;
65 let len = segments.len();
67 let ty: Punctuated<PathSegment, Colon> =
68 segments.clone().into_iter().take(len - 1).collect();
69
70 return quote! {
71 impl Example for #ty {
72 fn example() -> Self {
73 #segments
74 }
75 }
76 }
77 .into();
78 }
79 _ => {}
80 }
81 panic!("invalid input, should be struct or enum literal");
82}