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("_")
34 .expect("Failed to parse underscore literal - this should never happen");
35 let segments = p.path.segments;
36
37 let len = segments.len();
39 let ty: Punctuated<PathSegment, Colon> =
40 segments.clone().into_iter().take(len - 1).collect();
41 let args = e
42 .args
43 .into_iter()
44 .map(|a| {
45 if a == underscore {
46 quote! { Example::example() }
47 } else {
48 quote! { #a }
49 }
50 })
51 .collect::<Vec<_>>();
52 return quote! {
53 impl Example for #ty {
54 fn example() -> Self {
55 #segments ( #(#args),* )
56 }
57 }
58 }
59 .into();
60 }
61 }
62 Expr::Path(e) => {
63 let segments = e.path.segments;
66 let len = segments.len();
68 let ty: Punctuated<PathSegment, Colon> =
69 segments.clone().into_iter().take(len - 1).collect();
70
71 return quote! {
72 impl Example for #ty {
73 fn example() -> Self {
74 #segments
75 }
76 }
77 }
78 .into();
79 }
80 _ => {}
81 }
82 panic!("invalid input, should be struct or enum literal");
83}